aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/.gitignore91
-rw-r--r--src/transport/Makefile.am1691
-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.c3666
-rw-r--r--src/transport/gnunet-communicator-udp.c3873
-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.c10333
-rw-r--r--src/transport/gnunet-service-transport.c2788
-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.in147
-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.c2535
-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.conf30
-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_plugin_cmd_simple_send.c229
-rw-r--r--src/transport/test_transport_plugin_cmd_simple_send_v2.c234
-rw-r--r--src/transport/test_transport_plugin_cmd_udp_backchannel.c242
-rw-r--r--src/transport/test_transport_port_forward.c85
-rw-r--r--src/transport/test_transport_simple_send.c86
-rwxr-xr-xsrc/transport/test_transport_simple_send.sh2
-rw-r--r--src/transport/test_transport_simple_send_v2.c83
-rwxr-xr-xsrc/transport/test_transport_simple_send_v2.sh2
-rw-r--r--src/transport/test_transport_start_with_config.c85
-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
-rw-r--r--src/transport/transport-testing-cmds.h345
-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.c1158
-rw-r--r--src/transport/transport_api2_core.c801
-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_connecting_peers.c281
-rw-r--r--src/transport/transport_api_cmd_connecting_peers_v2.c242
-rw-r--r--src/transport/transport_api_cmd_connecting_peers_v3.c508
-rw-r--r--src/transport/transport_api_cmd_send_simple.c172
-rw-r--r--src/transport/transport_api_cmd_send_simple_v2.c156
-rw-r--r--src/transport/transport_api_cmd_start_peer.c611
-rw-r--r--src/transport/transport_api_cmd_start_peer_v2.c607
-rw-r--r--src/transport/transport_api_cmd_start_peer_v3.c619
-rw-r--r--src/transport/transport_api_cmd_stop_peer.c163
-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
287 files changed, 0 insertions, 99216 deletions
diff --git a/src/transport/.gitignore b/src/transport/.gitignore
deleted file mode 100644
index d88d40ef7..000000000
--- a/src/transport/.gitignore
+++ /dev/null
@@ -1,91 +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
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
deleted file mode 100644
index 32075ee16..000000000
--- a/src/transport/Makefile.am
+++ /dev/null
@@ -1,1691 +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
19if HAVE_LIBGNURL
20 HTTP_CLIENT_PLUGIN_TEST = test_plugin_http_client
21 HTTPS_CLIENT_PLUGIN_TEST = test_plugin_https_client
22 HTTP_CLIENT_PLUGIN_LA = libgnunet_plugin_transport_http_client.la
23 HTTPS_CLIENT_PLUGIN_LA = libgnunet_plugin_transport_https_client.la
24LIB_GNURL=@LIBGNURL@
25CPP_GNURL=@LIBGNURL_CPPFLAGS@
26else
27if HAVE_LIBCURL
28 HTTP_CLIENT_PLUGIN_TEST = test_plugin_http_client
29 HTTPS_CLIENT_PLUGIN_TEST = test_plugin_https_client
30 HTTP_CLIENT_PLUGIN_LA = libgnunet_plugin_transport_http_client.la
31 HTTPS_CLIENT_PLUGIN_LA = libgnunet_plugin_transport_https_client.la
32LIB_GNURL=@LIBCURL@
33CPP_GNURL=@LIBCURL_CPPFLAGS@
34endif
35endif
36
37if HAVE_LIBGNURL
38 HTTP_API_TEST = test_transport_api_http
39 HTTP_REVERSE_API_TEST = test_transport_api_http_reverse
40 HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http
41 HTTP_REL_TEST = test_transport_api_reliability_http \
42 test_transport_api_reliability_http_xhr
43 HTTP_QUOTA_TEST = test_quota_compliance_http \
44 test_quota_compliance_http_asymmetric
45 HTTP_SWITCH = test_transport_address_switch_http
46 HTTPS_API_TEST = test_transport_api_https
47 HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https
48if HAVE_EXPERIMENTAL
49 HTTPS_REL_TEST = test_transport_api_reliability_https \
50 test_transport_api_reliability_https_xhr
51endif
52 HTTPS_QUOTA_TEST = test_quota_compliance_https \
53 test_quota_compliance_https_asymmetric
54 HTTPS_SWITCH = test_transport_address_switch_https
55else
56if HAVE_LIBCURL
57 HTTP_API_TEST = test_transport_api_http
58 HTTP_REVERSE_API_TEST = test_transport_api_http_reverse
59 HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http
60 HTTP_REL_TEST = test_transport_api_reliability_http \
61 test_transport_api_reliability_http_xhr
62 HTTP_QUOTA_TEST = test_quota_compliance_http \
63 test_quota_compliance_http_asymmetric
64 HTTP_SWITCH = test_transport_address_switch_http
65 HTTPS_API_TEST = test_transport_api_https
66 HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https
67if HAVE_EXPERIMENTAL
68 HTTPS_REL_TEST = test_transport_api_reliability_https \
69 test_transport_api_reliability_https_xhr
70endif
71 HTTPS_QUOTA_TEST = test_quota_compliance_https \
72 test_quota_compliance_https_asymmetric
73 HTTPS_SWITCH = test_transport_address_switch_https
74endif
75endif
76
77if USE_COVERAGE
78 AM_CFLAGS = --coverage -O0
79endif
80
81if HAVE_EXPERIMENTAL
82if LINUX
83 WLAN_BIN = gnunet-helper-transport-wlan
84 WLAN_BIN_DUMMY = gnunet-helper-transport-wlan-dummy
85 WLAN_BIN_SENDER = gnunet-transport-wlan-sender
86 WLAN_BIN_RECEIVER = gnunet-transport-wlan-receiver
87 WLAN_PLUGIN_LA = libgnunet_plugin_transport_wlan.la
88 WLAN_PLUGIN_TEST = test_plugin_wlan
89 WLAN_API_TEST = test_transport_api_wlan
90 WLAN_TIMEOUT_TEST = test_transport_api_timeout_wlan
91 WLAN_REL_TEST = test_transport_api_reliability_wlan
92 WLAN_QUOTA_TEST = test_quota_compliance_wlan \
93 test_quota_compliance_wlan_asymmetric
94endif
95
96if LINUX
97if HAVE_LIBBLUETOOTH
98 BT_BIN = gnunet-helper-transport-bluetooth
99 BT_PLUGIN_LA = libgnunet_plugin_transport_bluetooth.la
100 BT_PLUGIN_TEST = test_plugin_bluetooth
101 BT_API_TEST = test_transport_api_bluetooth
102 BT_TIMEOUT_TEST = test_transport_api_timeout_bluetooth
103 BT_REL_TEST = test_transport_api_reliability_bluetooth
104 BT_QUOTA_TEST = test_quota_compliance_bluetooth \
105 test_quota_compliance_bluetooth_asymmetric
106endif
107endif
108
109# end of HAVE_EXPERIMENTAL
110endif
111
112
113UNIX_PLUGIN_LA = libgnunet_plugin_transport_unix.la
114UNIX_PLUGIN_TEST = test_transport_api_unix
115UNIX_TEST = test_plugin_unix
116UNIX_PLUGIN_TIMEOUT_TEST = test_transport_api_timeout_unix
117UNIX_REL_TEST = test_transport_api_reliability_unix
118UNIX_QUOTA_TEST = test_quota_compliance_unix \
119 test_quota_compliance_unix_asymmetric
120if LINUX
121 UNIX_API_ABSTRACT_TEST = test_transport_api_unix_abstract
122endif
123
124
125noinst_PROGRAMS = \
126 gnunet-transport-profiler \
127 gnunet-communicator-udp \
128 $(WLAN_BIN_SENDER) \
129 $(WLAN_BIN_RECEIVER)
130
131if HAVE_TESTING
132TESTING_LIBS = \
133 libgnunettransporttesting.la \
134 libgnunettransporttesting2.la
135endif
136
137lib_LTLIBRARIES = \
138 libgnunettransport.la \
139 libgnunettransportapplication.la \
140 libgnunettransportcore.la \
141 libgnunettransportcommunicator.la \
142 libgnunettransportmonitor.la \
143 $(TESTING_LIBS)
144
145libgnunettransporttesting_la_SOURCES = \
146 transport-testing.c transport-testing.h \
147 transport-testing-filenames.c \
148 transport-testing-loggers.c \
149 transport-testing-main.c \
150 transport-testing-send.c
151libgnunettransporttesting_la_LIBADD = \
152 libgnunettransport.la \
153 $(top_builddir)/src/hello/libgnunethello.la \
154 $(top_builddir)/src/ats/libgnunetats.la \
155 $(top_builddir)/src/util/libgnunetutil.la \
156 $(top_builddir)/src/testing/libgnunettesting.la \
157 $(top_builddir)/src/arm/libgnunetarm.la \
158 $(GN_LIBINTL)
159libgnunettransporttesting_la_LDFLAGS = \
160 $(GN_LIB_LDFLAGS)
161
162libgnunettransporttesting2_la_SOURCES = \
163 transport_api_cmd_connecting_peers.c \
164 transport_api_cmd_connecting_peers_v2.c \
165 transport_api_cmd_connecting_peers_v3.c \
166 transport_api_cmd_start_peer.c \
167 transport_api_cmd_start_peer_v2.c \
168 transport_api_cmd_start_peer_v3.c \
169 transport_api_cmd_stop_peer.c \
170 transport_api_cmd_send_simple.c \
171 transport_api_cmd_send_simple_v2.c \
172 transport-testing2.c transport-testing2.h \
173 transport-testing-cmds.h \
174 transport-testing-filenames2.c \
175 transport-testing-loggers2.c \
176 transport-testing-main2.c \
177 transport-testing-send2.c \
178 transport-testing-communicator.c transport-testing-communicator.h
179libgnunettransporttesting2_la_LIBADD = \
180 libgnunettransportapplication.la \
181 libgnunettransportcore.la \
182 $(top_builddir)/src/arm/libgnunetarm.la \
183 $(top_builddir)/src/testing/libgnunettesting.la \
184 $(top_builddir)/src/ats/libgnunetats.la \
185 $(top_builddir)/src/hello/libgnunethello.la \
186 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
187 $(top_builddir)/src/util/libgnunetutil.la
188libgnunettransporttesting2_la_LDFLAGS = \
189 $(GN_LIBINTL) \
190 $(GN_LIB_LDFLAGS) \
191 -version-info 0:0:0
192
193libgnunettransport_la_SOURCES = \
194 transport.h \
195 transport_api_address_to_string.c \
196 transport_api_blacklist.c \
197 transport_api_core.c \
198 transport_api_hello_get.c \
199 transport_api_manipulation.c \
200 transport_api_monitor_peers.c \
201 transport_api_monitor_plugins.c \
202 transport_api_offer_hello.c
203
204libgnunettransport_la_LIBADD = \
205 $(top_builddir)/src/hello/libgnunethello.la \
206 $(top_builddir)/src/ats/libgnunetats.la \
207 $(top_builddir)/src/util/libgnunetutil.la \
208 $(GN_LIBINTL)
209libgnunettransport_la_LDFLAGS = \
210 $(GN_LIB_LDFLAGS) \
211 -version-info 4:0:2
212
213libgnunettransportapplication_la_SOURCES = \
214 transport_api2_application.c
215libgnunettransportapplication_la_LIBADD = \
216 $(top_builddir)/src/util/libgnunetutil.la \
217 $(LTLIBINTL)
218libgnunettransportapplication_la_LDFLAGS = \
219 $(GN_LIB_LDFLAGS) \
220 -version-info 0:0:0
221
222
223libgnunettransportcore_la_SOURCES = \
224 transport_api2_core.c
225libgnunettransportcore_la_LIBADD = \
226 $(top_builddir)/src/util/libgnunetutil.la \
227 $(GN_LIBINTL)
228libgnunettransportcore_la_LDFLAGS = \
229 $(GN_LIB_LDFLAGS) \
230 -version-info 0:0:0
231
232libgnunettransportcommunicator_la_SOURCES = \
233 transport_api2_communication.c
234libgnunettransportcommunicator_la_LIBADD = \
235 $(top_builddir)/src/util/libgnunetutil.la \
236 $(GN_LIBINTL)
237libgnunettransportcommunicator_la_LDFLAGS = \
238 $(GN_LIB_LDFLAGS) \
239 -version-info 0:0:0
240
241
242libgnunettransportmonitor_la_SOURCES = \
243 transport_api2_monitor.c
244libgnunettransportmonitor_la_LIBADD = \
245 $(top_builddir)/src/util/libgnunetutil.la \
246 $(GN_LIBINTL)
247libgnunettransportmonitor_la_LDFLAGS = \
248 $(GN_LIB_LDFLAGS) \
249 -version-info 0:0:0
250
251
252libexec_PROGRAMS = \
253 $(WLAN_BIN) \
254 $(WLAN_BIN_DUMMY) \
255 $(BT_BIN) \
256 gnunet-service-transport \
257 gnunet-service-tng \
258 gnunet-communicator-unix \
259 gnunet-communicator-udp \
260 gnunet-communicator-tcp
261
262
263
264bin_PROGRAMS = \
265 gnunet-transport
266
267bin_SCRIPTS = \
268 gnunet-transport-certificate-creation
269
270# See: https://www.gnu.org/software/automake/manual/html_node/Scripts.html#Scripts
271do_subst = sed -e 's,[@]pkgdatadir[@],$(pkgdatadir),g'
272
273
274gnunet-transport-certificate-creation: gnunet-transport-certificate-creation.in Makefile
275 $(do_subst) < $(srcdir)/gnunet-transport-certificate-creation.in > gnunet-transport-certificate-creation
276 chmod +x gnunet-transport-certificate-creation
277
278
279
280gnunet_communicator_unix_SOURCES = \
281 gnunet-communicator-unix.c
282gnunet_communicator_unix_LDADD = \
283 libgnunettransportcommunicator.la \
284 $(top_builddir)/src/statistics/libgnunetstatistics.la \
285 $(top_builddir)/src/util/libgnunetutil.la
286
287gnunet_communicator_tcp_SOURCES = \
288 gnunet-communicator-tcp.c
289gnunet_communicator_tcp_LDADD = \
290 libgnunettransportcommunicator.la \
291 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
292 $(top_builddir)/src/nat/libgnunetnatnew.la \
293 $(top_builddir)/src/nt/libgnunetnt.la \
294 $(top_builddir)/src/statistics/libgnunetstatistics.la \
295 $(top_builddir)/src/util/libgnunetutil.la \
296 $(LIBGCRYPT_LIBS)
297
298gnunet_communicator_udp_SOURCES = \
299 gnunet-communicator-udp.c
300gnunet_communicator_udp_LDADD = \
301 libgnunettransportapplication.la \
302 libgnunettransportcommunicator.la \
303 $(top_builddir)/src/nat/libgnunetnatnew.la \
304 $(top_builddir)/src/nt/libgnunetnt.la \
305 $(top_builddir)/src/statistics/libgnunetstatistics.la \
306 $(top_builddir)/src/util/libgnunetutil.la \
307 $(LIBGCRYPT_LIBS)
308
309
310gnunet_helper_transport_wlan_SOURCES = \
311 gnunet-helper-transport-wlan.c
312
313gnunet_helper_transport_wlan_dummy_SOURCES = \
314 gnunet-helper-transport-wlan-dummy.c
315gnunet_helper_transport_wlan_dummy_LDADD = \
316 $(top_builddir)/src/util/libgnunetutil.la
317
318gnunet_transport_wlan_sender_SOURCES = \
319 gnunet-transport-wlan-sender.c
320gnunet_transport_wlan_sender_LDADD = \
321 $(top_builddir)/src/util/libgnunetutil.la
322
323gnunet_transport_wlan_receiver_SOURCES = \
324 gnunet-transport-wlan-receiver.c
325gnunet_transport_wlan_receiver_LDADD = \
326 $(top_builddir)/src/util/libgnunetutil.la
327
328gnunet_helper_transport_bluetooth_SOURCES = \
329 gnunet-helper-transport-bluetooth.c
330
331gnunet_helper_transport_bluetooth_LDFLAGS = -lbluetooth
332
333
334gnunet_transport_profiler_SOURCES = \
335 gnunet-transport-profiler.c
336gnunet_transport_profiler_LDADD = \
337 libgnunettransport.la \
338 $(top_builddir)/src/hello/libgnunethello.la \
339 $(top_builddir)/src/ats/libgnunetats.la \
340 $(top_builddir)/src/util/libgnunetutil.la \
341 $(GN_LIBINTL)
342
343gnunet_transport_SOURCES = \
344 gnunet-transport.c
345gnunet_transport_LDADD = \
346 libgnunettransport.la \
347 $(top_builddir)/src/hello/libgnunethello.la \
348 $(top_builddir)/src/util/libgnunetutil.la \
349 $(GN_LIBINTL)
350
351gnunet_service_transport_SOURCES = \
352 gnunet-service-transport.c gnunet-service-transport.h \
353 gnunet-service-transport_ats.h gnunet-service-transport_ats.c \
354 gnunet-service-transport_hello.h gnunet-service-transport_hello.c \
355 gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \
356 gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \
357 gnunet-service-transport_validation.h gnunet-service-transport_validation.c \
358 gnunet-service-transport_manipulation.h gnunet-service-transport_manipulation.c
359# Note that while gnunet-service-transport does not use libgnunetnat
360# directly, we must link against it as GNUNET_NAT_mini_map_stop will
361# leave a 'dangling' task to process_unmap_output which will cause
362# a crash on unloading of a plugin unless the service links against
363# that library as well.
364gnunet_service_transport_LDADD = \
365 libgnunettransport.la \
366 $(top_builddir)/src/ats/libgnunetats.la \
367 $(top_builddir)/src/hello/libgnunethello.la \
368 $(top_builddir)/src/nt/libgnunetnt.la \
369 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
370 $(top_builddir)/src/statistics/libgnunetstatistics.la \
371 $(top_builddir)/src/util/libgnunetutil.la \
372 $(GN_GLPK) \
373 $(GN_LIBINTL)
374gnunet_service_transport_CFLAGS = \
375 $(AM_CFLAGS)
376# -DANALYZE
377
378
379gnunet_service_tng_SOURCES = \
380 gnunet-service-tng.c
381gnunet_service_tng_LDADD = \
382 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
383 $(top_builddir)/src/hello/libgnunethello.la \
384 $(top_builddir)/src/statistics/libgnunetstatistics.la \
385 $(top_builddir)/src/util/libgnunetutil.la \
386 $(LIBGCRYPT_LIBS) \
387 $(GN_LIBINTL)
388
389plugin_LTLIBRARIES = \
390 libgnunet_plugin_transport_tcp.la \
391 $(UNIX_PLUGIN_LA) \
392 $(HTTP_CLIENT_PLUGIN_LA) \
393 $(HTTPS_CLIENT_PLUGIN_LA) \
394 $(HTTP_SERVER_PLUGIN_LA) \
395 $(HTTPS_SERVER_PLUGIN_LA) \
396 $(WLAN_PLUGIN_LA) \
397 $(BT_PLUGIN_LA) \
398 libgnunet_test_transport_plugin_cmd_simple_send.la \
399 libgnunet_test_transport_plugin_cmd_simple_send_v2.la \
400 libgnunet_test_transport_plugin_cmd_udp_backchannel.la
401
402libgnunet_test_transport_plugin_cmd_udp_backchannel_la_SOURCES = \
403 test_transport_plugin_cmd_udp_backchannel.c
404libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LIBADD = \
405 libgnunettransporttesting2.la \
406 libgnunettransportapplication.la \
407 libgnunettransportcore.la \
408 $(top_builddir)/src/testing/libgnunettesting.la \
409 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
410 $(top_builddir)/src/statistics/libgnunetstatistics.la \
411 $(top_builddir)/src/hello/libgnunethello.la \
412 $(top_builddir)/src/ats/libgnunetats.la \
413 $(top_builddir)/src/arm/libgnunetarm.la \
414 $(top_builddir)/src/util/libgnunetutil.la \
415 $(LTLIBINTL)
416libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LDFLAGS = \
417 $(GN_PLUGIN_LDFLAGS)
418
419libgnunet_test_transport_plugin_cmd_simple_send_la_SOURCES = \
420 test_transport_plugin_cmd_simple_send.c
421libgnunet_test_transport_plugin_cmd_simple_send_la_LIBADD = \
422 libgnunettransporttesting2.la \
423 libgnunettransportapplication.la \
424 libgnunettransportcore.la \
425 $(top_builddir)/src/testing/libgnunettesting.la \
426 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
427 $(top_builddir)/src/statistics/libgnunetstatistics.la \
428 $(top_builddir)/src/hello/libgnunethello.la \
429 $(top_builddir)/src/ats/libgnunetats.la \
430 $(top_builddir)/src/arm/libgnunetarm.la \
431 $(top_builddir)/src/util/libgnunetutil.la \
432 $(LTLIBINTL)
433libgnunet_test_transport_plugin_cmd_simple_send_la_LDFLAGS = \
434 $(GN_PLUGIN_LDFLAGS)
435
436libgnunet_test_transport_plugin_cmd_simple_send_v2_la_SOURCES = \
437 test_transport_plugin_cmd_simple_send_v2.c
438libgnunet_test_transport_plugin_cmd_simple_send_v2_la_LIBADD = \
439 libgnunettransporttesting2.la \
440 libgnunettransportapplication.la \
441 libgnunettransportcore.la \
442 $(top_builddir)/src/testing/libgnunettesting.la \
443 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
444 $(top_builddir)/src/statistics/libgnunetstatistics.la \
445 $(top_builddir)/src/hello/libgnunethello.la \
446 $(top_builddir)/src/ats/libgnunetats.la \
447 $(top_builddir)/src/arm/libgnunetarm.la \
448 $(top_builddir)/src/util/libgnunetutil.la \
449 $(LTLIBINTL)
450libgnunet_test_transport_plugin_cmd_simple_send_v2_la_LDFLAGS = \
451 $(GN_PLUGIN_LDFLAGS)
452
453if HAVE_EXPERIMENTAL
454plugin_LTLIBRARIES += \
455 libgnunet_plugin_transport_udp.la
456endif
457
458# Note: real plugins of course need to be added
459# to the plugin_LTLIBRARIES above
460noinst_LTLIBRARIES = \
461 libgnunet_plugin_transport_template.la
462
463libgnunet_plugin_transport_tcp_la_SOURCES = \
464 plugin_transport_tcp.c
465libgnunet_plugin_transport_tcp_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/nat/libgnunetnatnew.la \
470 $(top_builddir)/src/util/libgnunetutil.la \
471 $(LTLIBINTL)
472libgnunet_plugin_transport_tcp_la_LDFLAGS = \
473 $(GN_PLUGIN_LDFLAGS)
474
475libgnunet_plugin_transport_template_la_SOURCES = \
476 plugin_transport_template.c
477libgnunet_plugin_transport_template_la_LIBADD = \
478 $(top_builddir)/src/util/libgnunetutil.la \
479 $(LTLIBINTL)
480libgnunet_plugin_transport_template_la_LDFLAGS = \
481 $(GN_PLUGIN_LDFLAGS)
482
483libgnunet_plugin_transport_wlan_la_SOURCES = \
484 plugin_transport_wlan.c plugin_transport_wlan.h
485libgnunet_plugin_transport_wlan_la_LIBADD = \
486 $(top_builddir)/src/hello/libgnunethello.la \
487 $(top_builddir)/src/statistics/libgnunetstatistics.la \
488 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
489 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
490 $(top_builddir)/src/util/libgnunetutil.la
491libgnunet_plugin_transport_wlan_la_LDFLAGS = \
492 $(GN_PLUGIN_LDFLAGS)
493libgnunet_plugin_transport_wlan_la_CFLAGS = \
494 $(AM_CFLAGS) -DBUILD_WLAN
495
496libgnunet_plugin_transport_bluetooth_la_SOURCES = \
497 plugin_transport_wlan.c plugin_transport_wlan.h
498libgnunet_plugin_transport_bluetooth_la_LIBADD = \
499 $(top_builddir)/src/hello/libgnunethello.la \
500 $(top_builddir)/src/statistics/libgnunetstatistics.la \
501 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
502 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
503 $(top_builddir)/src/util/libgnunetutil.la
504libgnunet_plugin_transport_bluetooth_la_LDFLAGS = \
505 $(GN_PLUGIN_LDFLAGS)
506libgnunet_plugin_transport_bluetooth_la_CFLAGS = \
507 $(AM_CFLAGS) -DBUILD_BLUETOOTH
508
509if HAVE_EXPERIMENTAL
510libgnunet_plugin_transport_udp_la_SOURCES = \
511 plugin_transport_udp.c plugin_transport_udp.h \
512 plugin_transport_udp_broadcasting.c
513libgnunet_plugin_transport_udp_la_LIBADD = \
514 $(top_builddir)/src/hello/libgnunethello.la \
515 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
516 $(top_builddir)/src/statistics/libgnunetstatistics.la \
517 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
518 $(top_builddir)/src/nat/libgnunetnatnew.la \
519 $(top_builddir)/src/util/libgnunetutil.la \
520 $(LTLIBINTL)
521libgnunet_plugin_transport_udp_la_LDFLAGS = \
522 $(GN_PLUGIN_LDFLAGS)
523endif
524
525libgnunet_plugin_transport_unix_la_SOURCES = \
526 plugin_transport_unix.c
527libgnunet_plugin_transport_unix_la_LIBADD = \
528 $(top_builddir)/src/hello/libgnunethello.la \
529 $(top_builddir)/src/statistics/libgnunetstatistics.la \
530 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
531 $(top_builddir)/src/util/libgnunetutil.la \
532 $(LTLIBINTL)
533libgnunet_plugin_transport_unix_la_LDFLAGS = \
534 $(GN_PLUGIN_LDFLAGS)
535
536
537libgnunet_plugin_transport_http_client_la_SOURCES = \
538 plugin_transport_http_client.c plugin_transport_http_common.c plugin_transport_http_common.h
539libgnunet_plugin_transport_http_client_la_LIBADD = \
540 $(top_builddir)/src/hello/libgnunethello.la \
541 $(top_builddir)/src/statistics/libgnunetstatistics.la \
542 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
543 $(LIB_GNURL) \
544 $(top_builddir)/src/util/libgnunetutil.la
545libgnunet_plugin_transport_http_client_la_LDFLAGS = \
546 $(GN_LIBINTL) \
547 $(GN_PLUGIN_LDFLAGS)
548libgnunet_plugin_transport_http_client_la_CFLAGS = \
549 $(CPP_GNURL) $(AM_CFLAGS)
550
551
552libgnunet_plugin_transport_http_server_la_SOURCES = \
553 plugin_transport_http_server.c plugin_transport_http_common.c
554libgnunet_plugin_transport_http_server_la_LIBADD = \
555 $(MHD_LIBS) \
556 $(top_builddir)/src/hello/libgnunethello.la \
557 $(top_builddir)/src/statistics/libgnunetstatistics.la \
558 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
559 $(top_builddir)/src/nat/libgnunetnatnew.la \
560 $(top_builddir)/src/util/libgnunetutil.la
561libgnunet_plugin_transport_http_server_la_LDFLAGS = \
562 $(GN_LIBINTL) \
563 $(GN_PLUGIN_LDFLAGS)
564libgnunet_plugin_transport_http_server_la_CFLAGS = \
565 $(MHD_CFLAGS) $(AM_CFLAGS)
566
567libgnunet_plugin_transport_https_client_la_SOURCES = \
568 plugin_transport_http_client.c plugin_transport_http_common.c
569libgnunet_plugin_transport_https_client_la_LIBADD = \
570 $(top_builddir)/src/hello/libgnunethello.la \
571 $(top_builddir)/src/statistics/libgnunetstatistics.la \
572 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
573 $(LIB_GNURL) \
574 $(top_builddir)/src/util/libgnunetutil.la
575libgnunet_plugin_transport_https_client_la_LDFLAGS = \
576 $(GN_LIBINTL) \
577 $(GN_PLUGIN_LDFLAGS)
578libgnunet_plugin_transport_https_client_la_CFLAGS = \
579 $(CPP_GNURL) $(AM_CFLAGS) -DBUILD_HTTPS
580
581
582libgnunet_plugin_transport_https_server_la_SOURCES = \
583 plugin_transport_http_server.c plugin_transport_http_common.c
584libgnunet_plugin_transport_https_server_la_LIBADD = \
585 $(MHD_LIBS) \
586 $(top_builddir)/src/hello/libgnunethello.la \
587 $(top_builddir)/src/statistics/libgnunetstatistics.la \
588 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
589 $(top_builddir)/src/nat/libgnunetnatnew.la \
590 $(top_builddir)/src/util/libgnunetutil.la
591libgnunet_plugin_transport_https_server_la_LDFLAGS = \
592 $(GN_LIBINTL) \
593 $(GN_PLUGIN_LDFLAGS)
594libgnunet_plugin_transport_https_server_la_CFLAGS = \
595 $(MHD_CFLAGS) $(AM_CFLAGS) -DBUILD_HTTPS
596
597if HAVE_TESTING
598check_PROGRAMS = \
599 test_transport_simple_send \
600 test_transport_simple_send_v2 \
601 test_transport_start_with_config \
602 test_transport_address_switch_tcp \
603 test_transport_testing_startstop \
604 test_transport_testing_restart \
605 test_plugin_tcp \
606 $(UNIX_TEST) \
607 $(WLAN_PLUGIN_TEST) \
608 $(BT_PLUGIN_TEST) \
609 test_http_common \
610 $(HTTP_CLIENT_PLUGIN_TEST) \
611 $(HTTPS_CLIENT_PLUGIN_TEST) \
612 $(HTTP_SERVER_PLUGIN_TEST) \
613 $(HTTPS_SERVER_PLUGIN_TEST) \
614 test_transport_api_blacklisting_tcp \
615 test_transport_api_disconnect_tcp \
616 test_transport_api_tcp \
617 test_transport_api2_tcp \
618 test_transport_api_restart_1peer \
619 test_transport_api_restart_2peers \
620 test_transport_api_timeout_tcp \
621 test_transport_api_limited_sockets_tcp \
622 test_transport_api_tcp_nat \
623 $(UNIX_PLUGIN_TEST) \
624 $(UNIX_PLUGIN_TIMEOUT_TEST) \
625 $(UNIX_API_ABSTRACT_TEST) \
626 $(HTTP_API_TEST) \
627 $(HTTP_REVERSE_API_TEST) \
628 $(HTTP_API_TIMEOUT_TEST) \
629 $(HTTP_SWITCH) \
630 $(HTTPS_API_TEST) \
631 $(HTTPS_API_TIMEOUT_TEST) \
632 $(HTTPS_SWITCH) \
633 $(WLAN_API_TEST) \
634 $(WLAN_TIMEOUT_TEST) \
635 $(BT_API_TEST) \
636 $(BT_TIMEOUT_TEST) \
637 test_transport_api_multi \
638 test_transport_api_monitor_peers \
639 test_transport_blacklisting_no_bl \
640 test_transport_blacklisting_outbound_bl_full \
641 test_transport_blacklisting_outbound_bl_plugin \
642 test_transport_blacklisting_inbound_bl_plugin \
643 test_transport_blacklisting_inbound_bl_full \
644 test_transport_blacklisting_multiple_plugins \
645 test_transport_api_manipulation_send_tcp \
646 test_transport_api_manipulation_recv_tcp \
647 test_transport_api_manipulation_cfg \
648 test_transport_api_reliability_tcp \
649 test_transport_api_reliability_tcp_nat \
650 $(UNIX_REL_TEST) \
651 $(HTTP_REL_TEST) \
652 $(HTTPS_REL_TEST) \
653 $(WLAN_REL_TEST) \
654 $(WLAN_UREL_TEST) \
655 $(BT_REL_TEST) \
656 $(BT_UREL_TEST) \
657 test_quota_compliance_tcp \
658 test_quota_compliance_tcp_asymmetric \
659 $(UNIX_QUOTA_TEST) \
660 $(HTTP_QUOTA_TEST) \
661 $(HTTPS_QUOTA_TEST) \
662 $(WLAN_QUOTA_TEST) \
663 $(BT_QUOTA_TEST)
664if HAVE_GETOPT_BINARY
665check_PROGRAMS += \
666test_transport_api_slow_ats
667endif
668if HAVE_EXPERIMENTAL
669check_PROGRAMS += \
670 test_transport_address_switch_udp \
671 test_plugin_udp \
672 test_transport_api_udp \
673 test_transport_api_timeout_udp \
674 test_transport_api_udp_nat \
675 test_transport_api_reliability_udp \
676 test_quota_compliance_udp \
677 test_communicator_basic-unix \
678 test_communicator_basic-tcp \
679 test_communicator_basic-udp \
680 test_communicator_rekey-tcp \
681 test_communicator_rekey-udp \
682 test_communicator_backchannel-udp \
683 test_communicator_bidirect-tcp
684endif
685endif
686
687if ENABLE_TEST_RUN
688AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
689TESTS = \
690 test_transport_address_switch_tcp \
691 $(HTTP_SWITCH) \
692 $(HTTPS_SWITCH) \
693 test_transport_testing_startstop \
694 test_transport_testing_restart \
695 test_plugin_tcp \
696 $(UNIX_TEST) \
697 $(WLAN_PLUGIN_TEST) \
698 $(BT_PLUGIN_TEST) \
699 test_transport_api_blacklisting_tcp \
700 test_transport_api_disconnect_tcp \
701 test_transport_api_tcp \
702 test_transport_api_restart_1peer \
703 test_transport_api_restart_2peers \
704 test_transport_api_limited_sockets_tcp \
705 test_transport_api_tcp_nat \
706 $(UNIX_PLUGIN_TEST) \
707 $(UNIX_API_ABSTRACT_TEST) \
708 $(HTTP_API_TEST) \
709 $(HTTPS_API_TEST) \
710 $(WLAN_API_TEST) \
711 $(BT_API_TEST) \
712 test_transport_api_multi \
713 test_transport_api_monitor_peers \
714 test_transport_blacklisting_no_bl \
715 test_transport_blacklisting_outbound_bl_full \
716 test_transport_blacklisting_outbound_bl_plugin \
717 test_transport_blacklisting_inbound_bl_plugin \
718 test_transport_blacklisting_inbound_bl_full \
719 test_transport_blacklisting_multiple_plugins \
720 test_transport_api_manipulation_send_tcp \
721 test_transport_api_manipulation_recv_tcp \
722 test_transport_api_manipulation_cfg \
723 test_transport_api_reliability_tcp \
724 test_transport_api_reliability_tcp_nat \
725 $(UNIX_REL_TEST) \
726 $(HTTP_REL_TEST) \
727 $(HTTPS_REL_TEST) \
728 $(WLAN_REL_TEST) \
729 $(WLAN_UREL_TEST) \
730 $(BT_REL_TEST) \
731 $(BT_UREL_TEST) \
732 test_quota_compliance_tcp \
733 test_quota_compliance_tcp_asymmetric \
734 $(UNIX_QUOTA_TEST) \
735 $(HTTP_QUOTA_TEST) \
736 $(HTTPS_QUOTA_TEST) \
737 test_transport_api_timeout_tcp \
738 $(UNIX_PLUGIN_TIMEOUT_TEST) \
739 $(HTTP_API_TIMEOUT_TEST) \
740 $(HTTPS_API_TIMEOUT_TEST) \
741 $(WLAN_TIMEOUT_TEST) \
742 $(BT_TIMEOUT_TEST) \
743 $(check_SCRIPTS)
744if HAVE_GETOPT_BINARY
745TESTS += \
746test_transport_api_slow_ats
747endif
748if HAVE_EXPERIMENTAL
749TESTS += \
750 test_transport_simple_send \
751 test_transport_simple_send_v2 \
752 test_transport_start_with_config \
753 test_transport_address_switch_udp \
754 test_plugin_udp \
755 test_transport_api_udp \
756 test_transport_api_timeout_udp \
757 test_transport_api_udp_nat \
758 test_transport_api_reliability_udp \
759 test_quota_compliance_udp \
760 test_communicator_basic-unix \
761 test_communicator_basic-tcp \
762 test_communicator_basic-udp \
763 test_communicator_rekey-tcp \
764 test_communicator_rekey-udp \
765 test_communicator_backchannel-udp \
766 test_communicator_bidirect-tcp
767endif
768endif
769
770check_SCRIPTS= \
771 test_transport_simple_send.sh \
772 test_transport_simple_send_v2.sh \
773 test_transport_udp_backchannel.sh
774
775test_transport_start_with_config_SOURCES = \
776 test_transport_start_with_config.c
777test_transport_start_with_config_LDADD = \
778 $(top_builddir)/src/testing/libgnunettesting.la \
779 $(top_builddir)/src/util/libgnunetutil.la \
780 $(top_builddir)/src/testbed/libgnunettestbed.la \
781 $(top_builddir)/src/hello/libgnunethello.la \
782 libgnunettransportcore.la \
783 libgnunettransporttesting2.la
784
785test_transport_simple_send_SOURCES = \
786 test_transport_simple_send.c
787test_transport_simple_send_LDADD = \
788 $(top_builddir)/src/testing/libgnunettesting.la \
789 $(top_builddir)/src/util/libgnunetutil.la \
790 $(top_builddir)/src/testbed/libgnunettestbed.la \
791 $(top_builddir)/src/hello/libgnunethello.la \
792 libgnunettransportcore.la \
793 libgnunettransporttesting2.la
794
795test_transport_simple_send_v2_SOURCES = \
796 test_transport_simple_send_v2.c
797test_transport_simple_send_v2_LDADD = \
798 $(top_builddir)/src/testing/libgnunettesting.la \
799 $(top_builddir)/src/util/libgnunetutil.la \
800 $(top_builddir)/src/testbed/libgnunettestbed.la \
801 $(top_builddir)/src/hello/libgnunethello.la \
802 libgnunettransportcore.la \
803 libgnunettransporttesting2.la
804
805test_transport_testing_startstop_SOURCES = \
806 test_transport_testing_startstop.c
807test_transport_testing_startstop_LDADD = \
808 $(top_builddir)/src/util/libgnunetutil.la \
809 libgnunettransport.la \
810 $(top_builddir)/src/hello/libgnunethello.la \
811 libgnunettransporttesting.la
812
813test_transport_testing_restart_SOURCES = \
814 test_transport_testing_restart.c
815test_transport_testing_restart_LDADD = \
816 $(top_builddir)/src/util/libgnunetutil.la \
817 libgnunettransport.la \
818 $(top_builddir)/src/hello/libgnunethello.la \
819 libgnunettransporttesting.la
820
821test_transport_api_blacklisting_tcp_SOURCES = \
822 test_transport_api_blacklisting.c
823test_transport_api_blacklisting_tcp_LDADD = \
824 libgnunettransport.la \
825 $(top_builddir)/src/hello/libgnunethello.la \
826 $(top_builddir)/src/statistics/libgnunetstatistics.la \
827 $(top_builddir)/src/util/libgnunetutil.la \
828 libgnunettransporttesting.la
829
830test_transport_blacklisting_no_bl_SOURCES = \
831 test_transport_blacklisting.c
832test_transport_blacklisting_no_bl_LDADD = \
833 libgnunettransport.la \
834 $(top_builddir)/src/hello/libgnunethello.la \
835 $(top_builddir)/src/statistics/libgnunetstatistics.la \
836 $(top_builddir)/src/util/libgnunetutil.la \
837 libgnunettransporttesting.la
838
839test_transport_blacklisting_outbound_bl_full_SOURCES = \
840 test_transport_blacklisting.c
841test_transport_blacklisting_outbound_bl_full_LDADD = \
842 libgnunettransport.la \
843 $(top_builddir)/src/hello/libgnunethello.la \
844 $(top_builddir)/src/statistics/libgnunetstatistics.la \
845 $(top_builddir)/src/util/libgnunetutil.la \
846 libgnunettransporttesting.la
847
848test_transport_blacklisting_outbound_bl_plugin_SOURCES = \
849 test_transport_blacklisting.c
850test_transport_blacklisting_outbound_bl_plugin_LDADD = \
851 libgnunettransport.la \
852 $(top_builddir)/src/hello/libgnunethello.la \
853 $(top_builddir)/src/statistics/libgnunetstatistics.la \
854 $(top_builddir)/src/util/libgnunetutil.la \
855 libgnunettransporttesting.la
856
857test_transport_blacklisting_inbound_bl_full_SOURCES = \
858 test_transport_blacklisting.c
859test_transport_blacklisting_inbound_bl_full_LDADD = \
860 libgnunettransport.la \
861 $(top_builddir)/src/hello/libgnunethello.la \
862 $(top_builddir)/src/statistics/libgnunetstatistics.la \
863 $(top_builddir)/src/util/libgnunetutil.la \
864 libgnunettransporttesting.la
865
866test_transport_blacklisting_inbound_bl_plugin_SOURCES = \
867 test_transport_blacklisting.c
868test_transport_blacklisting_inbound_bl_plugin_LDADD = \
869 libgnunettransport.la \
870 $(top_builddir)/src/hello/libgnunethello.la \
871 $(top_builddir)/src/statistics/libgnunetstatistics.la \
872 $(top_builddir)/src/util/libgnunetutil.la \
873 libgnunettransporttesting.la
874
875test_transport_blacklisting_multiple_plugins_SOURCES = \
876 test_transport_blacklisting.c
877test_transport_blacklisting_multiple_plugins_LDADD = \
878 libgnunettransport.la \
879 $(top_builddir)/src/hello/libgnunethello.la \
880 $(top_builddir)/src/statistics/libgnunetstatistics.la \
881 $(top_builddir)/src/util/libgnunetutil.la \
882 libgnunettransporttesting.la
883
884
885test_transport_api_disconnect_tcp_SOURCES = \
886 test_transport_api_disconnect.c
887test_transport_api_disconnect_tcp_LDADD = \
888 libgnunettransport.la \
889 $(top_builddir)/src/hello/libgnunethello.la \
890 $(top_builddir)/src/statistics/libgnunetstatistics.la \
891 $(top_builddir)/src/util/libgnunetutil.la \
892 libgnunettransporttesting.la
893
894test_plugin_tcp_SOURCES = \
895 test_plugin_transport.c
896test_plugin_tcp_LDADD = \
897 libgnunettransport.la \
898 $(top_builddir)/src/statistics/libgnunetstatistics.la \
899 $(top_builddir)/src/hello/libgnunethello.la \
900 $(top_builddir)/src/util/libgnunetutil.la \
901 libgnunettransporttesting.la
902
903if HAVE_EXPERIMENTAL
904test_plugin_udp_SOURCES = \
905 test_plugin_transport.c
906test_plugin_udp_LDADD = \
907 libgnunettransport.la \
908 $(top_builddir)/src/statistics/libgnunetstatistics.la \
909 $(top_builddir)/src/hello/libgnunethello.la \
910 $(top_builddir)/src/util/libgnunetutil.la \
911 libgnunettransporttesting.la
912endif
913
914if HAVE_EXPERIMENTAL
915test_communicator_basic_unix_SOURCES = \
916 test_communicator_basic.c
917test_communicator_basic_unix_LDADD = \
918 libgnunettransporttesting2.la \
919 $(top_builddir)/src/testing/libgnunettesting.la \
920 $(top_builddir)/src/util/libgnunetutil.la \
921 $(top_builddir)/src/statistics/libgnunetstatistics.la
922
923test_communicator_basic_tcp_SOURCES = \
924 test_communicator_basic.c
925test_communicator_basic_tcp_LDADD = \
926 libgnunettransporttesting2.la \
927 $(top_builddir)/src/testing/libgnunettesting.la \
928 $(top_builddir)/src/util/libgnunetutil.la \
929 $(top_builddir)/src/statistics/libgnunetstatistics.la
930
931test_communicator_basic_udp_SOURCES = \
932 test_communicator_basic.c
933test_communicator_basic_udp_LDADD = \
934 libgnunettransporttesting2.la \
935 $(top_builddir)/src/testing/libgnunettesting.la \
936 $(top_builddir)/src/util/libgnunetutil.la \
937 $(top_builddir)/src/statistics/libgnunetstatistics.la
938
939test_communicator_rekey_tcp_SOURCES = \
940 test_communicator_basic.c
941test_communicator_rekey_tcp_LDADD = \
942 libgnunettransporttesting2.la \
943 $(top_builddir)/src/testing/libgnunettesting.la \
944 $(top_builddir)/src/util/libgnunetutil.la \
945 $(top_builddir)/src/statistics/libgnunetstatistics.la
946
947test_communicator_rekey_udp_SOURCES = \
948 test_communicator_basic.c
949test_communicator_rekey_udp_LDADD = \
950 libgnunettransporttesting2.la \
951 $(top_builddir)/src/testing/libgnunettesting.la \
952 $(top_builddir)/src/util/libgnunetutil.la \
953 $(top_builddir)/src/statistics/libgnunetstatistics.la
954
955test_communicator_backchannel_udp_SOURCES = \
956 test_communicator_basic.c
957test_communicator_backchannel_udp_LDADD = \
958 libgnunettransporttesting2.la \
959 $(top_builddir)/src/testing/libgnunettesting.la \
960 $(top_builddir)/src/util/libgnunetutil.la \
961 $(top_builddir)/src/statistics/libgnunetstatistics.la
962
963test_communicator_bidirect_tcp_SOURCES = \
964 test_communicator_basic.c
965test_communicator_bidirect_tcp_LDADD = \
966 libgnunettransporttesting2.la \
967 $(top_builddir)/src/testing/libgnunettesting.la \
968 $(top_builddir)/src/util/libgnunetutil.la \
969 $(top_builddir)/src/statistics/libgnunetstatistics.la
970endif
971
972test_plugin_unix_SOURCES = \
973 test_plugin_transport.c
974test_plugin_unix_LDADD = \
975 libgnunettransport.la \
976 $(top_builddir)/src/statistics/libgnunetstatistics.la \
977 $(top_builddir)/src/hello/libgnunethello.la \
978 $(top_builddir)/src/util/libgnunetutil.la \
979 libgnunettransporttesting.la
980
981test_plugin_wlan_SOURCES = \
982 test_plugin_transport.c
983test_plugin_wlan_LDADD = \
984 libgnunettransport.la \
985 $(top_builddir)/src/statistics/libgnunetstatistics.la \
986 $(top_builddir)/src/hello/libgnunethello.la \
987 $(top_builddir)/src/util/libgnunetutil.la \
988 libgnunettransporttesting.la
989
990test_plugin_bluetooth_SOURCES = \
991 test_plugin_transport.c
992test_plugin_bluetooth_LDADD = \
993 libgnunettransport.la \
994 $(top_builddir)/src/statistics/libgnunetstatistics.la \
995 $(top_builddir)/src/hello/libgnunethello.la \
996 $(top_builddir)/src/util/libgnunetutil.la \
997 libgnunettransporttesting.la
998
999test_http_common_SOURCES = \
1000 test_http_common.c plugin_transport_http_common.c
1001test_http_common_LDADD = \
1002 libgnunettransport.la \
1003 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1004 $(top_builddir)/src/hello/libgnunethello.la \
1005 $(top_builddir)/src/util/libgnunetutil.la \
1006 libgnunettransporttesting.la
1007
1008test_plugin_http_server_SOURCES = \
1009 test_plugin_transport.c
1010test_plugin_http_server_LDADD = \
1011 libgnunettransport.la \
1012 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1013 $(top_builddir)/src/hello/libgnunethello.la \
1014 $(top_builddir)/src/util/libgnunetutil.la \
1015 libgnunettransporttesting.la
1016
1017test_plugin_https_server_SOURCES = \
1018 test_plugin_transport.c
1019test_plugin_https_server_LDADD = \
1020 libgnunettransport.la \
1021 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1022 $(top_builddir)/src/hello/libgnunethello.la \
1023 $(top_builddir)/src/util/libgnunetutil.la \
1024 libgnunettransporttesting.la
1025
1026test_plugin_http_client_SOURCES = \
1027 test_plugin_transport.c
1028test_plugin_http_client_LDADD = \
1029 libgnunettransport.la \
1030 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1031 $(top_builddir)/src/hello/libgnunethello.la \
1032 $(top_builddir)/src/util/libgnunetutil.la \
1033 libgnunettransporttesting.la
1034
1035test_plugin_https_client_SOURCES = \
1036 test_plugin_transport.c
1037test_plugin_https_client_LDADD = \
1038 libgnunettransport.la \
1039 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1040 $(top_builddir)/src/hello/libgnunethello.la \
1041 $(top_builddir)/src/util/libgnunetutil.la \
1042 libgnunettransporttesting.la
1043
1044test_transport_api_tcp_SOURCES = \
1045 test_transport_api.c
1046test_transport_api_tcp_LDADD = \
1047 libgnunettransport.la \
1048 $(top_builddir)/src/hello/libgnunethello.la \
1049 $(top_builddir)/src/util/libgnunetutil.la \
1050 libgnunettransporttesting.la
1051
1052test_transport_api2_tcp_SOURCES = \
1053 test_transport_api2.c
1054test_transport_api2_tcp_LDADD = \
1055 $(top_builddir)/src/hello/libgnunethello.la \
1056 $(top_builddir)/src/util/libgnunetutil.la \
1057 libgnunettransporttesting2.la
1058
1059test_transport_api_restart_1peer_SOURCES = \
1060 test_transport_api_restart_reconnect.c
1061test_transport_api_restart_1peer_LDADD = \
1062 libgnunettransport.la \
1063 $(top_builddir)/src/hello/libgnunethello.la \
1064 $(top_builddir)/src/ats/libgnunetats.la \
1065 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1066 $(top_builddir)/src/util/libgnunetutil.la \
1067 libgnunettransporttesting.la
1068
1069test_transport_api_restart_2peers_SOURCES = \
1070 test_transport_api_restart_reconnect.c
1071test_transport_api_restart_2peers_LDADD = \
1072 libgnunettransport.la \
1073 $(top_builddir)/src/hello/libgnunethello.la \
1074 $(top_builddir)/src/ats/libgnunetats.la \
1075$(top_builddir)/src/statistics/libgnunetstatistics.la \
1076 $(top_builddir)/src/util/libgnunetutil.la \
1077 libgnunettransporttesting.la
1078
1079test_transport_api_limited_sockets_tcp_SOURCES = \
1080 test_transport_api_limited_sockets.c
1081test_transport_api_limited_sockets_tcp_LDADD = \
1082 libgnunettransport.la \
1083 $(top_builddir)/src/hello/libgnunethello.la \
1084 $(top_builddir)/src/util/libgnunetutil.la \
1085 libgnunettransporttesting.la
1086
1087test_transport_api_tcp_nat_SOURCES = \
1088 test_transport_api.c
1089test_transport_api_tcp_nat_LDADD = \
1090 libgnunettransport.la \
1091 $(top_builddir)/src/hello/libgnunethello.la \
1092 $(top_builddir)/src/util/libgnunetutil.la \
1093 libgnunettransporttesting.la
1094
1095test_transport_api_manipulation_send_tcp_SOURCES = \
1096 test_transport_api_manipulation_send_tcp.c
1097test_transport_api_manipulation_send_tcp_LDADD = \
1098 libgnunettransport.la \
1099 $(top_builddir)/src/hello/libgnunethello.la \
1100 $(top_builddir)/src/util/libgnunetutil.la \
1101 libgnunettransporttesting.la
1102
1103test_transport_api_manipulation_recv_tcp_SOURCES = \
1104 test_transport_api_manipulation_recv_tcp.c
1105test_transport_api_manipulation_recv_tcp_LDADD = \
1106 libgnunettransport.la \
1107 $(top_builddir)/src/hello/libgnunethello.la \
1108 $(top_builddir)/src/util/libgnunetutil.la \
1109 libgnunettransporttesting.la
1110
1111test_transport_api_manipulation_cfg_SOURCES = \
1112 test_transport_api_manipulation_cfg.c
1113test_transport_api_manipulation_cfg_LDADD = \
1114 libgnunettransport.la \
1115 $(top_builddir)/src/hello/libgnunethello.la \
1116 $(top_builddir)/src/util/libgnunetutil.la \
1117 libgnunettransporttesting.la
1118
1119test_transport_api_reliability_tcp_SOURCES = \
1120 test_transport_api_reliability.c
1121test_transport_api_reliability_tcp_LDADD = \
1122 libgnunettransport.la \
1123 $(top_builddir)/src/hello/libgnunethello.la \
1124 $(top_builddir)/src/util/libgnunetutil.la \
1125 libgnunettransporttesting.la
1126
1127test_transport_api_timeout_tcp_SOURCES = \
1128 test_transport_api_timeout.c
1129test_transport_api_timeout_tcp_LDADD = \
1130 libgnunettransport.la \
1131 $(top_builddir)/src/hello/libgnunethello.la \
1132 $(top_builddir)/src/util/libgnunetutil.la \
1133 libgnunettransporttesting.la
1134
1135test_transport_api_timeout_unix_SOURCES = \
1136 test_transport_api_timeout.c
1137test_transport_api_timeout_unix_LDADD = \
1138 libgnunettransport.la \
1139 $(top_builddir)/src/hello/libgnunethello.la \
1140 $(top_builddir)/src/util/libgnunetutil.la \
1141 libgnunettransporttesting.la
1142
1143test_transport_api_timeout_wlan_SOURCES = \
1144 test_transport_api_timeout.c
1145test_transport_api_timeout_wlan_LDADD = \
1146 libgnunettransport.la \
1147 $(top_builddir)/src/hello/libgnunethello.la \
1148 $(top_builddir)/src/util/libgnunetutil.la \
1149 libgnunettransporttesting.la
1150
1151test_transport_api_timeout_bluetooth_SOURCES = \
1152 test_transport_api_timeout.c
1153test_transport_api_timeout_bluetooth_LDADD = \
1154 libgnunettransport.la \
1155 $(top_builddir)/src/hello/libgnunethello.la \
1156 $(top_builddir)/src/util/libgnunetutil.la \
1157 libgnunettransporttesting.la
1158
1159test_transport_api_reliability_tcp_nat_SOURCES = \
1160 test_transport_api_reliability.c
1161test_transport_api_reliability_tcp_nat_LDADD = \
1162 libgnunettransport.la \
1163 $(top_builddir)/src/hello/libgnunethello.la \
1164 $(top_builddir)/src/util/libgnunetutil.la \
1165 libgnunettransporttesting.la
1166
1167test_transport_api_reliability_bluetooth_SOURCES = \
1168 test_transport_api_reliability.c
1169test_transport_api_reliability_bluetooth_LDADD = \
1170 libgnunettransport.la \
1171 $(top_builddir)/src/hello/libgnunethello.la \
1172 $(top_builddir)/src/util/libgnunetutil.la \
1173 libgnunettransporttesting.la
1174
1175test_transport_api_reliability_wlan_SOURCES = \
1176 test_transport_api_reliability.c
1177test_transport_api_reliability_wlan_LDADD = \
1178 libgnunettransport.la \
1179 $(top_builddir)/src/hello/libgnunethello.la \
1180 $(top_builddir)/src/util/libgnunetutil.la \
1181 libgnunettransporttesting.la
1182
1183if HAVE_EXPERIMENTAL
1184test_transport_api_udp_SOURCES = \
1185 test_transport_api.c
1186test_transport_api_udp_LDADD = \
1187 libgnunettransport.la \
1188 $(top_builddir)/src/hello/libgnunethello.la \
1189 $(top_builddir)/src/util/libgnunetutil.la \
1190 libgnunettransporttesting.la
1191
1192test_transport_api_timeout_udp_SOURCES = \
1193 test_transport_api_timeout.c
1194test_transport_api_timeout_udp_LDADD = \
1195 libgnunettransport.la \
1196 $(top_builddir)/src/hello/libgnunethello.la \
1197 $(top_builddir)/src/util/libgnunetutil.la \
1198 libgnunettransporttesting.la
1199
1200test_transport_api_udp_nat_SOURCES = \
1201 test_transport_api.c
1202test_transport_api_udp_nat_LDADD = \
1203 libgnunettransport.la \
1204 $(top_builddir)/src/hello/libgnunethello.la \
1205 $(top_builddir)/src/util/libgnunetutil.la \
1206 libgnunettransporttesting.la
1207endif
1208
1209test_transport_api_unix_SOURCES = \
1210 test_transport_api.c
1211test_transport_api_unix_LDADD = \
1212 libgnunettransport.la \
1213 $(top_builddir)/src/hello/libgnunethello.la \
1214 $(top_builddir)/src/util/libgnunetutil.la \
1215 libgnunettransporttesting.la
1216
1217test_transport_api_unix_abstract_SOURCES = \
1218 test_transport_api.c
1219test_transport_api_unix_abstract_LDADD = \
1220 libgnunettransport.la \
1221 $(top_builddir)/src/hello/libgnunethello.la \
1222 $(top_builddir)/src/util/libgnunetutil.la \
1223 libgnunettransporttesting.la
1224
1225# HTTP tests
1226test_transport_api_http_SOURCES = \
1227 test_transport_api.c
1228test_transport_api_http_LDADD = \
1229 libgnunettransport.la \
1230 $(top_builddir)/src/hello/libgnunethello.la \
1231 $(top_builddir)/src/util/libgnunetutil.la \
1232 libgnunettransporttesting.la
1233
1234test_transport_api_http_reverse_SOURCES = \
1235 test_transport_api.c
1236test_transport_api_http_reverse_LDADD = \
1237 libgnunettransport.la \
1238 $(top_builddir)/src/hello/libgnunethello.la \
1239 $(top_builddir)/src/util/libgnunetutil.la \
1240 libgnunettransporttesting.la
1241
1242test_transport_api_timeout_http_SOURCES = \
1243 test_transport_api_timeout.c
1244test_transport_api_timeout_http_LDADD = \
1245 libgnunettransport.la \
1246 $(top_builddir)/src/hello/libgnunethello.la \
1247 $(top_builddir)/src/util/libgnunetutil.la \
1248 libgnunettransporttesting.la
1249
1250test_transport_api_reliability_http_SOURCES = \
1251 test_transport_api_reliability.c
1252test_transport_api_reliability_http_LDADD = \
1253 libgnunettransport.la \
1254 $(top_builddir)/src/hello/libgnunethello.la \
1255 $(top_builddir)/src/util/libgnunetutil.la \
1256 libgnunettransporttesting.la
1257
1258test_transport_api_reliability_http_xhr_SOURCES = \
1259 test_transport_api_reliability.c
1260test_transport_api_reliability_http_xhr_LDADD = \
1261 libgnunettransport.la \
1262 $(top_builddir)/src/hello/libgnunethello.la \
1263 $(top_builddir)/src/util/libgnunetutil.la \
1264 libgnunettransporttesting.la
1265
1266test_quota_compliance_http_SOURCES = \
1267 test_quota_compliance.c
1268test_quota_compliance_http_LDADD = \
1269 libgnunettransport.la \
1270 $(top_builddir)/src/hello/libgnunethello.la \
1271 $(top_builddir)/src/ats/libgnunetats.la \
1272 $(top_builddir)/src/nt/libgnunetnt.la \
1273 $(top_builddir)/src/util/libgnunetutil.la \
1274 libgnunettransporttesting.la
1275
1276test_quota_compliance_http_asymmetric_SOURCES = \
1277 test_quota_compliance.c
1278test_quota_compliance_http_asymmetric_LDADD = \
1279 libgnunettransport.la \
1280 $(top_builddir)/src/hello/libgnunethello.la \
1281 $(top_builddir)/src/ats/libgnunetats.la \
1282 $(top_builddir)/src/nt/libgnunetnt.la \
1283 $(top_builddir)/src/util/libgnunetutil.la \
1284 libgnunettransporttesting.la
1285
1286test_quota_compliance_https_SOURCES = \
1287 test_quota_compliance.c
1288test_quota_compliance_https_LDADD = \
1289 libgnunettransport.la \
1290 $(top_builddir)/src/hello/libgnunethello.la \
1291 $(top_builddir)/src/ats/libgnunetats.la \
1292 $(top_builddir)/src/nt/libgnunetnt.la \
1293 $(top_builddir)/src/util/libgnunetutil.la \
1294 libgnunettransporttesting.la
1295
1296test_quota_compliance_https_asymmetric_SOURCES = \
1297 test_quota_compliance.c
1298test_quota_compliance_https_asymmetric_LDADD = \
1299 libgnunettransport.la \
1300 $(top_builddir)/src/hello/libgnunethello.la \
1301 $(top_builddir)/src/ats/libgnunetats.la \
1302 $(top_builddir)/src/nt/libgnunetnt.la \
1303 $(top_builddir)/src/util/libgnunetutil.la \
1304 libgnunettransporttesting.la
1305
1306# HTTPS tests
1307test_transport_api_https_SOURCES = \
1308 test_transport_api.c
1309test_transport_api_https_LDADD = \
1310 libgnunettransport.la \
1311 $(top_builddir)/src/hello/libgnunethello.la \
1312 $(top_builddir)/src/util/libgnunetutil.la \
1313 libgnunettransporttesting.la
1314
1315test_transport_api_timeout_https_SOURCES = \
1316 test_transport_api_timeout.c
1317test_transport_api_timeout_https_LDADD = \
1318 libgnunettransport.la \
1319 $(top_builddir)/src/hello/libgnunethello.la \
1320 $(top_builddir)/src/util/libgnunetutil.la \
1321 libgnunettransporttesting.la
1322
1323
1324test_transport_api_reliability_https_SOURCES = \
1325 test_transport_api_reliability.c
1326test_transport_api_reliability_https_LDADD = \
1327 libgnunettransport.la \
1328 $(top_builddir)/src/hello/libgnunethello.la \
1329 $(top_builddir)/src/util/libgnunetutil.la \
1330 libgnunettransporttesting.la
1331
1332test_transport_api_reliability_https_xhr_SOURCES = \
1333 test_transport_api_reliability.c
1334test_transport_api_reliability_https_xhr_LDADD = \
1335 libgnunettransport.la \
1336 $(top_builddir)/src/hello/libgnunethello.la \
1337 $(top_builddir)/src/util/libgnunetutil.la \
1338 libgnunettransporttesting.la
1339
1340test_transport_api_reliability_unix_SOURCES = \
1341 test_transport_api_reliability.c
1342test_transport_api_reliability_unix_LDADD = \
1343 libgnunettransport.la \
1344 $(top_builddir)/src/hello/libgnunethello.la \
1345 $(top_builddir)/src/util/libgnunetutil.la \
1346 libgnunettransporttesting.la
1347
1348if HAVE_EXPERIMENTAL
1349test_transport_api_reliability_udp_SOURCES = \
1350 test_transport_api_reliability.c
1351test_transport_api_reliability_udp_LDADD = \
1352 libgnunettransport.la \
1353 $(top_builddir)/src/hello/libgnunethello.la \
1354 $(top_builddir)/src/util/libgnunetutil.la \
1355 libgnunettransporttesting.la
1356endif
1357
1358if LINUX
1359test_transport_api_wlan_SOURCES = \
1360 test_transport_api.c
1361test_transport_api_wlan_LDADD = \
1362 libgnunettransport.la \
1363 $(top_builddir)/src/hello/libgnunethello.la \
1364 $(top_builddir)/src/util/libgnunetutil.la \
1365 libgnunettransporttesting.la
1366endif
1367
1368if LINUX
1369if HAVE_LIBBLUETOOTH
1370test_transport_api_bluetooth_SOURCES = \
1371 test_transport_api.c
1372test_transport_api_bluetooth_LDADD = \
1373 libgnunettransport.la \
1374 $(top_builddir)/src/hello/libgnunethello.la \
1375 $(top_builddir)/src/util/libgnunetutil.la \
1376 libgnunettransporttesting.la
1377endif
1378endif
1379
1380test_transport_address_switch_tcp_SOURCES = \
1381 test_transport_address_switch.c
1382test_transport_address_switch_tcp_LDADD = \
1383 libgnunettransport.la \
1384 $(top_builddir)/src/hello/libgnunethello.la \
1385 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1386 $(top_builddir)/src/util/libgnunetutil.la \
1387 libgnunettransporttesting.la
1388
1389if HAVE_EXPERIMENTAL
1390test_transport_address_switch_udp_SOURCES = \
1391 test_transport_address_switch.c
1392test_transport_address_switch_udp_LDADD = \
1393 libgnunettransport.la \
1394 $(top_builddir)/src/hello/libgnunethello.la \
1395 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1396 $(top_builddir)/src/util/libgnunetutil.la \
1397 libgnunettransporttesting.la
1398endif
1399
1400 test_transport_address_switch_http_SOURCES = \
1401 test_transport_address_switch.c
1402test_transport_address_switch_http_LDADD = \
1403 libgnunettransport.la \
1404 $(top_builddir)/src/hello/libgnunethello.la \
1405 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1406 $(top_builddir)/src/util/libgnunetutil.la \
1407 libgnunettransporttesting.la
1408
1409 test_transport_address_switch_https_SOURCES = \
1410 test_transport_address_switch.c
1411test_transport_address_switch_https_LDADD = \
1412 libgnunettransport.la \
1413 $(top_builddir)/src/hello/libgnunethello.la \
1414 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1415 $(top_builddir)/src/util/libgnunetutil.la \
1416 libgnunettransporttesting.la
1417
1418test_quota_compliance_tcp_SOURCES = \
1419 test_quota_compliance.c
1420test_quota_compliance_tcp_LDADD = \
1421 libgnunettransport.la \
1422 $(top_builddir)/src/hello/libgnunethello.la \
1423 $(top_builddir)/src/ats/libgnunetats.la \
1424 $(top_builddir)/src/nt/libgnunetnt.la \
1425 $(top_builddir)/src/util/libgnunetutil.la \
1426 libgnunettransporttesting.la
1427
1428test_quota_compliance_tcp_asymmetric_SOURCES = \
1429 test_quota_compliance.c
1430test_quota_compliance_tcp_asymmetric_LDADD = \
1431 libgnunettransport.la \
1432 $(top_builddir)/src/hello/libgnunethello.la \
1433 $(top_builddir)/src/nt/libgnunetnt.la \
1434 $(top_builddir)/src/ats/libgnunetats.la \
1435 $(top_builddir)/src/util/libgnunetutil.la \
1436 libgnunettransporttesting.la
1437
1438if HAVE_EXPERIMENTAL
1439test_quota_compliance_udp_SOURCES = \
1440 test_quota_compliance.c
1441test_quota_compliance_udp_LDADD = \
1442 libgnunettransport.la \
1443 $(top_builddir)/src/hello/libgnunethello.la \
1444 $(top_builddir)/src/ats/libgnunetats.la \
1445 $(top_builddir)/src/nt/libgnunetnt.la \
1446 $(top_builddir)/src/util/libgnunetutil.la \
1447 libgnunettransporttesting.la
1448endif
1449
1450test_quota_compliance_unix_SOURCES = \
1451 test_quota_compliance.c
1452test_quota_compliance_unix_LDADD = \
1453 libgnunettransport.la \
1454 $(top_builddir)/src/hello/libgnunethello.la \
1455 $(top_builddir)/src/ats/libgnunetats.la \
1456 $(top_builddir)/src/nt/libgnunetnt.la \
1457 $(top_builddir)/src/util/libgnunetutil.la \
1458 libgnunettransporttesting.la
1459
1460test_quota_compliance_unix_asymmetric_SOURCES = \
1461 test_quota_compliance.c
1462test_quota_compliance_unix_asymmetric_LDADD = \
1463 libgnunettransport.la \
1464 $(top_builddir)/src/hello/libgnunethello.la \
1465 $(top_builddir)/src/ats/libgnunetats.la \
1466 $(top_builddir)/src/nt/libgnunetnt.la \
1467 $(top_builddir)/src/util/libgnunetutil.la \
1468 libgnunettransporttesting.la
1469
1470test_quota_compliance_wlan_SOURCES = \
1471 test_quota_compliance.c
1472test_quota_compliance_wlan_LDADD = \
1473 libgnunettransport.la \
1474 $(top_builddir)/src/hello/libgnunethello.la \
1475 $(top_builddir)/src/ats/libgnunetats.la \
1476 $(top_builddir)/src/nt/libgnunetnt.la \
1477 $(top_builddir)/src/util/libgnunetutil.la \
1478 libgnunettransporttesting.la
1479
1480test_quota_compliance_wlan_asymmetric_SOURCES = \
1481 test_quota_compliance.c
1482test_quota_compliance_wlan_asymmetric_LDADD = \
1483 libgnunettransport.la \
1484 $(top_builddir)/src/hello/libgnunethello.la \
1485 $(top_builddir)/src/ats/libgnunetats.la \
1486 $(top_builddir)/src/nt/libgnunetnt.la \
1487 $(top_builddir)/src/util/libgnunetutil.la \
1488 libgnunettransporttesting.la
1489
1490test_quota_compliance_bluetooth_SOURCES = \
1491 test_quota_compliance.c
1492test_quota_compliance_bluetooth_LDADD = \
1493 libgnunettransport.la \
1494 $(top_builddir)/src/hello/libgnunethello.la \
1495 $(top_builddir)/src/ats/libgnunetats.la \
1496 $(top_builddir)/src/nt/libgnunetnt.la \
1497 $(top_builddir)/src/util/libgnunetutil.la \
1498 libgnunettransporttesting.la
1499
1500test_quota_compliance_bluetooth_asymmetric_SOURCES = \
1501 test_quota_compliance.c
1502test_quota_compliance_bluetooth_asymmetric_LDADD = \
1503 libgnunettransport.la \
1504 $(top_builddir)/src/hello/libgnunethello.la \
1505 $(top_builddir)/src/ats/libgnunetats.la \
1506 $(top_builddir)/src/nt/libgnunetnt.la \
1507 $(top_builddir)/src/util/libgnunetutil.la \
1508 libgnunettransporttesting.la
1509
1510test_transport_api_multi_SOURCES = \
1511 test_transport_api.c
1512test_transport_api_multi_LDADD = \
1513 libgnunettransport.la \
1514 $(top_builddir)/src/hello/libgnunethello.la \
1515 $(top_builddir)/src/util/libgnunetutil.la \
1516 libgnunettransporttesting.la
1517
1518test_transport_api_monitor_peers_SOURCES = \
1519 test_transport_api_monitor_peers.c
1520test_transport_api_monitor_peers_LDADD = \
1521 libgnunettransport.la \
1522 $(top_builddir)/src/hello/libgnunethello.la \
1523 $(top_builddir)/src/util/libgnunetutil.la \
1524 libgnunettransporttesting.la
1525
1526test_transport_api_slow_ats_SOURCES = \
1527 test_transport_api.c
1528test_transport_api_slow_ats_LDADD = \
1529 libgnunettransport.la \
1530 $(top_builddir)/src/hello/libgnunethello.la \
1531 $(top_builddir)/src/util/libgnunetutil.la \
1532 libgnunettransporttesting.la
1533
1534
1535EXTRA_DIST = \
1536gnunet-transport-certificate-creation.in \
1537communicator-unix.conf \
1538test_plugin_hostkey \
1539test_plugin_hostkey.ecc \
1540test_delay \
1541template_cfg_peer1.conf\
1542template_cfg_peer2.conf\
1543test_plugin_transport_data.conf\
1544test_plugin_transport_data_udp.conf\
1545test_quota_compliance_data.conf\
1546test_quota_compliance_http_peer1.conf\
1547test_quota_compliance_http_peer2.conf\
1548test_quota_compliance_https_peer1.conf\
1549test_quota_compliance_https_peer2.conf\
1550test_quota_compliance_tcp_peer1.conf\
1551test_quota_compliance_tcp_peer2.conf\
1552test_quota_compliance_udp_peer1.conf\
1553test_quota_compliance_udp_peer2.conf\
1554test_quota_compliance_unix_peer1.conf\
1555test_quota_compliance_unix_peer2.conf\
1556test_quota_compliance_wlan_peer1.conf\
1557test_quota_compliance_wlan_peer2.conf\
1558test_quota_compliance_bluetooth_peer1.conf\
1559test_quota_compliance_bluetooth_peer2.conf\
1560test_quota_compliance_http_asymmetric_peer1.conf\
1561test_quota_compliance_http_asymmetric_peer2.conf\
1562test_quota_compliance_https_asymmetric_peer1.conf\
1563test_quota_compliance_https_asymmetric_peer2.conf\
1564test_quota_compliance_tcp_asymmetric_peer1.conf\
1565test_quota_compliance_tcp_asymmetric_peer2.conf\
1566test_quota_compliance_unix_asymmetric_peer1.conf\
1567test_quota_compliance_unix_asymmetric_peer2.conf\
1568test_quota_compliance_wlan_asymmetric_peer1.conf\
1569test_quota_compliance_wlan_asymmetric_peer2.conf\
1570test_quota_compliance_bluetooth_asymmetric_peer1.conf\
1571test_quota_compliance_bluetooth_asymmetric_peer2.conf\
1572test_transport_api_data.conf\
1573test_transport_api_blacklisting_tcp_peer1.conf \
1574test_transport_api_blacklisting_tcp_peer2.conf \
1575test_transport_api_http_peer1.conf\
1576test_transport_api_http_peer2.conf\
1577test_transport_api_https_peer1.conf\
1578test_transport_api_https_peer2.conf\
1579test_transport_api_limited_sockets_tcp_peer1.conf\
1580test_transport_api_limited_sockets_tcp_peer2.conf\
1581test_transport_api_timeout_tcp_peer1.conf\
1582test_transport_api_timeout_tcp_peer2.conf\
1583test_transport_api_multi_peer1.conf\
1584test_transport_api_multi_peer2.conf\
1585test_transport_api_restart_1peer_peer1.conf\
1586test_transport_api_restart_1peer_peer2.conf\
1587test_transport_api_reliability_http_peer1.conf\
1588test_transport_api_reliability_http_peer2.conf\
1589test_transport_api_reliability_https_peer1.conf\
1590test_transport_api_reliability_https_peer2.conf\
1591test_transport_api_reliability_tcp_nat_peer1.conf\
1592test_transport_api_reliability_tcp_nat_peer2.conf\
1593test_transport_api_reliability_tcp_peer1.conf\
1594test_transport_api_reliability_tcp_peer2.conf\
1595test_transport_api_reliability_wlan_peer1.conf\
1596test_transport_api_reliability_wlan_peer2.conf\
1597test_transport_api_reliability_bluetooth_peer1.conf\
1598test_transport_api_reliability_bluetooth_peer2.conf\
1599test_transport_api_manipulation_send_tcp_peer1.conf\
1600test_transport_api_manipulation_send_tcp_peer2.conf\
1601test_transport_api_manipulation_recv_tcp_peer1.conf\
1602test_transport_api_manipulation_recv_tcp_peer2.conf\
1603test_transport_api_manipulation_cfg_peer1.conf\
1604test_transport_api_manipulation_cfg_peer2.conf\
1605test_transport_api_restart_1peer_peer1.conf\
1606test_transport_api_restart_1peer_peer2.conf\
1607test_transport_api_restart_2peers_peer1.conf\
1608test_transport_api_restart_2peers_peer2.conf\
1609test_transport_api_tcp_nat_peer1.conf\
1610test_transport_api_tcp_nat_peer2.conf\
1611test_transport_api_tcp_peer1.conf\
1612test_transport_api_tcp_peer2.conf\
1613test_transport_api2_tcp_peer1.conf\
1614test_transport_api2_tcp_peer2.conf\
1615test_transport_api_udp_nat_peer1.conf\
1616test_transport_api_udp_nat_peer2.conf\
1617test_transport_api_udp_peer1.conf\
1618test_transport_api_udp_peer2.conf\
1619test_transport_api_timeout_udp_peer1.conf\
1620test_transport_api_timeout_udp_peer2.conf\
1621test_transport_api_unix_peer1.conf\
1622test_transport_api_unix_peer2.conf\
1623test_transport_api_unix_abstract_peer1.conf \
1624test_transport_api_unix_abstract_peer2.conf \
1625test_transport_api_timeout_unix_peer1.conf\
1626test_transport_api_timeout_unix_peer2.conf\
1627test_transport_api_timeout_wlan_peer1.conf \
1628test_transport_api_timeout_wlan_peer2.conf \
1629test_transport_api_timeout_bluetooth_peer1.conf\
1630test_transport_api_timeout_bluetooth_peer2.conf\
1631test_transport_api_reliability_udp_peer1.conf\
1632test_transport_api_reliability_udp_peer2.conf\
1633test_transport_api_reliability_http_xhr_peer1.conf\
1634test_transport_api_reliability_http_xhr_peer2.conf\
1635test_transport_api_reliability_https_xhr_peer1.conf\
1636test_transport_api_reliability_https_xhr_peer2.conf\
1637test_transport_api_reliability_unix_peer1.conf\
1638test_transport_api_reliability_unix_peer2.conf\
1639test_transport_api_reliability_wlan_peer1.conf\
1640test_transport_api_reliability_wlan_peer2.conf\
1641test_transport_api_unreliability_wlan_peer1.conf\
1642test_transport_api_unreliability_wlan_peer2.conf\
1643test_transport_api_reliability_bluetooth_peer1.conf\
1644test_transport_api_reliability_bluetooth_peer2.conf\
1645test_transport_api_wlan_peer1.conf\
1646test_transport_api_wlan_peer2.conf\
1647test_transport_api_bluetooth_peer1.conf\
1648test_transport_api_bluetooth_peer2.conf\
1649test_transport_api_monitor_peers_peer1.conf\
1650test_transport_api_monitor_peers_peer2.conf\
1651test_transport_api_monitor_validation_peer1.conf\
1652test_transport_api_monitor_validation_peer2.conf\
1653test_transport_defaults.conf\
1654test_transport_api_disconnect_tcp_peer1.conf\
1655test_transport_api_disconnect_tcp_peer2.conf\
1656test_transport_api_timeout_http_peer1.conf\
1657test_transport_api_timeout_http_peer2.conf\
1658test_transport_api_timeout_https_peer1.conf\
1659test_transport_api_timeout_https_peer2.conf\
1660test_transport_blacklisting_cfg_peer1.conf \
1661test_transport_blacklisting_cfg_peer2.conf \
1662test_transport_blacklisting_cfg_blp_peer1_full.conf\
1663test_transport_blacklisting_cfg_blp_peer1_plugin.conf \
1664test_transport_blacklisting_cfg_blp_peer2_full.conf\
1665test_transport_blacklisting_cfg_blp_peer2_plugin.conf \
1666test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf \
1667test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf \
1668test_transport_api_http_reverse_peer1.conf \
1669test_transport_api_http_reverse_peer2.conf \
1670perf_tcp_peer1.conf \
1671perf_tcp_peer2.conf \
1672test_transport_api_slow_ats_peer1.conf \
1673test_transport_api_slow_ats_peer2.conf \
1674 tcp_connection_legacy.c \
1675 tcp_server_mst_legacy.c \
1676 tcp_server_legacy.c \
1677 tcp_service_legacy.c \
1678test_communicator_unix_basic_peer1.conf \
1679test_communicator_unix_basic_peer2.conf \
1680test_communicator_tcp_basic_peer1.conf \
1681test_communicator_tcp_basic_peer2.conf \
1682test_communicator_udp_basic_peer1.conf \
1683test_communicator_udp_basic_peer2.conf \
1684test_communicator_tcp_rekey_peer1.conf \
1685test_communicator_tcp_rekey_peer2.conf \
1686test_communicator_udp_rekey_peer1.conf \
1687test_communicator_udp_rekey_peer2.conf \
1688test_communicator_udp_backchannel_peer1.conf \
1689test_communicator_udp_backchannel_peer2.conf \
1690test_communicator_tcp_bidirect_peer1.conf \
1691test_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 d8bf7c1a8..000000000
--- a/src/transport/gnunet-communicator-tcp.c
+++ /dev/null
@@ -1,3666 +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_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 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_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 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_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 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_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 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_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_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 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 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 if (ntohs (hdr->size) != plaintext_len)
1123 {
1124 /* NOTE: If we ever allow multiple CORE messages in one
1125 BOX, this will have to change! */
1126 GNUNET_break (0);
1127 return;
1128 }
1129 ret = GNUNET_TRANSPORT_communicator_receive (ch,
1130 &queue->target,
1131 hdr,
1132 ADDRESS_VALIDITY_PERIOD,
1133 &core_read_finished_cb,
1134 queue);
1135 if (GNUNET_OK == ret)
1136 queue->backpressure++;
1137 GNUNET_break (GNUNET_NO != ret); /* backpressure not working!? */
1138 if (GNUNET_SYSERR == ret)
1139 GNUNET_STATISTICS_update (stats,
1140 "# bytes lost due to CORE not running",
1141 plaintext_len,
1142 GNUNET_NO);
1143}
1144
1145
1146/**
1147 * Setup @a cipher based on shared secret @a dh and decrypting
1148 * peer @a pid.
1149 *
1150 * @param dh shared secret
1151 * @param pid decrypting peer's identity
1152 * @param cipher[out] cipher to initialize
1153 * @param hmac_key[out] HMAC key to initialize
1154 */
1155static void
1156setup_cipher (const struct GNUNET_HashCode *dh,
1157 const struct GNUNET_PeerIdentity *pid,
1158 gcry_cipher_hd_t *cipher,
1159 struct GNUNET_HashCode *hmac_key)
1160{
1161 char key[256 / 8];
1162 char ctr[128 / 8];
1163
1164 GNUNET_assert (0 == gcry_cipher_open (cipher,
1165 GCRY_CIPHER_AES256 /* low level: go for speed */,
1166 GCRY_CIPHER_MODE_CTR,
1167 0 /* flags */));
1168 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (key,
1169 sizeof(key),
1170 "TCP-key",
1171 strlen ("TCP-key"),
1172 dh,
1173 sizeof(*dh),
1174 pid,
1175 sizeof(*pid),
1176 NULL,
1177 0));
1178 GNUNET_assert (0 == gcry_cipher_setkey (*cipher, key, sizeof(key)));
1179 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (ctr,
1180 sizeof(ctr),
1181 "TCP-ctr",
1182 strlen ("TCP-ctr"),
1183 dh,
1184 sizeof(*dh),
1185 pid,
1186 sizeof(*pid),
1187 NULL,
1188 0));
1189 gcry_cipher_setctr (*cipher, ctr, sizeof(ctr));
1190 GNUNET_assert (GNUNET_YES ==
1191 GNUNET_CRYPTO_kdf (hmac_key,
1192 sizeof(struct GNUNET_HashCode),
1193 "TCP-hmac",
1194 strlen ("TCP-hmac"),
1195 dh,
1196 sizeof(*dh),
1197 pid,
1198 sizeof(*pid),
1199 NULL,
1200 0));
1201}
1202
1203
1204/**
1205 * Callback called when peerstore store operation for rekey monotime value is finished.
1206 * @param cls Queue context the store operation was executed.
1207 * @param success Store operation was successful (GNUNET_OK) or not.
1208 */
1209static void
1210rekey_monotime_store_cb (void *cls, int success)
1211{
1212 struct Queue *queue = cls;
1213 if (GNUNET_OK != success)
1214 {
1215 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1216 "Failed to store rekey monotonic time in PEERSTORE!\n");
1217 }
1218 queue->rekey_monotime_sc = NULL;
1219}
1220
1221
1222/**
1223 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY
1224 * where found.
1225 * @param cls Queue context the store operation was executed.
1226 * @param record The record found or NULL if there is no record left.
1227 * @param emsg Message from peerstore.
1228 */
1229static void
1230rekey_monotime_cb (void *cls,
1231 const struct GNUNET_PEERSTORE_Record *record,
1232 const char *emsg)
1233{
1234 struct Queue *queue = cls;
1235 struct GNUNET_TIME_AbsoluteNBO *mtbe;
1236 struct GNUNET_TIME_Absolute mt;
1237 const struct GNUNET_PeerIdentity *pid;
1238 struct GNUNET_TIME_AbsoluteNBO *rekey_monotonic_time;
1239
1240 (void) emsg;
1241
1242 rekey_monotonic_time = &queue->rekey_monotonic_time;
1243 pid = &queue->target;
1244 if (NULL == record)
1245 {
1246 queue->rekey_monotime_get = NULL;
1247 return;
1248 }
1249 if (sizeof(*mtbe) != record->value_size)
1250 {
1251 GNUNET_break (0);
1252 return;
1253 }
1254 mtbe = record->value;
1255 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
1256 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
1257 queue->rekey_monotonic_time).abs_value_us)
1258 {
1259 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1260 "Queue from %s dropped, rekey monotime in the past\n",
1261 GNUNET_i2s (&queue->target));
1262 GNUNET_break (0);
1263 queue_finish (queue);
1264 return;
1265 }
1266 queue->rekey_monotime_sc = GNUNET_PEERSTORE_store (peerstore,
1267 "transport_tcp_communicator",
1268 pid,
1269 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY,
1270 rekey_monotonic_time,
1271 sizeof(*
1272 rekey_monotonic_time),
1273 GNUNET_TIME_UNIT_FOREVER_ABS,
1274 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
1275 &rekey_monotime_store_cb,
1276 queue);
1277}
1278
1279
1280/**
1281 * Setup cipher of @a queue for decryption.
1282 *
1283 * @param ephemeral ephemeral key we received from the other peer
1284 * @param queue[in,out] queue to initialize decryption cipher for
1285 */
1286static void
1287setup_in_cipher (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
1288 struct Queue *queue)
1289{
1290 struct GNUNET_HashCode dh;
1291
1292 GNUNET_CRYPTO_eddsa_ecdh (my_private_key, ephemeral, &dh);
1293 setup_cipher (&dh, &my_identity, &queue->in_cipher, &queue->in_hmac);
1294}
1295
1296
1297/**
1298 * Handle @a rekey message on @a queue. The message was already
1299 * HMAC'ed, but we should additionally still check the signature.
1300 * Then we need to stop the old cipher and start afresh.
1301 *
1302 * @param queue the queue @a rekey was received on
1303 * @param rekey the rekey message
1304 */
1305static void
1306do_rekey (struct Queue *queue, const struct TCPRekey *rekey)
1307{
1308 struct TcpRekeySignature thp;
1309
1310 thp.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_TCP_REKEY);
1311 thp.purpose.size = htonl (sizeof(thp));
1312 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1313 "do_rekey size %u\n",
1314 thp.purpose.size);
1315 thp.sender = queue->target;
1316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1317 "sender %s\n",
1318 GNUNET_p2s (&thp.sender.public_key));
1319 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1320 "sender %s\n",
1321 GNUNET_p2s (&queue->target.public_key));
1322 thp.receiver = my_identity;
1323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1324 "receiver %s\n",
1325 GNUNET_p2s (&thp.receiver.public_key));
1326 thp.ephemeral = rekey->ephemeral;
1327 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1328 "ephemeral %s\n",
1329 GNUNET_e2s (&thp.ephemeral));
1330 thp.monotonic_time = rekey->monotonic_time;
1331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1332 "time %s\n",
1333 GNUNET_STRINGS_absolute_time_to_string (
1334 GNUNET_TIME_absolute_ntoh (thp.monotonic_time)));
1335 GNUNET_assert (ntohl ((&thp)->purpose.size) == sizeof (*(&thp)));
1336 if (GNUNET_OK !=
1337 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_COMMUNICATOR_TCP_REKEY,
1338 &thp,
1339 &rekey->sender_sig,
1340 &queue->target.public_key))
1341 {
1342 GNUNET_break (0);
1343 queue_finish (queue);
1344 return;
1345 }
1346 queue->rekey_monotonic_time = rekey->monotonic_time;
1347 queue->rekey_monotime_get = GNUNET_PEERSTORE_iterate (peerstore,
1348 "transport_tcp_communicator",
1349 &queue->target,
1350 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY,
1351 &rekey_monotime_cb,
1352 queue);
1353 gcry_cipher_close (queue->in_cipher);
1354 queue->rekeyed = GNUNET_YES;
1355 setup_in_cipher (&rekey->ephemeral, queue);
1356}
1357
1358
1359/**
1360 * Callback called when peerstore store operation for handshake ack monotime value is finished.
1361 * @param cls Queue context the store operation was executed.
1362 * @param success Store operation was successful (GNUNET_OK) or not.
1363 */
1364static void
1365handshake_ack_monotime_store_cb (void *cls, int success)
1366{
1367 struct Queue *queue = cls;
1368
1369 if (GNUNET_OK != success)
1370 {
1371 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1372 "Failed to store handshake ack monotonic time in PEERSTORE!\n");
1373 }
1374 queue->handshake_ack_monotime_sc = NULL;
1375}
1376
1377
1378/**
1379 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK
1380 * where found.
1381 * @param cls Queue context the store operation was executed.
1382 * @param record The record found or NULL if there is no record left.
1383 * @param emsg Message from peerstore.
1384 */
1385static void
1386handshake_ack_monotime_cb (void *cls,
1387 const struct GNUNET_PEERSTORE_Record *record,
1388 const char *emsg)
1389{
1390 struct Queue *queue = cls;
1391 struct GNUNET_TIME_AbsoluteNBO *mtbe;
1392 struct GNUNET_TIME_Absolute mt;
1393 const struct GNUNET_PeerIdentity *pid;
1394 struct GNUNET_TIME_AbsoluteNBO *handshake_ack_monotonic_time;
1395
1396 (void) emsg;
1397
1398 handshake_ack_monotonic_time = &queue->handshake_ack_monotonic_time;
1399 pid = &queue->target;
1400 if (NULL == record)
1401 {
1402 queue->handshake_ack_monotime_get = NULL;
1403 return;
1404 }
1405 if (sizeof(*mtbe) != record->value_size)
1406 {
1407 GNUNET_break (0);
1408 return;
1409 }
1410 mtbe = record->value;
1411 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
1412 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
1413 queue->handshake_ack_monotonic_time).abs_value_us)
1414 {
1415 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1416 "Queue from %s dropped, handshake ack monotime in the past\n",
1417 GNUNET_i2s (&queue->target));
1418 GNUNET_break (0);
1419 queue_finish (queue);
1420 return;
1421 }
1422 queue->handshake_ack_monotime_sc =
1423 GNUNET_PEERSTORE_store (peerstore,
1424 "transport_tcp_communicator",
1425 pid,
1426 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK,
1427 handshake_ack_monotonic_time,
1428 sizeof(*handshake_ack_monotonic_time),
1429 GNUNET_TIME_UNIT_FOREVER_ABS,
1430 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
1431 &
1432 handshake_ack_monotime_store_cb,
1433 queue);
1434}
1435
1436
1437/**
1438 * Sending challenge with TcpConfirmationAck back to sender of ephemeral key.
1439 *
1440 * @param tc The TCPConfirmation originally send.
1441 * @param queue The queue context.
1442 */
1443static void
1444send_challenge (struct ChallengeNonceP challenge, struct Queue *queue)
1445{
1446 struct TCPConfirmationAck tca;
1447 struct TcpHandshakeAckSignature thas;
1448
1449 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1450 "transport",
1451 "sending challenge\n");
1452
1453 tca.header.type = ntohs (
1454 GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK);
1455 tca.header.size = ntohs (sizeof(tca));
1456 tca.challenge = challenge;
1457 tca.sender = my_identity;
1458 tca.monotonic_time =
1459 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
1460 thas.purpose.purpose = htonl (
1461 GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE_ACK);
1462 thas.purpose.size = htonl (sizeof(thas));
1463 thas.sender = my_identity;
1464 thas.receiver = queue->target;
1465 thas.monotonic_time = tca.monotonic_time;
1466 thas.challenge = tca.challenge;
1467 GNUNET_CRYPTO_eddsa_sign (my_private_key,
1468 &thas,
1469 &tca.sender_sig);
1470 GNUNET_assert (0 ==
1471 gcry_cipher_encrypt (queue->out_cipher,
1472 &queue->cwrite_buf[queue->cwrite_off],
1473 sizeof(tca),
1474 &tca,
1475 sizeof(tca)));
1476 queue->cwrite_off += sizeof(tca);
1477 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1478 "transport",
1479 "sending challenge done\n");
1480}
1481
1482
1483/**
1484 * Setup cipher for outgoing data stream based on target and
1485 * our ephemeral private key.
1486 *
1487 * @param queue queue to setup outgoing (encryption) cipher for
1488 */
1489static void
1490setup_out_cipher (struct Queue *queue)
1491{
1492 struct GNUNET_HashCode dh;
1493
1494 GNUNET_CRYPTO_ecdh_eddsa (&queue->ephemeral, &queue->target.public_key, &dh);
1495 /* we don't need the private key anymore, drop it! */
1496 memset (&queue->ephemeral, 0, sizeof(queue->ephemeral));
1497 setup_cipher (&dh, &queue->target, &queue->out_cipher, &queue->out_hmac);
1498 queue->rekey_time = GNUNET_TIME_relative_to_absolute (rekey_interval);
1499 queue->rekey_left_bytes =
1500 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, REKEY_MAX_BYTES);
1501}
1502
1503
1504/**
1505 * Inject a `struct TCPRekey` message into the queue's plaintext
1506 * buffer.
1507 *
1508 * @param queue queue to perform rekeying on
1509 */
1510static void
1511inject_rekey (struct Queue *queue)
1512{
1513 struct TCPRekey rekey;
1514 struct TcpRekeySignature thp;
1515
1516 GNUNET_assert (0 == queue->pwrite_off);
1517 memset (&rekey, 0, sizeof(rekey));
1518 GNUNET_CRYPTO_ecdhe_key_create (&queue->ephemeral);
1519 rekey.header.type = ntohs (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY);
1520 rekey.header.size = ntohs (sizeof(rekey));
1521 GNUNET_CRYPTO_ecdhe_key_get_public (&queue->ephemeral, &rekey.ephemeral);
1522 rekey.monotonic_time =
1523 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
1524 thp.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_TCP_REKEY);
1525 thp.purpose.size = htonl (sizeof(thp));
1526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1527 "inject_rekey size %u\n",
1528 thp.purpose.size);
1529 thp.sender = my_identity;
1530 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1531 "sender %s\n",
1532 GNUNET_p2s (&thp.sender.public_key));
1533 thp.receiver = queue->target;
1534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1535 "receiver %s\n",
1536 GNUNET_p2s (&thp.receiver.public_key));
1537 thp.ephemeral = rekey.ephemeral;
1538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1539 "ephemeral %s\n",
1540 GNUNET_e2s (&thp.ephemeral));
1541 thp.monotonic_time = rekey.monotonic_time;
1542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1543 "time %s\n",
1544 GNUNET_STRINGS_absolute_time_to_string (
1545 GNUNET_TIME_absolute_ntoh (thp.monotonic_time)));
1546 GNUNET_CRYPTO_eddsa_sign (my_private_key,
1547 &thp,
1548 &rekey.sender_sig);
1549 calculate_hmac (&queue->out_hmac, &rekey, sizeof(rekey), &rekey.hmac);
1550 /* Encrypt rekey message with 'old' cipher */
1551 GNUNET_assert (0 ==
1552 gcry_cipher_encrypt (queue->out_cipher,
1553 &queue->cwrite_buf[queue->cwrite_off],
1554 sizeof(rekey),
1555 &rekey,
1556 sizeof(rekey)));
1557 queue->cwrite_off += sizeof(rekey);
1558 /* Setup new cipher for successive messages */
1559 gcry_cipher_close (queue->out_cipher);
1560 setup_out_cipher (queue);
1561}
1562
1563
1564/**
1565 * We have been notified that our socket is ready to write.
1566 * Then reschedule this function to be called again once more is available.
1567 *
1568 * @param cls a `struct Queue`
1569 */
1570static void
1571queue_write (void *cls)
1572{
1573 struct Queue *queue = cls;
1574 ssize_t sent;
1575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "In queue write\n");
1576 queue->write_task = NULL;
1577 if (0 != queue->cwrite_off)
1578 {
1579 sent = GNUNET_NETWORK_socket_send (queue->sock,
1580 queue->cwrite_buf,
1581 queue->cwrite_off);
1582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1583 "Sent %lu bytes to TCP queue\n", sent);
1584 if ((-1 == sent) && (EAGAIN != errno) && (EINTR != errno))
1585 {
1586 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
1587 queue_destroy (queue);
1588 return;
1589 }
1590 if (sent > 0)
1591 {
1592 size_t usent = (size_t) sent;
1593 queue->cwrite_off -= usent;
1594 memmove (queue->cwrite_buf,
1595 &queue->cwrite_buf[usent],
1596 queue->cwrite_off);
1597 reschedule_queue_timeout (queue);
1598 }
1599 }
1600 /* can we encrypt more? (always encrypt full messages, needed
1601 such that #mq_cancel() can work!) */
1602 if ((0 < queue->rekey_left_bytes) &&
1603 (queue->pwrite_off > 0) &&
1604 (queue->cwrite_off + queue->pwrite_off <= BUF_SIZE))
1605 {
1606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1607 "Encrypting %lu bytes\n", queue->pwrite_off);
1608 GNUNET_assert (0 ==
1609 gcry_cipher_encrypt (queue->out_cipher,
1610 &queue->cwrite_buf[queue->cwrite_off],
1611 queue->pwrite_off,
1612 queue->pwrite_buf,
1613 queue->pwrite_off));
1614 if (queue->rekey_left_bytes > queue->pwrite_off)
1615 queue->rekey_left_bytes -= queue->pwrite_off;
1616 else
1617 queue->rekey_left_bytes = 0;
1618 queue->cwrite_off += queue->pwrite_off;
1619 queue->pwrite_off = 0;
1620 }
1621 // if ((-1 != unverified_size)&& ((0 == queue->pwrite_off) &&
1622 if (((0 == queue->pwrite_off) &&
1623 ((0 == queue->rekey_left_bytes) ||
1624 (0 ==
1625 GNUNET_TIME_absolute_get_remaining (
1626 queue->rekey_time).rel_value_us))))
1627 {
1628 inject_rekey (queue);
1629 }
1630 if ((0 == queue->pwrite_off) && (! queue->finishing) &&
1631 (GNUNET_YES == queue->mq_awaits_continue))
1632 {
1633 queue->mq_awaits_continue = GNUNET_NO;
1634 GNUNET_MQ_impl_send_continue (queue->mq);
1635 }
1636 /* did we just finish writing 'finish'? */
1637 if ((0 == queue->cwrite_off) && (GNUNET_YES == queue->finishing))
1638 {
1639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1640 "Finishing queue\n");
1641 queue_destroy (queue);
1642 return;
1643 }
1644 /* do we care to write more? */
1645 if ((0 < queue->cwrite_off) || (0 < queue->pwrite_off))
1646 queue->write_task =
1647 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1648 queue->sock,
1649 &queue_write,
1650 queue);
1651}
1652
1653
1654/**
1655 * Test if we have received a full message in plaintext.
1656 * If so, handle it.
1657 *
1658 * @param queue queue to process inbound plaintext for
1659 * @return number of bytes of plaintext handled, 0 for none
1660 */
1661static size_t
1662try_handle_plaintext (struct Queue *queue)
1663{
1664 const struct GNUNET_MessageHeader *hdr =
1665 (const struct GNUNET_MessageHeader *) queue->pread_buf;
1666 const struct TCPConfirmationAck *tca = (const struct
1667 TCPConfirmationAck *) queue->pread_buf;
1668 const struct TCPBox *box = (const struct TCPBox *) queue->pread_buf;
1669 const struct TCPRekey *rekey = (const struct TCPRekey *) queue->pread_buf;
1670 const struct TCPFinish *fin = (const struct TCPFinish *) queue->pread_buf;
1671 struct TCPRekey rekeyz;
1672 struct TCPFinish finz;
1673 struct GNUNET_ShortHashCode tmac;
1674 uint16_t type;
1675 size_t size = 0; /* make compiler happy */
1676 struct TcpHandshakeAckSignature thas;
1677 const struct ChallengeNonceP challenge = queue->challenge;
1678
1679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1680 "try handle plaintext!\n");
1681
1682 if ((sizeof(*hdr) > queue->pread_off))
1683 {
1684 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1685 "Handling plaintext, not even a header!\n");
1686 return 0; /* not even a header */
1687 }
1688
1689 if ((-1 != unverified_size) && (unverified_size > INITIAL_CORE_KX_SIZE))
1690 {
1691 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1692 "Already received data of size %lu bigger than KX size %lu!\n",
1693 unverified_size,
1694 INITIAL_CORE_KX_SIZE);
1695 GNUNET_break_op (0);
1696 queue_finish (queue);
1697 return 0;
1698 }
1699
1700 type = ntohs (hdr->type);
1701 switch (type)
1702 {
1703 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK:
1704 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1705 "start processing ack\n");
1706 if (sizeof(*tca) > queue->pread_off)
1707 {
1708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1709 "Handling plaintext size of tca greater than pread offset.\n");
1710 return 0;
1711 }
1712 if (ntohs (hdr->size) != sizeof(*tca))
1713 {
1714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1715 "Handling plaintext size does not match message type.\n");
1716 GNUNET_break_op (0);
1717 queue_finish (queue);
1718 return 0;
1719 }
1720
1721 thas.purpose.purpose = htonl (
1722 GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE_ACK);
1723 thas.purpose.size = htonl (sizeof(thas));
1724 thas.sender = tca->sender;
1725 thas.receiver = my_identity;
1726 thas.monotonic_time = tca->monotonic_time;
1727 thas.challenge = tca->challenge;
1728
1729 if (GNUNET_SYSERR == GNUNET_CRYPTO_eddsa_verify (
1730 GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE_ACK,
1731 &thas,
1732 &tca->sender_sig,
1733 &tca->sender.public_key))
1734 {
1735 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1736 "Verification of signature failed!\n");
1737 GNUNET_break (0);
1738 queue_finish (queue);
1739 return 0;
1740 }
1741 if (0 != GNUNET_memcmp (&tca->challenge, &challenge))
1742 {
1743 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1744 "Challenge in TCPConfirmationAck not correct!\n");
1745 GNUNET_break (0);
1746 queue_finish (queue);
1747 return 0;
1748 }
1749
1750 queue->handshake_ack_monotime_get = GNUNET_PEERSTORE_iterate (peerstore,
1751 "transport_tcp_communicator",
1752 &queue->target,
1753 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK,
1754 &
1755 handshake_ack_monotime_cb,
1756 queue);
1757
1758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1759 "Handling plaintext, ack processed!\n");
1760
1761 if (GNUNET_TRANSPORT_CS_INBOUND == queue->cs)
1762 {
1763 send_challenge (queue->challenge_received, queue);
1764 queue->write_task =
1765 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1766 queue->sock,
1767 &queue_write,
1768 queue);
1769 }
1770
1771 unverified_size = -1;
1772
1773 char *foreign_addr;
1774
1775 switch (queue->address->sa_family)
1776 {
1777 case AF_INET:
1778 GNUNET_asprintf (&foreign_addr,
1779 "%s-%s",
1780 COMMUNICATOR_ADDRESS_PREFIX,
1781 GNUNET_a2s (queue->address, queue->address_len));
1782 break;
1783
1784 case AF_INET6:
1785 GNUNET_asprintf (&foreign_addr,
1786 "%s-%s",
1787 COMMUNICATOR_ADDRESS_PREFIX,
1788 GNUNET_a2s (queue->address, queue->address_len));
1789 break;
1790
1791 default:
1792 GNUNET_assert (0);
1793 }
1794
1795 queue->qh = GNUNET_TRANSPORT_communicator_mq_add (ch,
1796 &queue->target,
1797 foreign_addr,
1798 UINT32_MAX, /* no MTU */
1799 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
1800 0, /* Priority */
1801 queue->nt,
1802 queue->cs,
1803 queue->mq);
1804
1805 GNUNET_free (foreign_addr);
1806
1807 size = ntohs (hdr->size);
1808 break;
1809 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX:
1810 /* Special case: header size excludes box itself! */
1811 if (ntohs (hdr->size) + sizeof(struct TCPBox) > queue->pread_off)
1812 return 0;
1813 calculate_hmac (&queue->in_hmac, &box[1], ntohs (hdr->size), &tmac);
1814 if (0 != memcmp (&tmac, &box->hmac, sizeof(tmac)))
1815 {
1816 GNUNET_break_op (0);
1817 queue_finish (queue);
1818 return 0;
1819 }
1820 pass_plaintext_to_core (queue, (const void *) &box[1], ntohs (hdr->size));
1821 size = ntohs (hdr->size) + sizeof(*box);
1822 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1823 "Handling plaintext, box processed!\n");
1824 break;
1825
1826 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY:
1827 if (sizeof(*rekey) > queue->pread_off)
1828 return 0;
1829 if (ntohs (hdr->size) != sizeof(*rekey))
1830 {
1831 GNUNET_break_op (0);
1832 queue_finish (queue);
1833 return 0;
1834 }
1835 rekeyz = *rekey;
1836 memset (&rekeyz.hmac, 0, sizeof(rekeyz.hmac));
1837 calculate_hmac (&queue->in_hmac, &rekeyz, sizeof(rekeyz), &tmac);
1838 if (0 != memcmp (&tmac, &rekey->hmac, sizeof(tmac)))
1839 {
1840 GNUNET_break_op (0);
1841 queue_finish (queue);
1842 return 0;
1843 }
1844 do_rekey (queue, rekey);
1845 size = ntohs (hdr->size);
1846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1847 "Handling plaintext, rekey processed!\n");
1848 break;
1849
1850 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH:
1851 if (sizeof(*fin) > queue->pread_off)
1852 return 0;
1853 if (ntohs (hdr->size) != sizeof(*fin))
1854 {
1855 GNUNET_break_op (0);
1856 queue_finish (queue);
1857 return 0;
1858 }
1859 finz = *fin;
1860 memset (&finz.hmac, 0, sizeof(finz.hmac));
1861 calculate_hmac (&queue->in_hmac, &rekeyz, sizeof(rekeyz), &tmac);
1862 if (0 != memcmp (&tmac, &fin->hmac, sizeof(tmac)))
1863 {
1864 GNUNET_break_op (0);
1865 queue_finish (queue);
1866 return 0;
1867 }
1868 /* handle FINISH by destroying queue */
1869 queue_destroy (queue);
1870 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1871 "Handling plaintext, finish processed!\n");
1872 break;
1873
1874 default:
1875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1876 "Handling plaintext, nothing processed!\n");
1877 GNUNET_break_op (0);
1878 queue_finish (queue);
1879 return 0;
1880 }
1881 GNUNET_assert (0 != size);
1882 if (-1 != unverified_size)
1883 unverified_size += size;
1884 return size;
1885}
1886
1887
1888/**
1889 * Queue read task. If we hit the timeout, disconnect it
1890 *
1891 * @param cls the `struct Queue *` to disconnect
1892 */
1893static void
1894queue_read (void *cls)
1895{
1896 struct Queue *queue = cls;
1897 struct GNUNET_TIME_Relative left;
1898 ssize_t rcvd;
1899
1900 queue->read_task = NULL;
1901 rcvd = GNUNET_NETWORK_socket_recv (queue->sock,
1902 &queue->cread_buf[queue->cread_off],
1903 BUF_SIZE - queue->cread_off);
1904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1905 "Received %lu bytes from TCP queue\n", rcvd);
1906 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1907 "transport",
1908 "Received %lu bytes from TCP queue\n", rcvd);
1909 if (-1 == rcvd)
1910 {
1911 if ((EAGAIN != errno) && (EINTR != errno))
1912 {
1913 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
1914 queue_finish (queue);
1915 return;
1916 }
1917 /* try again */
1918 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
1919 queue->read_task =
1920 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read, queue);
1921 return;
1922 }
1923 if (0 != rcvd)
1924 reschedule_queue_timeout (queue);
1925 queue->cread_off += rcvd;
1926 while ((queue->pread_off < sizeof(queue->pread_buf)) &&
1927 (queue->cread_off > 0))
1928 {
1929 size_t max = GNUNET_MIN (sizeof(queue->pread_buf) - queue->pread_off,
1930 queue->cread_off);
1931 size_t done;
1932 size_t total;
1933 size_t old_pread_off = queue->pread_off;
1934
1935 GNUNET_assert (0 ==
1936 gcry_cipher_decrypt (queue->in_cipher,
1937 &queue->pread_buf[queue->pread_off],
1938 max,
1939 queue->cread_buf,
1940 max));
1941 queue->pread_off += max;
1942 total = 0;
1943 while (0 != (done = try_handle_plaintext (queue)))
1944 {
1945 /* 'done' bytes of plaintext were used, shift buffer */
1946 GNUNET_assert (done <= queue->pread_off);
1947 /* NOTE: this memmove() could possibly sometimes be
1948 avoided if we pass 'total' into try_handle_plaintext()
1949 and use it at an offset into the buffer there! */
1950 memmove (queue->pread_buf,
1951 &queue->pread_buf[done],
1952 queue->pread_off - done);
1953 queue->pread_off -= done;
1954 total += done;
1955 /* The last plaintext was a rekey, abort for now */
1956 if (GNUNET_YES == queue->rekeyed)
1957 break;
1958 }
1959 /* when we encounter a rekey message, the decryption above uses the
1960 wrong key for everything after the rekey; in that case, we have
1961 to re-do the decryption at 'total' instead of at 'max'.
1962 However, we have to take into account that the plaintext buffer may have
1963 already contained data and not jumped too far ahead in the ciphertext.
1964 If there is no rekey and the last message is incomplete (max > total),
1965 it is safe to keep the decryption so we shift by 'max' */
1966 if (GNUNET_YES == queue->rekeyed)
1967 {
1968 max = total - old_pread_off;
1969 queue->rekeyed = GNUNET_NO;
1970 queue->pread_off = 0;
1971 }
1972 memmove (queue->cread_buf, &queue->cread_buf[max], queue->cread_off - max);
1973 queue->cread_off -= max;
1974 }
1975 if (BUF_SIZE == queue->cread_off)
1976 return; /* buffer full, suspend reading */
1977 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
1978 if (0 != left.rel_value_us)
1979 {
1980 if (max_queue_length > queue->backpressure)
1981 {
1982 /* continue reading */
1983 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
1984 queue->read_task =
1985 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read, queue);
1986 }
1987 return;
1988 }
1989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1990 "Queue %p was idle for %s, disconnecting\n",
1991 queue,
1992 GNUNET_STRINGS_relative_time_to_string (
1993 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
1994 GNUNET_YES));
1995 queue_finish (queue);
1996}
1997
1998
1999/**
2000 * Convert a `struct sockaddr_in6 to a `struct sockaddr *`
2001 *
2002 * @param[out] sock_len set to the length of the address.
2003 * @param v6 The sockaddr_in6 to be converted.
2004 * @return The struct sockaddr *.
2005 */
2006static struct sockaddr *
2007tcp_address_to_sockaddr_numeric_v6 (socklen_t *sock_len, struct sockaddr_in6 v6,
2008 unsigned int port)
2009{
2010 struct sockaddr *in;
2011
2012 v6.sin6_family = AF_INET6;
2013 v6.sin6_port = htons ((uint16_t) port);
2014#if HAVE_SOCKADDR_IN_SIN_LEN
2015 v6.sin6_len = sizeof(sizeof(struct sockaddr_in6));
2016#endif
2017 v6.sin6_flowinfo = 0;
2018 v6.sin6_scope_id = 0;
2019 in = GNUNET_memdup (&v6, sizeof(v6));
2020 *sock_len = sizeof(struct sockaddr_in6);
2021
2022 return in;
2023}
2024
2025
2026/**
2027 * Convert a `struct sockaddr_in4 to a `struct sockaddr *`
2028 *
2029 * @param[out] sock_len set to the length of the address.
2030 * @param v4 The sockaddr_in4 to be converted.
2031 * @return The struct sockaddr *.
2032 */
2033static struct sockaddr *
2034tcp_address_to_sockaddr_numeric_v4 (socklen_t *sock_len, struct sockaddr_in v4,
2035 unsigned int port)
2036{
2037 struct sockaddr *in;
2038
2039 v4.sin_family = AF_INET;
2040 v4.sin_port = htons ((uint16_t) port);
2041#if HAVE_SOCKADDR_IN_SIN_LEN
2042 v4.sin_len = sizeof(struct sockaddr_in);
2043#endif
2044 in = GNUNET_memdup (&v4, sizeof(v4));
2045 *sock_len = sizeof(struct sockaddr_in);
2046 return in;
2047}
2048
2049
2050/**
2051 * Convert TCP bind specification to a `struct PortOnlyIpv4Ipv6 *`
2052 *
2053 * @param bindto bind specification to convert.
2054 * @return The converted bindto specification.
2055 */
2056static struct PortOnlyIpv4Ipv6 *
2057tcp_address_to_sockaddr_port_only (const char *bindto, unsigned int *port)
2058{
2059 struct PortOnlyIpv4Ipv6 *po;
2060 struct sockaddr_in *i4;
2061 struct sockaddr_in6 *i6;
2062 socklen_t sock_len_ipv4;
2063 socklen_t sock_len_ipv6;
2064
2065 /* interpreting value as just a PORT number */
2066 if (*port > UINT16_MAX)
2067 {
2068 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2069 "BINDTO specification `%s' invalid: value too large for port\n",
2070 bindto);
2071 return NULL;
2072 }
2073
2074 po = GNUNET_new (struct PortOnlyIpv4Ipv6);
2075
2076 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
2077 (GNUNET_YES ==
2078 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2079 COMMUNICATOR_CONFIG_SECTION,
2080 "DISABLE_V6")))
2081 {
2082 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2083 po->addr_ipv4 = tcp_address_to_sockaddr_numeric_v4 (&sock_len_ipv4, *i4,
2084 *port);
2085 po->addr_len_ipv4 = sock_len_ipv4;
2086 }
2087 else
2088 {
2089
2090 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2091 po->addr_ipv4 = tcp_address_to_sockaddr_numeric_v4 (&sock_len_ipv4, *i4,
2092 *port);
2093 po->addr_len_ipv4 = sock_len_ipv4;
2094
2095 i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
2096 po->addr_ipv6 = tcp_address_to_sockaddr_numeric_v6 (&sock_len_ipv6, *i6,
2097 *port);
2098
2099 po->addr_len_ipv6 = sock_len_ipv6;
2100
2101 GNUNET_free (i6);
2102 }
2103
2104 GNUNET_free (i4);
2105
2106 return po;
2107}
2108
2109
2110/**
2111 * This Method extracts the address part of the BINDTO string.
2112 *
2113 * @param bindto String we extract the address part from.
2114 * @return The extracted address string.
2115 */
2116static char *
2117extract_address (const char *bindto)
2118{
2119
2120 char *start;
2121 char *token;
2122 char *cp;
2123 char *rest = NULL;
2124 char *res;
2125
2126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2127 "extract address with bindto %s\n",
2128 bindto);
2129
2130 if (NULL == bindto)
2131 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2132 "bindto is NULL\n");
2133
2134 cp = GNUNET_strdup (bindto);
2135
2136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2137 "extract address 2\n");
2138
2139 start = cp;
2140 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
2141 {
2142 start++; /* skip over '['*/
2143 cp[strlen (cp) - 1] = '\0'; /* eat ']'*/
2144 }
2145 else
2146 {
2147 token = strtok_r (cp, "]", &rest);
2148 if (strlen (bindto) == strlen (token))
2149 {
2150 token = strtok_r (cp, ":", &rest);
2151 }
2152 else
2153 {
2154 token++;
2155 res = GNUNET_strdup (token);
2156 GNUNET_free (cp);
2157 return res;
2158 }
2159 }
2160
2161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2162 "extract address 3\n");
2163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2164 "extract address with start %s\n",
2165 start);
2166
2167 return GNUNET_strdup (start);
2168}
2169
2170
2171/**
2172 * This Method extracts the port part of the BINDTO string.
2173 *
2174 * @param addr_and_port String we extract the port from.
2175 * @return The extracted port as unsigned int.
2176 */
2177static unsigned int
2178extract_port (const char *addr_and_port)
2179{
2180 unsigned int port;
2181 char dummy[2];
2182 char *token;
2183 char *addr;
2184 char *colon;
2185 char *cp;
2186 char *rest = NULL;
2187
2188 if (NULL != addr_and_port)
2189 {
2190 cp = GNUNET_strdup (addr_and_port);
2191 token = strtok_r (cp, "]", &rest);
2192 if (strlen (addr_and_port) == strlen (token))
2193 {
2194 colon = strrchr (cp, ':');
2195 if (NULL == colon)
2196 {
2197 GNUNET_free (cp);
2198 return 0;
2199 }
2200 addr = colon;
2201 addr++;
2202 }
2203 else
2204 {
2205 token = strtok_r (NULL, "]", &rest);
2206 if (NULL == token)
2207 {
2208 GNUNET_free (cp);
2209 return 0;
2210 }
2211 else
2212 {
2213 addr = token;
2214 addr++;
2215 }
2216 }
2217
2218
2219 if (1 == sscanf (addr, "%u%1s", &port, dummy))
2220 {
2221 /* interpreting value as just a PORT number */
2222 if (port > UINT16_MAX)
2223 {
2224 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2225 "Port `%u' invalid: value too large for port\n",
2226 port);
2227 GNUNET_free (cp);
2228 return 0;
2229 }
2230 }
2231 else
2232 {
2233 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2234 "BINDTO specification invalid: last ':' not followed by number\n");
2235 GNUNET_free (cp);
2236 return 0;
2237 }
2238 }
2239 else
2240 {
2241 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2242 "return 0\n");
2243 /* interpret missing port as 0, aka pick any free one */
2244 port = 0;
2245 }
2246
2247
2248 return port;
2249}
2250
2251
2252/**
2253 * Convert TCP bind specification to a `struct sockaddr *`
2254 *
2255 * @param bindto bind specification to convert
2256 * @param[out] sock_len set to the length of the address
2257 * @return converted bindto specification
2258 */
2259static struct sockaddr *
2260tcp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
2261{
2262 struct sockaddr *in;
2263 unsigned int port;
2264 struct sockaddr_in v4;
2265 struct sockaddr_in6 v6;
2266 char *start;
2267
2268 // cp = GNUNET_strdup (bindto);
2269 start = extract_address (bindto);
2270
2271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2272 "start %s\n",
2273 start);
2274
2275 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2276 "!bindto %s\n",
2277 bindto);
2278
2279
2280 if (1 == inet_pton (AF_INET, start, &v4.sin_addr))
2281 {
2282 // colon = strrchr (cp, ':');
2283 port = extract_port (bindto);
2284
2285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2286 "port %u\n",
2287 port);
2288
2289 in = tcp_address_to_sockaddr_numeric_v4 (sock_len, v4, port);
2290 }
2291 else if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
2292 {
2293 // colon = strrchr (cp, ':');
2294 port = extract_port (bindto);
2295 in = tcp_address_to_sockaddr_numeric_v6 (sock_len, v6, port);
2296 }
2297 else
2298 {
2299 GNUNET_assert (0);
2300 }
2301
2302 GNUNET_free (start);
2303 return in;
2304}
2305
2306
2307/**
2308 * Signature of functions implementing the sending functionality of a
2309 * message queue.
2310 *
2311 * @param mq the message queue
2312 * @param msg the message to send
2313 * @param impl_state our `struct Queue`
2314 */
2315static void
2316mq_send (struct GNUNET_MQ_Handle *mq,
2317 const struct GNUNET_MessageHeader *msg,
2318 void *impl_state)
2319{
2320 struct Queue *queue = impl_state;
2321 uint16_t msize = ntohs (msg->size);
2322 struct TCPBox box;
2323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2324 "In MQ send. Queue finishing: %s; write task running: %s\n",
2325 (GNUNET_YES == queue->finishing) ? "yes" : "no",
2326 (NULL == queue->write_task) ? "yes" : "no");
2327 GNUNET_assert (mq == queue->mq);
2328 queue->mq_awaits_continue = GNUNET_YES;
2329 if (GNUNET_YES == queue->finishing)
2330 return; /* this queue is dying, drop msg */
2331 GNUNET_assert (0 == queue->pwrite_off);
2332 box.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX);
2333 box.header.size = htons (msize);
2334 calculate_hmac (&queue->out_hmac, msg, msize, &box.hmac);
2335 memcpy (&queue->pwrite_buf[queue->pwrite_off], &box, sizeof(box));
2336 queue->pwrite_off += sizeof(box);
2337 memcpy (&queue->pwrite_buf[queue->pwrite_off], msg, msize);
2338 queue->pwrite_off += msize;
2339 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2340 "%lu bytes of plaintext to send\n", queue->pwrite_off);
2341 GNUNET_assert (NULL != queue->sock);
2342 if (NULL == queue->write_task)
2343 queue->write_task =
2344 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2345 queue->sock,
2346 &queue_write,
2347 queue);
2348}
2349
2350
2351/**
2352 * Signature of functions implementing the destruction of a message
2353 * queue. Implementations must not free @a mq, but should take care
2354 * of @a impl_state.
2355 *
2356 * @param mq the message queue to destroy
2357 * @param impl_state our `struct Queue`
2358 */
2359static void
2360mq_destroy (struct GNUNET_MQ_Handle *mq, void *impl_state)
2361{
2362 struct Queue *queue = impl_state;
2363
2364 if (mq == queue->mq)
2365 {
2366 queue->mq = NULL;
2367 queue_finish (queue);
2368 }
2369}
2370
2371
2372/**
2373 * Implementation function that cancels the currently sent message.
2374 *
2375 * @param mq message queue
2376 * @param impl_state our `struct Queue`
2377 */
2378static void
2379mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
2380{
2381 struct Queue *queue = impl_state;
2382
2383 GNUNET_assert (0 != queue->pwrite_off);
2384 queue->pwrite_off = 0;
2385}
2386
2387
2388/**
2389 * Generic error handler, called with the appropriate
2390 * error code and the same closure specified at the creation of
2391 * the message queue.
2392 * Not every message queue implementation supports an error handler.
2393 *
2394 * @param cls our `struct Queue`
2395 * @param error error code
2396 */
2397static void
2398mq_error (void *cls, enum GNUNET_MQ_Error error)
2399{
2400 struct Queue *queue = cls;
2401
2402 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2403 "MQ error in queue to %s: %d\n",
2404 GNUNET_i2s (&queue->target),
2405 (int) error);
2406 queue_finish (queue);
2407}
2408
2409
2410/**
2411 * Add the given @a queue to our internal data structure. Setup the
2412 * MQ processing and inform transport that the queue is ready. Must
2413 * be called after the KX for outgoing messages has been bootstrapped.
2414 *
2415 * @param queue queue to boot
2416 */
2417static void
2418boot_queue (struct Queue *queue)
2419{
2420 queue->nt =
2421 GNUNET_NT_scanner_get_type (is, queue->address, queue->address_len);
2422 (void) GNUNET_CONTAINER_multipeermap_put (
2423 queue_map,
2424 &queue->target,
2425 queue,
2426 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2427 GNUNET_STATISTICS_set (stats,
2428 "# queues active",
2429 GNUNET_CONTAINER_multipeermap_size (queue_map),
2430 GNUNET_NO);
2431 queue->timeout =
2432 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2433 queue->mq = GNUNET_MQ_queue_for_callbacks (&mq_send,
2434 &mq_destroy,
2435 &mq_cancel,
2436 queue,
2437 NULL,
2438 &mq_error,
2439 queue);
2440}
2441
2442
2443/**
2444 * Generate and transmit our ephemeral key and the signature for
2445 * the initial KX with the other peer. Must be called first, before
2446 * any other bytes are ever written to the output buffer. Note that
2447 * our cipher must already be initialized when calling this function.
2448 * Helper function for #start_initial_kx_out().
2449 *
2450 * @param queue queue to do KX for
2451 * @param epub our public key for the KX
2452 */
2453static void
2454transmit_kx (struct Queue *queue,
2455 const struct GNUNET_CRYPTO_EcdhePublicKey *epub)
2456{
2457 struct TcpHandshakeSignature ths;
2458 struct TCPConfirmation tc;
2459
2460 memcpy (queue->cwrite_buf, epub, sizeof(*epub));
2461 queue->cwrite_off = sizeof(*epub);
2462 /* compute 'tc' and append in encrypted format to cwrite_buf */
2463 tc.sender = my_identity;
2464 tc.monotonic_time =
2465 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
2466 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
2467 &tc.challenge,
2468 sizeof(tc.challenge));
2469 ths.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE);
2470 ths.purpose.size = htonl (sizeof(ths));
2471 ths.sender = my_identity;
2472 ths.receiver = queue->target;
2473 ths.ephemeral = *epub;
2474 ths.monotonic_time = tc.monotonic_time;
2475 ths.challenge = tc.challenge;
2476 GNUNET_CRYPTO_eddsa_sign (my_private_key,
2477 &ths,
2478 &tc.sender_sig);
2479 GNUNET_assert (0 ==
2480 gcry_cipher_encrypt (queue->out_cipher,
2481 &queue->cwrite_buf[queue->cwrite_off],
2482 sizeof(tc),
2483 &tc,
2484 sizeof(tc)));
2485 queue->challenge = tc.challenge;
2486 queue->cwrite_off += sizeof(tc);
2487
2488 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2489 "transport",
2490 "handshake written\n");
2491}
2492
2493
2494/**
2495 * Initialize our key material for outgoing transmissions and
2496 * inform the other peer about it. Must be called first before
2497 * any data is sent.
2498 *
2499 * @param queue the queue to setup
2500 */
2501static void
2502start_initial_kx_out (struct Queue *queue)
2503{
2504 struct GNUNET_CRYPTO_EcdhePublicKey epub;
2505
2506 GNUNET_CRYPTO_ecdhe_key_create (&queue->ephemeral);
2507 GNUNET_CRYPTO_ecdhe_key_get_public (&queue->ephemeral, &epub);
2508 setup_out_cipher (queue);
2509 transmit_kx (queue, &epub);
2510}
2511
2512
2513/**
2514 * Callback called when peerstore store operation for handshake monotime is finished.
2515 * @param cls Queue context the store operation was executed.
2516 * @param success Store operation was successful (GNUNET_OK) or not.
2517 */
2518static void
2519handshake_monotime_store_cb (void *cls, int success)
2520{
2521 struct Queue *queue = cls;
2522 if (GNUNET_OK != success)
2523 {
2524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2525 "Failed to store handshake monotonic time in PEERSTORE!\n");
2526 }
2527 queue->handshake_monotime_sc = NULL;
2528}
2529
2530
2531/**
2532 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE
2533 * where found.
2534 * @param cls Queue context the store operation was executed.
2535 * @param record The record found or NULL if there is no record left.
2536 * @param emsg Message from peerstore.
2537 */
2538static void
2539handshake_monotime_cb (void *cls,
2540 const struct GNUNET_PEERSTORE_Record *record,
2541 const char *emsg)
2542{
2543 struct Queue *queue = cls;
2544 struct GNUNET_TIME_AbsoluteNBO *mtbe;
2545 struct GNUNET_TIME_Absolute mt;
2546 const struct GNUNET_PeerIdentity *pid;
2547 struct GNUNET_TIME_AbsoluteNBO *handshake_monotonic_time;
2548
2549 (void) emsg;
2550
2551 handshake_monotonic_time = &queue->handshake_monotonic_time;
2552 pid = &queue->target;
2553 if (NULL == record)
2554 {
2555 queue->handshake_monotime_get = NULL;
2556 return;
2557 }
2558 if (sizeof(*mtbe) != record->value_size)
2559 {
2560 GNUNET_break (0);
2561 return;
2562 }
2563 mtbe = record->value;
2564 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
2565 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
2566 queue->handshake_monotonic_time).abs_value_us)
2567 {
2568 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2569 "Queue from %s dropped, handshake monotime in the past\n",
2570 GNUNET_i2s (&queue->target));
2571 GNUNET_break (0);
2572 queue_finish (queue);
2573 return;
2574 }
2575 queue->handshake_monotime_sc = GNUNET_PEERSTORE_store (peerstore,
2576 "transport_tcp_communicator",
2577 pid,
2578 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE,
2579 handshake_monotonic_time,
2580 sizeof(*
2581 handshake_monotonic_time),
2582 GNUNET_TIME_UNIT_FOREVER_ABS,
2583 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
2584 &
2585 handshake_monotime_store_cb,
2586 queue);
2587}
2588
2589
2590/**
2591 * We have received the first bytes from the other side on a @a queue.
2592 * Decrypt the @a tc contained in @a ibuf and check the signature.
2593 * Note that #setup_in_cipher() must have already been called.
2594 *
2595 * @param queue queue to decrypt initial bytes from other peer for
2596 * @param tc[out] where to store the result
2597 * @param ibuf incoming data, of size
2598 * `INITIAL_KX_SIZE`
2599 * @return #GNUNET_OK if the signature was OK, #GNUNET_SYSERR if not
2600 */
2601static int
2602decrypt_and_check_tc (struct Queue *queue,
2603 struct TCPConfirmation *tc,
2604 char *ibuf)
2605{
2606 struct TcpHandshakeSignature ths;
2607
2608 GNUNET_assert (
2609 0 ==
2610 gcry_cipher_decrypt (queue->in_cipher,
2611 tc,
2612 sizeof(*tc),
2613 &ibuf[sizeof(struct GNUNET_CRYPTO_EcdhePublicKey)],
2614 sizeof(*tc)));
2615 ths.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE);
2616 ths.purpose.size = htonl (sizeof(ths));
2617 ths.sender = tc->sender;
2618 ths.receiver = my_identity;
2619 memcpy (&ths.ephemeral, ibuf, sizeof(struct GNUNET_CRYPTO_EcdhePublicKey));
2620 ths.monotonic_time = tc->monotonic_time;
2621 ths.challenge = tc->challenge;
2622 queue->handshake_monotime_get =
2623 GNUNET_PEERSTORE_iterate (peerstore,
2624 "transport_tcp_communicator",
2625 &queue->target,
2626 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE,
2627 &handshake_monotime_cb,
2628 queue);
2629 return GNUNET_CRYPTO_eddsa_verify (
2630 GNUNET_SIGNATURE_COMMUNICATOR_TCP_HANDSHAKE,
2631 &ths,
2632 &tc->sender_sig,
2633 &tc->sender.public_key);
2634}
2635
2636
2637/**
2638 * Closes socket and frees memory associated with @a pq.
2639 *
2640 * @param pq proto queue to free
2641 */
2642static void
2643free_proto_queue (struct ProtoQueue *pq)
2644{
2645 if (NULL != pq->listen_sock)
2646 {
2647 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pq->listen_sock));
2648 pq->listen_sock = NULL;
2649 }
2650 GNUNET_NETWORK_socket_close (pq->sock);
2651 GNUNET_free (pq->address);
2652 GNUNET_CONTAINER_DLL_remove (proto_head, proto_tail, pq);
2653 GNUNET_free (pq);
2654}
2655
2656
2657/**
2658 * Read from the socket of the proto queue until we have enough data
2659 * to upgrade to full queue.
2660 *
2661 * @param cls a `struct ProtoQueue`
2662 */
2663static void
2664proto_read_kx (void *cls)
2665{
2666 struct ProtoQueue *pq = cls;
2667 ssize_t rcvd;
2668 struct GNUNET_TIME_Relative left;
2669 struct Queue *queue;
2670 struct TCPConfirmation tc;
2671
2672 pq->read_task = NULL;
2673 left = GNUNET_TIME_absolute_get_remaining (pq->timeout);
2674 if (0 == left.rel_value_us)
2675 {
2676 free_proto_queue (pq);
2677 return;
2678 }
2679 rcvd = GNUNET_NETWORK_socket_recv (pq->sock,
2680 &pq->ibuf[pq->ibuf_off],
2681 sizeof(pq->ibuf) - pq->ibuf_off);
2682 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2683 "Received %lu bytes for KX\n", rcvd);
2684 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2685 "transport",
2686 "Received %lu bytes for KX\n", rcvd);
2687 if (-1 == rcvd)
2688 {
2689 if ((EAGAIN != errno) && (EINTR != errno))
2690 {
2691 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2692 free_proto_queue (pq);
2693 return;
2694 }
2695 /* try again */
2696 pq->read_task =
2697 GNUNET_SCHEDULER_add_read_net (left, pq->sock, &proto_read_kx, pq);
2698 return;
2699 }
2700 pq->ibuf_off += rcvd;
2701 if (pq->ibuf_off > sizeof(pq->ibuf))
2702 {
2703 /* read more */
2704 pq->read_task =
2705 GNUNET_SCHEDULER_add_read_net (left, pq->sock, &proto_read_kx, pq);
2706 return;
2707 }
2708 /* we got all the data, let's find out who we are talking to! */
2709 queue = GNUNET_new (struct Queue);
2710 setup_in_cipher ((const struct GNUNET_CRYPTO_EcdhePublicKey *) pq->ibuf,
2711 queue);
2712 if (GNUNET_OK != decrypt_and_check_tc (queue, &tc, pq->ibuf))
2713 {
2714 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2715 "Invalid TCP KX received from %s\n",
2716 GNUNET_a2s (pq->address, pq->address_len));
2717 gcry_cipher_close (queue->in_cipher);
2718 GNUNET_free (queue);
2719 free_proto_queue (pq);
2720 return;
2721 }
2722 queue->address = pq->address; /* steals reference */
2723 queue->address_len = pq->address_len;
2724 queue->target = tc.sender;
2725 queue->listen_sock = pq->listen_sock;
2726 queue->sock = pq->sock;
2727
2728
2729 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2730 "start kx proto\n");
2731
2732 start_initial_kx_out (queue);
2733 queue->cs = GNUNET_TRANSPORT_CS_INBOUND;
2734 boot_queue (queue);
2735 queue->read_task =
2736 GNUNET_SCHEDULER_add_read_net (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2737 queue->sock,
2738 &queue_read,
2739 queue);
2740 queue->write_task =
2741 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2742 queue->sock,
2743 &queue_write,
2744 queue);
2745 // TODO To early! Move it somewhere else.
2746 // send_challenge (tc.challenge, queue);
2747 queue->challenge_received = tc.challenge;
2748
2749 GNUNET_CONTAINER_DLL_remove (proto_head, proto_tail, pq);
2750 GNUNET_free (pq);
2751}
2752
2753
2754/**
2755 * We have been notified that our listen socket has something to
2756 * read. Do the read and reschedule this function to be called again
2757 * once more is available.
2758 *
2759 * @param cls ListenTask with listening socket and task
2760 */
2761static void
2762listen_cb (void *cls)
2763{
2764 struct sockaddr_storage in;
2765 socklen_t addrlen;
2766 struct GNUNET_NETWORK_Handle *sock;
2767 struct ProtoQueue *pq;
2768 struct ListenTask *lt;
2769
2770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2771 "listen_cb\n");
2772
2773 lt = cls;
2774
2775 lt->listen_task = NULL;
2776 GNUNET_assert (NULL != lt->listen_sock);
2777 addrlen = sizeof(in);
2778 memset (&in, 0, sizeof(in));
2779 sock = GNUNET_NETWORK_socket_accept (lt->listen_sock,
2780 (struct sockaddr*) &in,
2781 &addrlen);
2782 if ((NULL == sock) && ((EMFILE == errno) || (ENFILE == errno)))
2783 return; /* system limit reached, wait until connection goes down */
2784 lt->listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2785 lt->listen_sock,
2786 &listen_cb,
2787 lt);
2788 if ((NULL == sock) && ((EAGAIN == errno) || (ENOBUFS == errno)))
2789 return;
2790 if (NULL == sock)
2791 {
2792 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "accept");
2793 return;
2794 }
2795 pq = GNUNET_new (struct ProtoQueue);
2796 pq->address_len = addrlen;
2797 pq->address = GNUNET_memdup (&in, addrlen);
2798 pq->timeout = GNUNET_TIME_relative_to_absolute (PROTO_QUEUE_TIMEOUT);
2799 pq->sock = sock;
2800 pq->read_task = GNUNET_SCHEDULER_add_read_net (PROTO_QUEUE_TIMEOUT,
2801 pq->sock,
2802 &proto_read_kx,
2803 pq);
2804 GNUNET_CONTAINER_DLL_insert (proto_head, proto_tail, pq);
2805}
2806
2807
2808/**
2809 * Read from the socket of the queue until we have enough data
2810 * to initialize the decryption logic and can switch to regular
2811 * reading.
2812 *
2813 * @param cls a `struct Queue`
2814 */
2815static void
2816queue_read_kx (void *cls)
2817{
2818 struct Queue *queue = cls;
2819 ssize_t rcvd;
2820 struct GNUNET_TIME_Relative left;
2821 struct TCPConfirmation tc;
2822
2823 queue->read_task = NULL;
2824 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
2825 if (0 == left.rel_value_us)
2826 {
2827 queue_destroy (queue);
2828 return;
2829 }
2830 rcvd = GNUNET_NETWORK_socket_recv (queue->sock,
2831 &queue->cread_buf[queue->cread_off],
2832 BUF_SIZE - queue->cread_off);
2833 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2834 "Received %lu bytes for KX\n",
2835 rcvd);
2836 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2837 "transport",
2838 "Received %lu bytes for KX\n",
2839 rcvd);
2840 if (-1 == rcvd)
2841 {
2842 if ((EAGAIN != errno) && (EINTR != errno))
2843 {
2844 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2845 queue_destroy (queue);
2846 return;
2847 }
2848 queue->read_task =
2849 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read_kx, queue);
2850 return;
2851 }
2852 queue->cread_off += rcvd;
2853 if (queue->cread_off < INITIAL_KX_SIZE)
2854 {
2855 /* read more */
2856 queue->read_task =
2857 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read_kx, queue);
2858 return;
2859 }
2860 /* we got all the data, let's find out who we are talking to! */
2861 setup_in_cipher ((const struct GNUNET_CRYPTO_EcdhePublicKey *)
2862 queue->cread_buf,
2863 queue);
2864 if (GNUNET_OK != decrypt_and_check_tc (queue, &tc, queue->cread_buf))
2865 {
2866 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2867 "Invalid TCP KX received from %s\n",
2868 GNUNET_a2s (queue->address, queue->address_len));
2869 queue_destroy (queue);
2870 return;
2871 }
2872 if (0 !=
2873 memcmp (&tc.sender, &queue->target, sizeof(struct GNUNET_PeerIdentity)))
2874 {
2875 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2876 "Invalid sender in TCP KX received from %s\n",
2877 GNUNET_a2s (queue->address, queue->address_len));
2878 queue_destroy (queue);
2879 return;
2880 }
2881 send_challenge (tc.challenge, queue);
2882 queue->write_task =
2883 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2884 queue->sock,
2885 &queue_write,
2886 queue);
2887
2888 /* update queue timeout */
2889 reschedule_queue_timeout (queue);
2890 /* prepare to continue with regular read task immediately */
2891 memmove (queue->cread_buf,
2892 &queue->cread_buf[INITIAL_KX_SIZE],
2893 queue->cread_off - (INITIAL_KX_SIZE));
2894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2895 "cread_off is %lu bytes before adjusting\n",
2896 queue->cread_off);
2897 queue->cread_off -= INITIAL_KX_SIZE;
2898 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2899 "cread_off set to %lu bytes\n",
2900 queue->cread_off);
2901 queue->read_task = GNUNET_SCHEDULER_add_now (&queue_read, queue);
2902}
2903
2904
2905/**
2906 * Function called by the transport service to initialize a
2907 * message queue given address information about another peer.
2908 * If and when the communication channel is established, the
2909 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
2910 * to notify the service that the channel is now up. It is
2911 * the responsibility of the communicator to manage sane
2912 * retries and timeouts for any @a peer/@a address combination
2913 * provided by the transport service. Timeouts and retries
2914 * do not need to be signalled to the transport service.
2915 *
2916 * @param cls closure
2917 * @param peer identity of the other peer
2918 * @param address where to send the message, human-readable
2919 * communicator-specific format, 0-terminated, UTF-8
2920 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is
2921 * invalid
2922 */
2923static int
2924mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
2925{
2926 struct Queue *queue;
2927 const char *path;
2928 struct sockaddr *in;
2929 socklen_t in_len = 0;
2930 struct GNUNET_NETWORK_Handle *sock;
2931
2932 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2933 "Connecting to %s\n", address);
2934 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2935 "transport",
2936 "Connecting to %s\n", address);
2937 if (0 != strncmp (address,
2938 COMMUNICATOR_ADDRESS_PREFIX "-",
2939 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
2940 {
2941 GNUNET_break_op (0);
2942 return GNUNET_SYSERR;
2943 }
2944 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
2945 in = tcp_address_to_sockaddr (path, &in_len);
2946
2947 if (NULL == in)
2948 {
2949 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2950 "Failed to setup TCP socket address\n");
2951 return GNUNET_SYSERR;
2952 }
2953
2954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2955 "in %s\n",
2956 GNUNET_a2s (in, in_len));
2957
2958 sock = GNUNET_NETWORK_socket_create (in->sa_family, SOCK_STREAM, IPPROTO_TCP);
2959 if (NULL == sock)
2960 {
2961 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2962 "socket(%d) failed: %s",
2963 in->sa_family,
2964 strerror (errno));
2965 GNUNET_free (in);
2966 return GNUNET_SYSERR;
2967 }
2968 if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (sock, in, in_len)) &&
2969 (errno != EINPROGRESS))
2970 {
2971 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2972 "connect to `%s' failed: %s",
2973 address,
2974 strerror (errno));
2975 GNUNET_NETWORK_socket_close (sock);
2976 GNUNET_free (in);
2977 return GNUNET_SYSERR;
2978 }
2979
2980 queue = GNUNET_new (struct Queue);
2981 queue->target = *peer;
2982 queue->address = in;
2983 queue->address_len = in_len;
2984 queue->sock = sock;
2985 queue->cs = GNUNET_TRANSPORT_CS_OUTBOUND;
2986 boot_queue (queue);
2987 // queue->mq_awaits_continue = GNUNET_YES;
2988 queue->read_task =
2989 GNUNET_SCHEDULER_add_read_net (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2990 queue->sock,
2991 &queue_read_kx,
2992 queue);
2993
2994
2995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2996 "start kx mq_init\n");
2997
2998 start_initial_kx_out (queue);
2999 queue->write_task =
3000 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3001 queue->sock,
3002 &queue_write,
3003 queue);
3004 return GNUNET_OK;
3005}
3006
3007
3008/**
3009 * Iterator over all ListenTasks to clean up.
3010 *
3011 * @param cls NULL
3012 * @param key unused
3013 * @param value the ListenTask to cancel.
3014 * @return #GNUNET_OK to continue to iterate
3015 */
3016static int
3017get_lt_delete_it (void *cls,
3018 const struct GNUNET_HashCode *key,
3019 void *value)
3020{
3021 struct ListenTask *lt = value;
3022
3023 (void) cls;
3024 (void) key;
3025 if (NULL != lt->listen_task)
3026 {
3027 GNUNET_SCHEDULER_cancel (lt->listen_task);
3028 lt->listen_task = NULL;
3029 }
3030 if (NULL != lt->listen_sock)
3031 {
3032 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (lt->listen_sock));
3033 lt->listen_sock = NULL;
3034 }
3035 return GNUNET_OK;
3036}
3037
3038
3039/**
3040 * Iterator over all message queues to clean up.
3041 *
3042 * @param cls NULL
3043 * @param target unused
3044 * @param value the queue to destroy
3045 * @return #GNUNET_OK to continue to iterate
3046 */
3047static int
3048get_queue_delete_it (void *cls,
3049 const struct GNUNET_PeerIdentity *target,
3050 void *value)
3051{
3052 struct Queue *queue = value;
3053
3054 (void) cls;
3055 (void) target;
3056 queue_destroy (queue);
3057 return GNUNET_OK;
3058}
3059
3060
3061/**
3062 * Shutdown the UNIX communicator.
3063 *
3064 * @param cls NULL (always)
3065 */
3066static void
3067do_shutdown (void *cls)
3068{
3069 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3070 "Shutdown %s!\n",
3071 shutdown_running ? "running" : "not running");
3072
3073 if (GNUNET_YES == shutdown_running)
3074 return;
3075 else
3076 shutdown_running = GNUNET_YES;
3077
3078 while (NULL != proto_head)
3079 free_proto_queue (proto_head);
3080 if (NULL != nat)
3081 {
3082 GNUNET_NAT_unregister (nat);
3083 nat = NULL;
3084 }
3085 GNUNET_CONTAINER_multihashmap_iterate (lt_map, &get_lt_delete_it, NULL);
3086 GNUNET_CONTAINER_multipeermap_iterate (queue_map, &get_queue_delete_it, NULL);
3087 GNUNET_CONTAINER_multipeermap_destroy (queue_map);
3088 if (NULL != ch)
3089 {
3090 GNUNET_TRANSPORT_communicator_address_remove_all (ch);
3091 GNUNET_TRANSPORT_communicator_disconnect (ch);
3092 ch = NULL;
3093 }
3094 if (NULL != stats)
3095 {
3096 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3097 stats = NULL;
3098 }
3099 if (NULL != my_private_key)
3100 {
3101 GNUNET_free (my_private_key);
3102 my_private_key = NULL;
3103 }
3104 if (NULL != is)
3105 {
3106 GNUNET_NT_scanner_done (is);
3107 is = NULL;
3108 }
3109 if (NULL != peerstore)
3110 {
3111 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
3112 peerstore = NULL;
3113 }
3114 if (NULL != resolve_request_handle)
3115 {
3116 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3117 resolve_request_handle = NULL;
3118 }
3119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3120 "Shutdown done!\n");
3121}
3122
3123
3124/**
3125 * Function called when the transport service has received an
3126 * acknowledgement for this communicator (!) via a different return
3127 * path.
3128 *
3129 * Not applicable for TCP.
3130 *
3131 * @param cls closure
3132 * @param sender which peer sent the notification
3133 * @param msg payload
3134 */
3135static void
3136enc_notify_cb (void *cls,
3137 const struct GNUNET_PeerIdentity *sender,
3138 const struct GNUNET_MessageHeader *msg)
3139{
3140 (void) cls;
3141 (void) sender;
3142 (void) msg;
3143 GNUNET_break_op (0);
3144}
3145
3146
3147/**
3148 * Signature of the callback passed to #GNUNET_NAT_register() for
3149 * a function to call whenever our set of 'valid' addresses changes.
3150 *
3151 * @param cls closure
3152 * @param app_ctx[in,out] location where the app can store stuff
3153 * on add and retrieve it on remove
3154 * @param add_remove #GNUNET_YES to add a new public IP address,
3155 * #GNUNET_NO to remove a previous (now invalid) one
3156 * @param ac address class the address belongs to
3157 * @param addr either the previous or the new public IP address
3158 * @param addrlen actual length of the @a addr
3159 */
3160static void
3161nat_address_cb (void *cls,
3162 void **app_ctx,
3163 int add_remove,
3164 enum GNUNET_NAT_AddressClass ac,
3165 const struct sockaddr *addr,
3166 socklen_t addrlen)
3167{
3168 char *my_addr;
3169 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
3170
3171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3172 "nat address cb %s %s\n",
3173 add_remove ? "add" : "remove",
3174 GNUNET_a2s (addr, addrlen));
3175
3176 if (GNUNET_YES == add_remove)
3177 {
3178 enum GNUNET_NetworkType nt;
3179
3180 GNUNET_asprintf (&my_addr,
3181 "%s-%s",
3182 COMMUNICATOR_ADDRESS_PREFIX,
3183 GNUNET_a2s (addr, addrlen));
3184 nt = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3185 ai =
3186 GNUNET_TRANSPORT_communicator_address_add (ch,
3187 my_addr,
3188 nt,
3189 GNUNET_TIME_UNIT_FOREVER_REL);
3190 GNUNET_free (my_addr);
3191 *app_ctx = ai;
3192 }
3193 else
3194 {
3195 ai = *app_ctx;
3196 GNUNET_TRANSPORT_communicator_address_remove (ai);
3197 *app_ctx = NULL;
3198 }
3199}
3200
3201
3202/**
3203 * This method adds addresses to the DLL, that are later register at the NAT service.
3204 */
3205static void
3206add_addr (struct sockaddr *in, socklen_t in_len)
3207{
3208
3209 struct Addresses *saddrs;
3210
3211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3212 "add address %s\n",
3213 GNUNET_a2s (in, in_len));
3214
3215 saddrs = GNUNET_new (struct Addresses);
3216 saddrs->addr = in;
3217 saddrs->addr_len = in_len;
3218 GNUNET_CONTAINER_DLL_insert (addrs_head, addrs_tail, saddrs);
3219
3220 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3221 "after add address %s\n",
3222 GNUNET_a2s (in, in_len));
3223
3224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3225 "add address %s\n",
3226 GNUNET_a2s (saddrs->addr, saddrs->addr_len));
3227
3228 addrs_lens++;
3229}
3230
3231
3232/**
3233 * This method launch network interactions for each address we like to bind to.
3234 *
3235 * @param addr The address we will listen to.
3236 * @param in_len The length of the address we will listen to.
3237 * @return GNUNET_SYSERR in case of error. GNUNET_OK in case we are successfully listen to the address.
3238 */
3239static int
3240init_socket (struct sockaddr *addr,
3241 socklen_t in_len)
3242{
3243 struct sockaddr_storage in_sto;
3244 socklen_t sto_len;
3245 struct GNUNET_NETWORK_Handle *listen_sock;
3246 struct ListenTask *lt;
3247 int sockfd;
3248 struct GNUNET_HashCode h_sock;
3249
3250 if (NULL == addr)
3251 {
3252 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3253 "Address is NULL.\n");
3254 return GNUNET_SYSERR;
3255 }
3256
3257 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3258 "address %s\n",
3259 GNUNET_a2s (addr, in_len));
3260
3261 listen_sock =
3262 GNUNET_NETWORK_socket_create (addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
3263 if (NULL == listen_sock)
3264 {
3265 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
3266 return GNUNET_SYSERR;
3267 }
3268
3269 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (listen_sock, addr, in_len))
3270 {
3271 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
3272 GNUNET_NETWORK_socket_close (listen_sock);
3273 listen_sock = NULL;
3274 return GNUNET_SYSERR;
3275 }
3276
3277 if (GNUNET_OK !=
3278 GNUNET_NETWORK_socket_listen (listen_sock,
3279 5))
3280 {
3281 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3282 "listen");
3283 GNUNET_NETWORK_socket_close (listen_sock);
3284 listen_sock = NULL;
3285 return GNUNET_SYSERR;
3286 }
3287
3288 /* We might have bound to port 0, allowing the OS to figure it out;
3289 thus, get the real IN-address from the socket */
3290 sto_len = sizeof(in_sto);
3291
3292 if (0 != getsockname (GNUNET_NETWORK_get_fd (listen_sock),
3293 (struct sockaddr *) &in_sto,
3294 &sto_len))
3295 {
3296 memcpy (&in_sto, addr, in_len);
3297 sto_len = in_len;
3298 }
3299
3300 // addr = (struct sockaddr *) &in_sto;
3301 in_len = sto_len;
3302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3303 "Bound to `%s'\n",
3304 GNUNET_a2s ((const struct sockaddr *) &in_sto, sto_len));
3305 stats = GNUNET_STATISTICS_create ("C-TCP", cfg);
3306
3307 if (NULL == is)
3308 is = GNUNET_NT_scanner_init ();
3309
3310 if (NULL == my_private_key)
3311 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
3312 if (NULL == my_private_key)
3313 {
3314 GNUNET_log (
3315 GNUNET_ERROR_TYPE_ERROR,
3316 _ (
3317 "Transport service is lacking key configuration settings. Exiting.\n"));
3318 if (NULL != resolve_request_handle)
3319 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3320 GNUNET_SCHEDULER_shutdown ();
3321 return GNUNET_SYSERR;
3322 }
3323 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
3324 /* start listening */
3325
3326 lt = GNUNET_new (struct ListenTask);
3327 lt->listen_sock = listen_sock;
3328
3329 lt->listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3330 listen_sock,
3331 &listen_cb,
3332 lt);
3333
3334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3335 "creating hash\n");
3336 sockfd = GNUNET_NETWORK_get_fd (lt->listen_sock);
3337 GNUNET_CRYPTO_hash (&sockfd,
3338 sizeof(int),
3339 &h_sock);
3340
3341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3342 "creating map\n");
3343 if (NULL == lt_map)
3344 lt_map = GNUNET_CONTAINER_multihashmap_create (2, GNUNET_NO);
3345
3346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3347 "creating map entry\n");
3348 GNUNET_assert (GNUNET_OK ==
3349 GNUNET_CONTAINER_multihashmap_put (lt_map,
3350 &h_sock,
3351 lt,
3352 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3353
3354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3355 "map entry created\n");
3356
3357 if (NULL == queue_map)
3358 queue_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
3359
3360 if (NULL == ch)
3361 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
3362 COMMUNICATOR_CONFIG_SECTION,
3363 COMMUNICATOR_ADDRESS_PREFIX,
3364 GNUNET_TRANSPORT_CC_RELIABLE,
3365 &mq_init,
3366 NULL,
3367 &enc_notify_cb,
3368 NULL);
3369
3370 if (NULL == ch)
3371 {
3372 GNUNET_break (0);
3373 if (NULL != resolve_request_handle)
3374 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3375 GNUNET_SCHEDULER_shutdown ();
3376 return GNUNET_SYSERR;
3377 }
3378
3379 add_addr (addr, in_len);
3380 return GNUNET_OK;
3381
3382}
3383
3384
3385/**
3386 * This method reads from the DLL addrs_head to register them at the NAT service.
3387 */
3388static void
3389nat_register ()
3390{
3391
3392 struct sockaddr **saddrs;
3393 socklen_t *saddr_lens;
3394 int i;
3395 struct Addresses *pos;
3396
3397
3398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3399 "starting nat register!\n");
3400
3401 i = 0;
3402 saddrs = GNUNET_malloc ((addrs_lens + 1) * sizeof(struct sockaddr *));
3403
3404 saddr_lens = GNUNET_malloc ((addrs_lens + 1) * sizeof(socklen_t));
3405
3406 for (pos = addrs_head; NULL != pos; pos = pos->next)
3407 {
3408
3409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3410 "registering address %s\n",
3411 GNUNET_a2s (addrs_head->addr, addrs_head->addr_len));
3412
3413 saddr_lens[i] = addrs_head->addr_len;
3414 saddrs[i] = GNUNET_memdup (addrs_head->addr, saddr_lens[i]);
3415
3416 i++;
3417
3418 }
3419
3420 nat = GNUNET_NAT_register (cfg,
3421 COMMUNICATOR_CONFIG_SECTION,
3422 IPPROTO_TCP,
3423 addrs_lens,
3424 (const struct sockaddr **) saddrs,
3425 saddr_lens,
3426 &nat_address_cb,
3427 NULL /* FIXME: support reversal: #5529 */,
3428 NULL /* closure */);
3429
3430 i = 0;
3431
3432 for (i = addrs_lens - 1; i >= 0; i--)
3433 GNUNET_free (saddrs[i]);
3434 GNUNET_free (saddrs);
3435 GNUNET_free (saddr_lens);
3436
3437 if (NULL == nat)
3438 {
3439 GNUNET_break (0);
3440 if (NULL != resolve_request_handle)
3441 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3442 GNUNET_SCHEDULER_shutdown ();
3443 }
3444}
3445
3446
3447/**
3448 * This method is the callback called by the resolver API, and wraps method init_socket.
3449 *
3450 * @param cls The port we will bind to.
3451 * @param addr The address we will bind to.
3452 * @param in_len The length of the address we will bind to.
3453 */
3454static void
3455init_socket_resolv (void *cls,
3456 const struct sockaddr *addr,
3457 socklen_t in_len)
3458{
3459 struct sockaddr_in *v4;
3460 struct sockaddr_in6 *v6;
3461 struct sockaddr *in;
3462
3463 (void) cls;
3464 if (NULL != addr)
3465 {
3466 if (AF_INET == addr->sa_family)
3467 {
3468 v4 = (struct sockaddr_in *) addr;
3469 in = tcp_address_to_sockaddr_numeric_v4 (&in_len, *v4, bind_port);// _global);
3470 }
3471 else if (AF_INET6 == addr->sa_family)
3472 {
3473 v6 = (struct sockaddr_in6 *) addr;
3474 in = tcp_address_to_sockaddr_numeric_v6 (&in_len, *v6, bind_port);// _global);
3475 }
3476 else
3477 {
3478 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3479 "Address family %u not suitable (not AF_INET %u nor AF_INET6 %u \n",
3480 addr->sa_family,
3481 AF_INET,
3482 AF_INET6);
3483 return;
3484 }
3485 init_socket (in, in_len);
3486 }
3487 else
3488 {
3489 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3490 "Address is NULL. This might be an error or the resolver finished resolving.\n");
3491 if (NULL == addrs_head)
3492 {
3493 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3494 "Resolver finished resolving, but we do not listen to an address!.\n");
3495 return;
3496 }
3497 nat_register ();
3498
3499 }
3500}
3501
3502
3503/**
3504 * Setup communicator and launch network interactions.
3505 *
3506 * @param cls NULL (always)
3507 * @param args remaining command-line arguments
3508 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
3509 * @param c configuration
3510 */
3511static void
3512run (void *cls,
3513 char *const *args,
3514 const char *cfgfile,
3515 const struct GNUNET_CONFIGURATION_Handle *c)
3516{
3517 char *bindto;
3518 struct sockaddr *in;
3519 socklen_t in_len;
3520 struct sockaddr_in v4;
3521 struct sockaddr_in6 v6;
3522 char *start;
3523 unsigned int port;
3524 char dummy[2];
3525 char *rest = NULL;
3526 struct PortOnlyIpv4Ipv6 *po;
3527 socklen_t addr_len_ipv4;
3528 socklen_t addr_len_ipv6;
3529
3530 (void) cls;
3531 cfg = c;
3532 if (GNUNET_OK !=
3533 GNUNET_CONFIGURATION_get_value_string (cfg,
3534 COMMUNICATOR_CONFIG_SECTION,
3535 "BINDTO",
3536 &bindto))
3537 {
3538 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3539 COMMUNICATOR_CONFIG_SECTION,
3540 "BINDTO");
3541 return;
3542 }
3543 if (GNUNET_OK !=
3544 GNUNET_CONFIGURATION_get_value_number (cfg,
3545 COMMUNICATOR_CONFIG_SECTION,
3546 "MAX_QUEUE_LENGTH",
3547 &max_queue_length))
3548 max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
3549 if (GNUNET_OK !=
3550 GNUNET_CONFIGURATION_get_value_time (cfg,
3551 COMMUNICATOR_CONFIG_SECTION,
3552 "REKEY_INTERVAL",
3553 &rekey_interval))
3554 rekey_interval = DEFAULT_REKEY_INTERVAL;
3555
3556 peerstore = GNUNET_PEERSTORE_connect (cfg);
3557 if (NULL == peerstore)
3558 {
3559 GNUNET_free (bindto);
3560 GNUNET_break (0);
3561 GNUNET_SCHEDULER_shutdown ();
3562 return;
3563 }
3564
3565 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
3566
3567 if (1 == sscanf (bindto, "%u%1s", &bind_port, dummy))
3568 {
3569 po = tcp_address_to_sockaddr_port_only (bindto, &bind_port);
3570
3571 addr_len_ipv4 = po->addr_len_ipv4;
3572
3573
3574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3575 "address po %s\n",
3576 GNUNET_a2s (po->addr_ipv4, addr_len_ipv4));
3577
3578 if (NULL != po->addr_ipv4)
3579 {
3580 init_socket (po->addr_ipv4, addr_len_ipv4);
3581 }
3582
3583 if (NULL != po->addr_ipv6)
3584 {
3585 addr_len_ipv6 = po->addr_len_ipv6;
3586 init_socket (po->addr_ipv6, addr_len_ipv6);
3587 }
3588
3589 GNUNET_free (po);
3590 nat_register ();
3591 GNUNET_free (bindto);
3592 return;
3593 }
3594
3595 start = extract_address (bindto);
3596
3597 if (1 == inet_pton (AF_INET, start, &v4.sin_addr))
3598 {
3599 bind_port = extract_port (bindto);
3600
3601 in = tcp_address_to_sockaddr_numeric_v4 (&in_len, v4, bind_port);
3602 init_socket (in, in_len);
3603 nat_register ();
3604 GNUNET_free (start);
3605 GNUNET_free (bindto);
3606 return;
3607 }
3608
3609 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
3610 {
3611 bind_port = extract_port (bindto);
3612 in = tcp_address_to_sockaddr_numeric_v6 (&in_len, v6, bind_port);
3613 init_socket (in, in_len);
3614 nat_register ();
3615 GNUNET_free (start);
3616 GNUNET_free (bindto);
3617 return;
3618 }
3619
3620
3621 bind_port = extract_port (bindto);
3622
3623 resolve_request_handle = GNUNET_RESOLVER_ip_get (strtok_r (bindto, ":",
3624 &rest),
3625 AF_UNSPEC,
3626 GNUNET_TIME_UNIT_MINUTES,
3627 &init_socket_resolv,
3628 &port);
3629 GNUNET_free (bindto);
3630 GNUNET_free (start);
3631}
3632
3633
3634/**
3635 * The main function for the UNIX communicator.
3636 *
3637 * @param argc number of arguments from the command line
3638 * @param argv command line arguments
3639 * @return 0 ok, 1 on error
3640 */
3641int
3642main (int argc, char *const *argv)
3643{
3644 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
3645 GNUNET_GETOPT_OPTION_END
3646 };
3647 int ret;
3648
3649 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
3650 return 2;
3651
3652 ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
3653 argv,
3654 "gnunet-communicator-tcp",
3655 _ ("GNUnet TCP communicator"),
3656 options,
3657 &run,
3658 NULL))
3659 ? 0
3660 : 1;
3661 GNUNET_free_nz ((void *) argv);
3662 return ret;
3663}
3664
3665
3666/* 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 ef7b1d6c0..000000000
--- a/src/transport/gnunet-communicator-udp.c
+++ /dev/null
@@ -1,3873 +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_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_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_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_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 GNUNET_assert (NULL != receiver->d_qh);
1498
1499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1500 "Tell transport we have %u more acks!\n",
1501 acks_to_add);
1502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1503 "%u kce for rekeying.\n",
1504 receiver->number_rekeying_kce);
1505 GNUNET_TRANSPORT_communicator_mq_update (ch,
1506 receiver->d_qh,
1507 acks_to_add,
1508 1);
1509 // Until here for alternativ 1
1510
1511 /* move ss to head to avoid discarding it anytime soon! */
1512
1513 GNUNET_CONTAINER_DLL_remove (receiver->ss_head, receiver->ss_tail, ss);
1514 GNUNET_CONTAINER_DLL_insert (receiver->ss_head, receiver->ss_tail, ss);
1515 destroy_all_secrets (ss, GNUNET_YES);
1516}
1517
1518
1519static uint32_t
1520reset_rekey_kces (struct ReceiverAddress *receiver,
1521 uint32_t acks_to_add)
1522{
1523 int needed_for_rekeying;
1524
1525 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1526 "%u kce for rekeying and %u acks_to_add\n",
1527 receiver->number_rekeying_kce,
1528 acks_to_add);
1529
1530 needed_for_rekeying = (3 - receiver->number_rekeying_kce);
1531 if (acks_to_add <= needed_for_rekeying)
1532 {
1533 receiver->number_rekeying_kce += acks_to_add;
1534 acks_to_add = 0;
1535 }
1536 else
1537 {
1538 acks_to_add -= (3 - receiver->number_rekeying_kce);
1539 receiver->number_rekeying_kce = 3;
1540 }
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 return acks_to_add;
1547}
1548
1549
1550static void
1551add_acks_rekey (struct ReceiverAddress *receiver)
1552{
1553 uint32_t acks_to_add = receiver->ss_rekey->sequence_allowed;
1554
1555 if (receiver->number_rekeying_kce < 3)
1556 acks_to_add = reset_rekey_kces (receiver, acks_to_add);
1557 receiver->acks_available = receiver->ss_rekey->sequence_allowed;
1558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1559 "%u receiver->acks_available 4\n",
1560 receiver->acks_available);
1561 /* add_acks (receiver->ss_rekey, acks_to_add - 3); */
1562 if (0 != acks_to_add)
1563 {
1564 add_acks (receiver->ss_rekey, acks_to_add);
1565 }
1566 receiver->ss_rekey = NULL;
1567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1568 "# rekeying successful\n");
1569 GNUNET_STATISTICS_update (stats,
1570 "# rekeying successful",
1571 1,
1572 GNUNET_NO);
1573}
1574
1575
1576/**
1577 * We received an ACK for @a pid. Check if it is for
1578 * the receiver in @a value and if so, handle it and
1579 * return #GNUNET_NO. Otherwise, return #GNUNET_YES.
1580 *
1581 * @param cls a `const struct UDPAck`
1582 * @param pid peer the ACK is from
1583 * @param value a `struct ReceiverAddress`
1584 * @return #GNUNET_YES to continue to iterate
1585 */
1586static int
1587handle_ack (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
1588{
1589 const struct UDPAck *ack = cls;
1590 struct ReceiverAddress *receiver = value;
1591 uint32_t acks_to_add;
1592 uint32_t allowed;
1593 // int needed_for_rekeying;
1594
1595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1596 "in handle ack with cmac %s\n",
1597 GNUNET_h2s (&ack->cmac));
1598
1599 if (NULL != receiver->ss_rekey)
1600 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1601 "We have rekey secret with cmac %s \n",
1602 GNUNET_h2s (&receiver->ss_rekey->cmac));
1603
1604 if ((NULL != receiver->ss_rekey) && (0 == memcmp (&ack->cmac,
1605 &receiver->ss_rekey->cmac,
1606 sizeof(struct
1607 GNUNET_HashCode))) )
1608 {
1609 allowed = ntohl (ack->sequence_max);
1610
1611 if (allowed > receiver->ss_rekey->sequence_allowed)
1612 {
1613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1614 "%u > %u (%u %u) for rekey secrect %s\n", allowed,
1615 receiver->ss_rekey->sequence_allowed,
1616 receiver->acks_available,
1617 ack->acks_available,
1618 GNUNET_h2s (&receiver->ss_rekey->master));
1619
1620 receiver->ss_rekey->sequence_allowed = allowed;
1621
1622 if (GNUNET_NO == receiver->rekeying)
1623 add_acks_rekey (receiver);
1624
1625 return GNUNET_NO;
1626 }
1627 }
1628
1629 (void) pid;
1630 for (struct SharedSecret *ss = receiver->ss_head; NULL != ss; ss = ss->next)
1631 {
1632 if (0 == memcmp (&ack->cmac, &ss->cmac, sizeof(struct GNUNET_HashCode)))
1633 {
1634
1635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1636 "Found matching mac\n");
1637
1638 allowed = ntohl (ack->sequence_max);
1639
1640 if (allowed > ss->sequence_allowed)
1641 {
1642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1643 "%u > %u (%u %u) for secrect %s\n", allowed,
1644 ss->sequence_allowed,
1645 receiver->acks_available,
1646 ack->acks_available,
1647 GNUNET_h2s (&ss->master));
1648 // Uncomment this for alternativ 1 of backchannel functionality
1649 acks_to_add = (allowed - ss->sequence_allowed);
1650 if ((GNUNET_NO == receiver->rekeying) &&
1651 (receiver->number_rekeying_kce < 3) )
1652 acks_to_add = reset_rekey_kces (receiver, acks_to_add);
1653 /* if ((GNUNET_NO == receiver->rekeying) && */
1654 /* (receiver->number_rekeying_kce < */
1655 /* 3) ) */
1656 /* { */
1657 /* needed_for_rekeying = (3 - receiver->number_rekeying_kce); */
1658 /* if (acks_to_add <= needed_for_rekeying) */
1659 /* { */
1660 /* receiver->number_rekeying_kce += acks_to_add; */
1661 /* acks_to_add = 0; */
1662 /* } */
1663 /* else */
1664 /* { */
1665 /* acks_to_add -= (3 - receiver->number_rekeying_kce); */
1666 /* receiver->number_rekeying_kce = 3; */
1667 /* } */
1668 /* } */
1669 /* GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, */
1670 /* "%u kce for rekeying\n", */
1671 /* receiver->number_rekeying_kce); */
1672
1673 if ((0 != acks_to_add) && (GNUNET_NO == receiver->rekeying))
1674 {
1675 receiver->acks_available += (allowed - ss->sequence_allowed);
1676 ss->sequence_allowed = allowed;
1677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1678 "%u receiver->acks_available 5\n",
1679 receiver->acks_available);
1680 add_acks (ss, acks_to_add);
1681 }
1682 }
1683 return GNUNET_NO;
1684 }
1685 }
1686 return GNUNET_YES;
1687}
1688
1689
1690/**
1691 * Test if we have received a valid message in plaintext.
1692 * If so, handle it.
1693 *
1694 * @param sender peer to process inbound plaintext for
1695 * @param buf buffer we received
1696 * @param buf_size number of bytes in @a buf
1697 */
1698static void
1699try_handle_plaintext (struct SenderAddress *sender,
1700 const void *buf,
1701 size_t buf_size)
1702{
1703 const struct GNUNET_MessageHeader *hdr =
1704 (const struct GNUNET_MessageHeader *) buf;
1705 const struct UDPAck *ack = (const struct UDPAck *) buf;
1706 uint16_t type;
1707
1708 if (sizeof(*hdr) > buf_size)
1709 return; /* not even a header */
1710 if (ntohs (hdr->size) > buf_size)
1711 return; /* not even a header */
1712 type = ntohs (hdr->type);
1713 switch (type)
1714 {
1715 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK:
1716 /* lookup master secret by 'cmac', then update sequence_max */
1717 GNUNET_CONTAINER_multipeermap_get_multiple (receivers,
1718 &sender->target,
1719 &handle_ack,
1720 (void *) ack);
1721 /* There could be more messages after the ACK, handle those as well */
1722 buf += ntohs (hdr->size);
1723 buf_size -= ntohs (hdr->size);
1724 pass_plaintext_to_core (sender, buf, buf_size);
1725 break;
1726
1727 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD:
1728 /* skip padding */
1729 break;
1730
1731 default:
1732 pass_plaintext_to_core (sender, buf, buf_size);
1733 }
1734}
1735
1736
1737static void
1738kce_generate_cb (void *cls)
1739{
1740 struct SharedSecret *ss = cls;
1741
1742 ss->sender->kce_task = NULL;
1743
1744 if (((GNUNET_NO == ss->sender->rekeying) && (ss->sender->acks_available <
1745 KCN_TARGET) ) ||
1746 ((ss->sender->ss_rekey == ss) && (GNUNET_YES == ss->sender->rekeying) &&
1747 (ss->sender->acks_available < 128)))
1748 {
1749
1750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1751 "Precomputing keys for master %s\n",
1752 GNUNET_h2s (&(ss->master)));
1753
1754 for (int i = 0; i < GENERATE_AT_ONCE; i++)
1755 kce_generate (ss, ++ss->sequence_allowed);
1756
1757 ss->sender->kce_task = GNUNET_SCHEDULER_add_delayed (
1758 WORKING_QUEUE_INTERVALL,
1759 kce_generate_cb,
1760 ss);
1761 }
1762 else
1763 {
1764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1765 "We have enough keys.\n");
1766 ss_finished = ss;
1767 ss->sender->kce_task_finished = GNUNET_YES;
1768 }
1769
1770
1771}
1772
1773
1774static void
1775kce_generate_rekey_cb (void *cls)
1776{
1777 struct SharedSecret *ss = cls;
1778
1779 ss->sender->kce_task_rekey = NULL;
1780
1781 if (NULL == ss->sender->kce_task)
1782 {
1783
1784 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1785 "Precomputing keys for rekey master %s\n",
1786 GNUNET_h2s (&(ss->master)));
1787
1788 for (int i = 0; i < GENERATE_AT_ONCE; i++)
1789 kce_generate (ss, ++ss->sequence_allowed);
1790
1791 ss->sender->kce_task = GNUNET_SCHEDULER_add_delayed (
1792 WORKING_QUEUE_INTERVALL,
1793 kce_generate_cb,
1794 ss);
1795 ss->sender->kce_task_rekey = NULL;
1796 }
1797 else
1798 {
1799 ss->sender->kce_task_rekey = GNUNET_SCHEDULER_add_delayed (
1800 WORKING_QUEUE_INTERVALL,
1801 kce_generate_rekey_cb,
1802 ss);
1803 }
1804}
1805
1806
1807/**
1808 * We established a shared secret with a sender. We should try to send
1809 * the sender an `struct UDPAck` at the next opportunity to allow the
1810 * sender to use @a ss longer (assuming we did not yet already
1811 * recently).
1812 *
1813 * @param ss shared secret to generate ACKs for
1814 * @param initial The SharedSecret came with initial KX.
1815 */
1816static void
1817consider_ss_ack (struct SharedSecret *ss, int initial)
1818{
1819 struct GNUNET_SCHEDULER_Task *kce_task_rekey;
1820 struct GNUNET_SCHEDULER_Task *kce_task;
1821 int kce_task_finished;
1822
1823 kce_task_rekey = ss->sender->kce_task_rekey;
1824 kce_task_finished = ss->sender->kce_task_finished;
1825 kce_task = ss->sender->kce_task;
1826
1827 GNUNET_assert (NULL != ss->sender);
1828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1829 "Considering SS UDPAck %s\n",
1830 GNUNET_i2s_full (&ss->sender->target));
1831
1832 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1833 "We have %u acks available.\n",
1834 ss->sender->acks_available);
1835 /* drop ancient KeyCacheEntries */
1836 while ((NULL != ss->kce_head) &&
1837 (MAX_SQN_DELTA <
1838 ss->kce_head->sequence_number - ss->kce_tail->sequence_number))
1839 kce_destroy (ss->kce_tail);
1840
1841
1842 if (GNUNET_NO == initial)
1843 kce_generate (ss, ++ss->sequence_allowed);
1844
1845 /*if (0 == ss->sender->acks_available)
1846 {
1847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1848 "Generating keys\n");
1849 while (ss->active_kce_count < KCN_TARGET)
1850 kce_generate (ss, ++ss->sequence_allowed);
1851 }*/
1852
1853 if (((NULL != kce_task) && kce_task_finished) || (GNUNET_NO == initial))
1854 {
1855 struct UDPAck ack;
1856 struct SharedSecret *ss_tell;
1857
1858 if (GNUNET_NO != initial)
1859 ss_tell = ss_finished;
1860 else
1861 ss_tell = ss;
1862
1863 ack.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK);
1864 ack.header.size = htons (sizeof(ack));
1865 ack.sequence_max = htonl (ss_tell->sequence_allowed);
1866 ack.acks_available = ss->sender->acks_available;
1867 ack.cmac = ss_tell->cmac;
1868 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1869 "Notifying transport of UDPAck %s with initial %u and master %s\n",
1870 GNUNET_i2s_full (&ss_tell->sender->target),
1871 initial,
1872 GNUNET_h2s (&(ss_tell->master)));
1873 GNUNET_TRANSPORT_communicator_notify (ch,
1874 &ss_tell->sender->target,
1875 COMMUNICATOR_ADDRESS_PREFIX,
1876 &ack.header);
1877 if (GNUNET_NO != initial)
1878 {
1879 destroy_all_secrets (ss, GNUNET_YES);
1880 kce_task = NULL;
1881 kce_task_finished = GNUNET_NO;
1882 }
1883 }
1884 else if ((NULL == kce_task) && ((KCN_THRESHOLD >
1885 ss->sender->acks_available) ||
1886 (GNUNET_YES == ss->sender->rekeying) ||
1887 (ss->sender->num_secrets > MAX_SECRETS) ))
1888 {
1889
1890 // kce_generate (ss, ++ss->sequence_allowed);
1891 // kce_generate (ss, ++ss->sequence_allowed);
1892 // TODO This task must be per sender!
1893 kce_task = GNUNET_SCHEDULER_add_delayed (WORKING_QUEUE_INTERVALL,
1894 kce_generate_cb,
1895 ss);
1896 kce_task_finished = GNUNET_NO;
1897
1898 }
1899 else if ((NULL == kce_task_rekey) && (GNUNET_YES ==
1900 ss->sender->rekeying) )
1901 {
1902 kce_task_rekey = GNUNET_SCHEDULER_add_delayed (WORKING_QUEUE_INTERVALL,
1903 kce_generate_rekey_cb,
1904 ss);
1905 }
1906}
1907
1908
1909/**
1910 * We received a @a box with matching @a kce. Decrypt and process it.
1911 *
1912 * @param box the data we received
1913 * @param box_len number of bytes in @a box
1914 * @param kce key index to decrypt @a box
1915 */
1916static void
1917decrypt_box (const struct UDPBox *box,
1918 size_t box_len,
1919 struct KeyCacheEntry *kce)
1920{
1921 struct SharedSecret *ss = kce->ss;
1922 char out_buf[box_len - sizeof(*box)];
1923
1924 GNUNET_assert (NULL != ss->sender);
1925 if (GNUNET_OK != try_decrypt (ss,
1926 box->gcm_tag,
1927 kce->sequence_number,
1928 (const char *) &box[1],
1929 sizeof(out_buf),
1930 out_buf))
1931 {
1932 GNUNET_STATISTICS_update (stats,
1933 "# Decryption failures with valid KCE",
1934 1,
1935 GNUNET_NO);
1936 kce_destroy (kce);
1937 return;
1938 }
1939 kce_destroy (kce);
1940 GNUNET_STATISTICS_update (stats,
1941 "# bytes decrypted with BOX",
1942 sizeof(out_buf),
1943 GNUNET_NO);
1944 GNUNET_STATISTICS_update (stats,
1945 "# messages decrypted with BOX",
1946 1,
1947 GNUNET_NO);
1948 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1949 "decrypted UDPBox with kid %s\n",
1950 GNUNET_sh2s (&box->kid));
1951 try_handle_plaintext (ss->sender, out_buf, sizeof(out_buf));
1952 if ((GNUNET_NO == box->rekeying) && (GNUNET_YES == ss->sender->rekeying))
1953 {
1954 ss->sender->rekeying = GNUNET_NO;
1955 ss->sender->ss_rekey = NULL;
1956 // destroy_all_secrets (ss, GNUNET_NO);
1957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1958 "Receiver stopped rekeying.\n");
1959 }
1960 else if (GNUNET_NO == box->rekeying)
1961 consider_ss_ack (ss, GNUNET_NO);
1962 else
1963 {
1964 ss->sender->rekeying = GNUNET_YES;
1965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1966 "Got Box: Receiver doing rekeying.\n");
1967 }
1968}
1969
1970
1971/**
1972 * We received a @a rekey with matching @a kce. Decrypt and process it.
1973 *
1974 * @param rekey the data we received
1975 * @param rekey_len number of bytes in @a rekey
1976 * @param kce key index to decrypt @a rekey
1977 */
1978static void
1979decrypt_rekey (const struct UDPRekey *rekey,
1980 size_t rekey_len,
1981 struct KeyCacheEntry *kce,
1982 struct SenderAddress *sender)
1983{
1984 struct SharedSecret *ss = kce->ss;
1985 struct SharedSecret *ss_rekey;
1986 char out_buf[rekey_len - sizeof(*rekey)];
1987 struct GNUNET_HashCode *master;
1988
1989
1990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1991 "decrypt_rekey.\n");
1992
1993 GNUNET_assert (NULL != ss->sender);
1994 if (GNUNET_OK != try_decrypt (ss,
1995 rekey->gcm_tag,
1996 kce->sequence_number,
1997 (const char *) &rekey[1],
1998 sizeof(out_buf),
1999 out_buf))
2000 {
2001 GNUNET_STATISTICS_update (stats,
2002 "# Decryption failures with valid KCE",
2003 1,
2004 GNUNET_NO);
2005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2006 "Decryption with kid %s failed\n",
2007 GNUNET_sh2s (&rekey->kid));
2008 kce_destroy (kce);
2009 return;
2010 }
2011 kce_destroy (kce);
2012 GNUNET_STATISTICS_update (stats,
2013 "# bytes decrypted with Rekey",
2014 sizeof(out_buf),
2015 GNUNET_NO);
2016 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2017 "decrypted UDPRekey with kid %s\n",
2018 GNUNET_sh2s (&rekey->kid));
2019 /*cmac = (struct GNUNET_HashCode *) out_buf;
2020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2021 "Received secret with cmac %s \n",
2022 GNUNET_h2s (&cmac));*/
2023 // ss_rekey = (struct SharedSecret *) out_buf;
2024 master = (struct GNUNET_HashCode *) out_buf;
2025 ss_rekey = GNUNET_new (struct SharedSecret);
2026 ss_rekey->master = *master;
2027 calculate_cmac (ss_rekey);
2028 ss_rekey->sender = sender;
2029 // ss_rekey->sequence_used = 0;
2030 // ss_rekey->sequence_allowed = 0;
2031 /* ss_rekey->active_kce_count = 0; */
2032 /* ss_rekey->prev = NULL; */
2033 /* ss_rekey->next = NULL; */
2034 /* GNUNET_assert (ss_rekey->prev == NULL && sender->ss_head != ss_rekey); */
2035 /* GNUNET_assert (ss_rekey->next == NULL && sender->ss_tail != ss_rekey); */
2036 GNUNET_CONTAINER_DLL_insert (sender->ss_head, sender->ss_tail, ss_rekey);
2037 sender->ss_rekey = ss_rekey;
2038 sender->num_secrets++;
2039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2040 "Received secret with cmac %s\n",
2041 GNUNET_h2s (&(ss_rekey->cmac)));
2042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2043 "Received secret with master %s.\n",
2044 GNUNET_h2s (&(ss_rekey->master)));
2045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2046 "We have %u sequence_allowed.\n",
2047 ss_rekey->sequence_allowed);
2048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2049 "We have a sender %p\n",
2050 ss_rekey->sender);
2051 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2052 "We have %u acks available.\n",
2053 ss_rekey->sender->acks_available);
2054 consider_ss_ack (ss_rekey, GNUNET_YES);
2055
2056}
2057
2058
2059/**
2060 * Closure for #find_sender_by_address()
2061 */
2062struct SearchContext
2063{
2064 /**
2065 * Address we are looking for.
2066 */
2067 const struct sockaddr *address;
2068
2069 /**
2070 * Number of bytes in @e address.
2071 */
2072 socklen_t address_len;
2073
2074 /**
2075 * Return value to set if we found a match.
2076 */
2077 struct SenderAddress *sender;
2078};
2079
2080
2081/**
2082 * Find existing `struct SenderAddress` by matching addresses.
2083 *
2084 * @param cls a `struct SearchContext`
2085 * @param key ignored, must match already
2086 * @param value a `struct SenderAddress`
2087 * @return #GNUNET_YES if not found (continue to search), #GNUNET_NO if found
2088 */
2089static int
2090find_sender_by_address (void *cls,
2091 const struct GNUNET_PeerIdentity *key,
2092 void *value)
2093{
2094 struct SearchContext *sc = cls;
2095 struct SenderAddress *sender = value;
2096
2097 if ((sender->address_len == sc->address_len) &&
2098 (0 == memcmp (sender->address, sc->address, sender->address_len)))
2099 {
2100 sc->sender = sender;
2101 return GNUNET_NO; /* stop iterating! */
2102 }
2103 return GNUNET_YES;
2104}
2105
2106
2107/**
2108 * Create sender address for @a target. Note that we
2109 * might already have one, so a fresh one is only allocated
2110 * if one does not yet exist for @a address.
2111 *
2112 * @param target peer to generate address for
2113 * @param address target address
2114 * @param address_len number of bytes in @a address
2115 * @return data structure to keep track of key material for
2116 * decrypting data from @a target
2117 */
2118static struct SenderAddress *
2119setup_sender (const struct GNUNET_PeerIdentity *target,
2120 const struct sockaddr *address,
2121 socklen_t address_len)
2122{
2123 struct SenderAddress *sender;
2124 struct SearchContext sc = { .address = address,
2125 .address_len = address_len,
2126 .sender = NULL };
2127
2128 GNUNET_CONTAINER_multipeermap_get_multiple (senders,
2129 target,
2130 &find_sender_by_address,
2131 &sc);
2132 if (NULL != sc.sender)
2133 {
2134 reschedule_sender_timeout (sc.sender);
2135 return sc.sender;
2136 }
2137 sender = GNUNET_new (struct SenderAddress);
2138 sender->target = *target;
2139 sender->address = GNUNET_memdup (address, address_len);
2140 sender->address_len = address_len;
2141 (void) GNUNET_CONTAINER_multipeermap_put (
2142 senders,
2143 &sender->target,
2144 sender,
2145 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2146 GNUNET_STATISTICS_set (stats,
2147 "# senders active",
2148 GNUNET_CONTAINER_multipeermap_size (receivers),
2149 GNUNET_NO);
2150 sender->timeout =
2151 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2152 sender->hn = GNUNET_CONTAINER_heap_insert (senders_heap,
2153 sender,
2154 sender->timeout.abs_value_us);
2155 sender->nt = GNUNET_NT_scanner_get_type (is, address, address_len);
2156 if (NULL == timeout_task)
2157 timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL);
2158 return sender;
2159}
2160
2161
2162/**
2163 * Check signature from @a uc against @a ephemeral.
2164 *
2165 * @param ephermal key that is signed
2166 * @param uc signature of claimant
2167 * @return #GNUNET_OK if signature is valid
2168 */
2169static int
2170verify_confirmation (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
2171 const struct UDPConfirmation *uc)
2172{
2173 struct UdpHandshakeSignature uhs;
2174
2175 uhs.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_UDP_HANDSHAKE);
2176 uhs.purpose.size = htonl (sizeof(uhs));
2177 uhs.sender = uc->sender;
2178 uhs.receiver = my_identity;
2179 uhs.ephemeral = *ephemeral;
2180 uhs.monotonic_time = uc->monotonic_time;
2181 return GNUNET_CRYPTO_eddsa_verify (
2182 GNUNET_SIGNATURE_COMMUNICATOR_UDP_HANDSHAKE,
2183 &uhs,
2184 &uc->sender_sig,
2185 &uc->sender.public_key);
2186}
2187
2188
2189/**
2190 * Converts @a address to the address string format used by this
2191 * communicator in HELLOs.
2192 *
2193 * @param address the address to convert, must be AF_INET or AF_INET6.
2194 * @param address_len number of bytes in @a address
2195 * @return string representation of @a address
2196 */
2197static char *
2198sockaddr_to_udpaddr_string (const struct sockaddr *address,
2199 socklen_t address_len)
2200{
2201 char *ret;
2202
2203 switch (address->sa_family)
2204 {
2205 case AF_INET:
2206 GNUNET_asprintf (&ret,
2207 "%s-%s",
2208 COMMUNICATOR_ADDRESS_PREFIX,
2209 GNUNET_a2s (address, address_len));
2210 break;
2211
2212 case AF_INET6:
2213 GNUNET_asprintf (&ret,
2214 "%s-%s",
2215 COMMUNICATOR_ADDRESS_PREFIX,
2216 GNUNET_a2s (address, address_len));
2217 break;
2218
2219 default:
2220 GNUNET_assert (0);
2221 }
2222 return ret;
2223}
2224
2225
2226/**
2227 * Socket read task.
2228 *
2229 * @param cls NULL
2230 */
2231static void
2232sock_read (void *cls)
2233{
2234 struct sockaddr_storage sa;
2235 socklen_t salen = sizeof(sa);
2236 char buf[UINT16_MAX];
2237 ssize_t rcvd;
2238
2239 (void) cls;
2240 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2241 udp_sock,
2242 &sock_read,
2243 NULL);
2244 rcvd = GNUNET_NETWORK_socket_recvfrom (udp_sock,
2245 buf,
2246 sizeof(buf),
2247 (struct sockaddr *) &sa,
2248 &salen);
2249 if (-1 == rcvd)
2250 {
2251 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2252 return;
2253 }
2254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2255 "Read %lu bytes\n", rcvd);
2256
2257 if (rcvd > sizeof(struct UDPRekey))
2258 {
2259 const struct UDPRekey *rekey;
2260 const struct UDPBox *box;
2261 struct KeyCacheEntry *kce;
2262 struct SenderAddress *sender;
2263 int do_decrypt = GNUNET_NO;
2264
2265 rekey = (const struct UDPRekey *) buf;
2266 box = (const struct UDPBox *) buf;
2267 kce = GNUNET_CONTAINER_multishortmap_get (key_cache, &rekey->kid);
2268
2269 if ((GNUNET_YES == box->rekeying) || (GNUNET_NO == box->rekeying))
2270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2271 "UDPRekey has rekeying %u\n",
2272 box->rekeying);
2273 else
2274 do_decrypt = GNUNET_YES;
2275
2276 if ((GNUNET_YES == do_decrypt) && (NULL != kce) && (GNUNET_YES ==
2277 kce->ss->sender->
2278 rekeying))
2279 {
2280 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2281 "UDPRekey with kid %s\n",
2282 GNUNET_sh2s (&rekey->kid));
2283 sender = setup_sender (&rekey->sender, (const struct sockaddr *) &sa,
2284 salen);
2285
2286 if (NULL != sender->ss_rekey)
2287 return;
2288
2289 decrypt_rekey (rekey, (size_t) rcvd, kce, sender);
2290 return;
2291 }
2292 }
2293
2294 /* first, see if it is a UDPBox */
2295 if (rcvd > sizeof(struct UDPBox))
2296 {
2297 const struct UDPBox *box;
2298 struct KeyCacheEntry *kce;
2299
2300 box = (const struct UDPBox *) buf;
2301 kce = GNUNET_CONTAINER_multishortmap_get (key_cache, &box->kid);
2302 if (NULL != kce)
2303 {
2304 decrypt_box (box, (size_t) rcvd, kce);
2305 return;
2306 }
2307 }
2308
2309 /* next, check if it is a broadcast */
2310 if (sizeof(struct UDPBroadcast) == rcvd)
2311 {
2312 const struct UDPBroadcast *ub;
2313 struct UdpBroadcastSignature uhs;
2314
2315 ub = (const struct UDPBroadcast *) buf;
2316 uhs.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_UDP_BROADCAST);
2317 uhs.purpose.size = htonl (sizeof(uhs));
2318 uhs.sender = ub->sender;
2319 GNUNET_CRYPTO_hash (&sa, salen, &uhs.h_address);
2320 if (GNUNET_OK ==
2321 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_COMMUNICATOR_UDP_BROADCAST,
2322 &uhs,
2323 &ub->sender_sig,
2324 &ub->sender.public_key))
2325 {
2326 char *addr_s;
2327 enum GNUNET_NetworkType nt;
2328
2329 addr_s =
2330 sockaddr_to_udpaddr_string ((const struct sockaddr *) &sa, salen);
2331 GNUNET_STATISTICS_update (stats, "# broadcasts received", 1, GNUNET_NO);
2332 /* use our own mechanism to determine network type */
2333 nt =
2334 GNUNET_NT_scanner_get_type (is, (const struct sockaddr *) &sa, salen);
2335 GNUNET_TRANSPORT_application_validate (ah, &ub->sender, nt, addr_s);
2336 GNUNET_free (addr_s);
2337 return;
2338 }
2339 /* continue with KX, mostly for statistics... */
2340 }
2341
2342
2343 /* finally, test if it is a KX */
2344 if (rcvd < sizeof(struct UDPConfirmation) + sizeof(struct InitialKX))
2345 {
2346 GNUNET_STATISTICS_update (stats,
2347 "# messages dropped (no kid, too small for KX)",
2348 1,
2349 GNUNET_NO);
2350 return;
2351 }
2352 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2353 "Got KX\n");
2354 {
2355 const struct InitialKX *kx;
2356 struct SharedSecret *ss;
2357 char pbuf[rcvd - sizeof(struct InitialKX)];
2358 const struct UDPConfirmation *uc;
2359 struct SenderAddress *sender;
2360
2361 kx = (const struct InitialKX *) buf;
2362 ss = setup_shared_secret_dec (&kx->ephemeral);
2363 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2364 "Before DEC\n");
2365
2366 if (GNUNET_OK != try_decrypt (ss,
2367 kx->gcm_tag,
2368 0,
2369 &buf[sizeof(*kx)],
2370 sizeof(pbuf),
2371 pbuf))
2372 {
2373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2374 "Unable to decrypt tag, dropping...\n");
2375 GNUNET_free (ss);
2376 GNUNET_STATISTICS_update (
2377 stats,
2378 "# messages dropped (no kid, AEAD decryption failed)",
2379 1,
2380 GNUNET_NO);
2381 return;
2382 }
2383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2384 "Before VERIFY\n");
2385
2386 uc = (const struct UDPConfirmation *) pbuf;
2387 if (GNUNET_OK != verify_confirmation (&kx->ephemeral, uc))
2388 {
2389 GNUNET_break_op (0);
2390 GNUNET_free (ss);
2391 GNUNET_STATISTICS_update (stats,
2392 "# messages dropped (sender signature invalid)",
2393 1,
2394 GNUNET_NO);
2395 return;
2396 }
2397 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2398 "Before SETUP_SENDER\n");
2399
2400 calculate_cmac (ss);
2401 sender = setup_sender (&uc->sender, (const struct sockaddr *) &sa, salen);
2402 ss->sender = sender;
2403 GNUNET_CONTAINER_DLL_insert (sender->ss_head, sender->ss_tail, ss);
2404 sender->num_secrets++;
2405 GNUNET_STATISTICS_update (stats, "# Secrets active", 1, GNUNET_NO);
2406 GNUNET_STATISTICS_update (stats,
2407 "# messages decrypted without BOX",
2408 1,
2409 GNUNET_NO);
2410 try_handle_plaintext (sender, &uc[1], sizeof(pbuf) - sizeof(*uc));
2411 if ((GNUNET_NO == kx->rekeying) && (GNUNET_YES == ss->sender->rekeying))
2412 {
2413 ss->sender->rekeying = GNUNET_NO;
2414 sender->ss_rekey = NULL;
2415 // destroy_all_secrets (ss, GNUNET_NO);
2416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2417 "Receiver stopped rekeying.\n");
2418 }
2419 else if (GNUNET_NO == kx->rekeying)
2420 consider_ss_ack (ss, GNUNET_YES);
2421 else
2422 {
2423 ss->sender->rekeying = GNUNET_YES;
2424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2425 "Got KX: Receiver doing rekeying.\n");
2426 }
2427 /*if (sender->num_secrets > MAX_SECRETS)
2428 secret_destroy (sender->ss_tail);*/
2429 }
2430}
2431
2432
2433/**
2434 * Convert UDP bind specification to a `struct sockaddr *`
2435 *
2436 * @param bindto bind specification to convert
2437 * @param[out] sock_len set to the length of the address
2438 * @return converted bindto specification
2439 */
2440static struct sockaddr *
2441udp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
2442{
2443 struct sockaddr *in;
2444 unsigned int port;
2445 char dummy[2];
2446 char *colon;
2447 char *cp;
2448
2449 if (1 == sscanf (bindto, "%u%1s", &port, dummy))
2450 {
2451 /* interpreting value as just a PORT number */
2452 if (port > UINT16_MAX)
2453 {
2454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2455 "BINDTO specification `%s' invalid: value too large for port\n",
2456 bindto);
2457 return NULL;
2458 }
2459 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
2460 (GNUNET_YES ==
2461 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2462 COMMUNICATOR_CONFIG_SECTION,
2463 "DISABLE_V6")))
2464 {
2465 struct sockaddr_in *i4;
2466
2467 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2468 i4->sin_family = AF_INET;
2469 i4->sin_port = htons ((uint16_t) port);
2470 *sock_len = sizeof(struct sockaddr_in);
2471 in = (struct sockaddr *) i4;
2472 }
2473 else
2474 {
2475 struct sockaddr_in6 *i6;
2476
2477 i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
2478 i6->sin6_family = AF_INET6;
2479 i6->sin6_port = htons ((uint16_t) port);
2480 *sock_len = sizeof(struct sockaddr_in6);
2481 in = (struct sockaddr *) i6;
2482 }
2483 return in;
2484 }
2485 cp = GNUNET_strdup (bindto);
2486 colon = strrchr (cp, ':');
2487 if (NULL != colon)
2488 {
2489 /* interpret value after colon as port */
2490 *colon = '\0';
2491 colon++;
2492 if (1 == sscanf (colon, "%u%1s", &port, dummy))
2493 {
2494 /* interpreting value as just a PORT number */
2495 if (port > UINT16_MAX)
2496 {
2497 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2498 "BINDTO specification `%s' invalid: value too large for port\n",
2499 bindto);
2500 GNUNET_free (cp);
2501 return NULL;
2502 }
2503 }
2504 else
2505 {
2506 GNUNET_log (
2507 GNUNET_ERROR_TYPE_ERROR,
2508 "BINDTO specification `%s' invalid: last ':' not followed by number\n",
2509 bindto);
2510 GNUNET_free (cp);
2511 return NULL;
2512 }
2513 }
2514 else
2515 {
2516 /* interpret missing port as 0, aka pick any free one */
2517 port = 0;
2518 }
2519 {
2520 /* try IPv4 */
2521 struct sockaddr_in v4;
2522 if (1 == inet_pton (AF_INET, cp, &v4.sin_addr))
2523 {
2524 v4.sin_family = AF_INET;
2525 v4.sin_port = htons ((uint16_t) port);
2526#if HAVE_SOCKADDR_IN_SIN_LEN
2527 v4.sin_len = sizeof(struct sockaddr_in);
2528#endif
2529 in = GNUNET_memdup (&v4, sizeof(struct sockaddr_in));
2530 *sock_len = sizeof(struct sockaddr_in);
2531 GNUNET_free (cp);
2532 return in;
2533 }
2534 }
2535 {
2536 /* try IPv6 */
2537 struct sockaddr_in6 v6;
2538 const char *start;
2539
2540 start = cp;
2541 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
2542 {
2543 start++; /* skip over '[' */
2544 cp[strlen (cp) - 1] = '\0'; /* eat ']' */
2545 }
2546 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
2547 {
2548 v6.sin6_family = AF_INET6;
2549 v6.sin6_port = htons ((uint16_t) port);
2550#if HAVE_SOCKADDR_IN_SIN_LEN
2551 v6.sin6_len = sizeof(sizeof(struct sockaddr_in6));
2552#endif
2553 in = GNUNET_memdup (&v6, sizeof(v6));
2554 *sock_len = sizeof(v6);
2555 GNUNET_free (cp);
2556 return in;
2557 }
2558 }
2559 /* #5528 FIXME (feature!): maybe also try getnameinfo()? */
2560 GNUNET_free (cp);
2561 return NULL;
2562}
2563
2564
2565/**
2566 * Pad @a dgram by @a pad_size using @a out_cipher.
2567 *
2568 * @param out_cipher cipher to use
2569 * @param dgram datagram to pad
2570 * @param pad_size number of bytes of padding to append
2571 */
2572static void
2573do_pad (gcry_cipher_hd_t out_cipher, char *dgram, size_t pad_size)
2574{
2575 char pad[pad_size];
2576
2577 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, pad, sizeof(pad));
2578 if (sizeof(pad) > sizeof(struct GNUNET_MessageHeader))
2579 {
2580 struct GNUNET_MessageHeader hdr =
2581 { .size = htons (sizeof(pad)),
2582 .type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD) };
2583
2584 memcpy (pad, &hdr, sizeof(hdr));
2585 }
2586 GNUNET_assert (
2587 0 ==
2588 gcry_cipher_encrypt (out_cipher, dgram, sizeof(pad), pad, sizeof(pad)));
2589}
2590
2591
2592/**
2593 * Signature of functions implementing the sending functionality of a
2594 * message queue.
2595 *
2596 * @param mq the message queue
2597 * @param msg the message to send
2598 * @param impl_state our `struct ReceiverAddress`
2599 */
2600static void
2601mq_send_kx (struct GNUNET_MQ_Handle *mq,
2602 const struct GNUNET_MessageHeader *msg,
2603 void *impl_state)
2604{
2605 struct ReceiverAddress *receiver = impl_state;
2606 uint16_t msize = ntohs (msg->size);
2607 struct UdpHandshakeSignature uhs;
2608 struct UDPConfirmation uc;
2609 struct InitialKX kx;
2610 struct GNUNET_CRYPTO_EcdhePrivateKey epriv;
2611 char dgram[receiver->kx_mtu + sizeof(uc) + sizeof(kx)];
2612 size_t dpos;
2613 gcry_cipher_hd_t out_cipher;
2614 struct SharedSecret *ss;
2615
2616 GNUNET_assert (mq == receiver->kx_mq);
2617 if (msize > receiver->kx_mtu)
2618 {
2619 GNUNET_break (0);
2620 if (GNUNET_YES != receiver->receiver_destroy_called)
2621 receiver_destroy (receiver);
2622 return;
2623 }
2624 reschedule_receiver_timeout (receiver);
2625
2626 /* setup key material */
2627 GNUNET_CRYPTO_ecdhe_key_create (&epriv);
2628
2629 ss = setup_shared_secret_enc (&epriv, receiver, GNUNET_YES);
2630
2631 if (receiver->num_secrets > MAX_SECRETS)
2632 {
2633 destroy_all_secrets (ss, GNUNET_YES);
2634 }
2635
2636 setup_cipher (&ss->master, 0, &out_cipher);
2637 /* compute 'uc' */
2638 uc.sender = my_identity;
2639 uc.monotonic_time =
2640 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
2641 uhs.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_UDP_HANDSHAKE);
2642 uhs.purpose.size = htonl (sizeof(uhs));
2643 uhs.sender = my_identity;
2644 uhs.receiver = receiver->target;
2645 GNUNET_CRYPTO_ecdhe_key_get_public (&epriv, &uhs.ephemeral);
2646 uhs.monotonic_time = uc.monotonic_time;
2647 GNUNET_CRYPTO_eddsa_sign (my_private_key,
2648 &uhs,
2649 &uc.sender_sig);
2650 /* Leave space for kx */
2651 dpos = sizeof(kx);
2652 /* Append encrypted uc to dgram */
2653 GNUNET_assert (0 == gcry_cipher_encrypt (out_cipher,
2654 &dgram[dpos],
2655 sizeof(uc),
2656 &uc,
2657 sizeof(uc)));
2658 dpos += sizeof(uc);
2659 /* Append encrypted payload to dgram */
2660 GNUNET_assert (
2661 0 == gcry_cipher_encrypt (out_cipher, &dgram[dpos], msize, msg, msize));
2662 dpos += msize;
2663 do_pad (out_cipher, &dgram[dpos], sizeof(dgram) - dpos);
2664 /* Datagram starts with kx */
2665 kx.ephemeral = uhs.ephemeral;
2666 GNUNET_assert (
2667 0 == gcry_cipher_gettag (out_cipher, kx.gcm_tag, sizeof(kx.gcm_tag)));
2668 gcry_cipher_close (out_cipher);
2669 if (GNUNET_NO == receiver->rekeying)
2670 kx.rekeying = GNUNET_NO;
2671 else
2672 kx.rekeying = GNUNET_YES;
2673 memcpy (dgram, &kx, sizeof(kx));
2674 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
2675 dgram,
2676 sizeof(dgram),
2677 receiver->address,
2678 receiver->address_len))
2679 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
2680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2681 "Sending KX to %s\n", GNUNET_a2s (receiver->address,
2682 receiver->address_len));
2683 GNUNET_MQ_impl_send_continue (mq);
2684}
2685
2686
2687static void
2688check_for_rekeying (struct ReceiverAddress *receiver, struct UDPBox *box)
2689{
2690
2691 struct GNUNET_TIME_Relative rt;
2692
2693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2694 "Timeout is %llu\n.",
2695 (unsigned long long) receiver->rekey_timeout.abs_value_us);
2696
2697 if (0 == receiver->rekey_timeout.abs_value_us)
2698 {
2699 receiver->rekey_timeout = GNUNET_TIME_relative_to_absolute (
2700 rekey_interval);
2701 }
2702 else
2703 {
2704 rt = GNUNET_TIME_absolute_get_remaining (receiver->rekey_timeout);
2705 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2706 "Relative time is %llu and timeout is %llu\n.",
2707 (unsigned long long) rt.rel_value_us,
2708 (unsigned long long) receiver->rekey_timeout.abs_value_us);
2709
2710 if ((0 == rt.rel_value_us) || (receiver->rekey_send_bytes >
2711 rekey_max_bytes) )
2712 {
2713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2714 "Bytes send %llu greater than %llu max bytes\n.",
2715 (unsigned long long) receiver->rekey_send_bytes,
2716 rekey_max_bytes);
2717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2718 "Relative time is %llu and timeout is %llu\n.",
2719 (unsigned long long) rt.rel_value_us,
2720 (unsigned long long) receiver->rekey_timeout.abs_value_us);
2721
2722 receiver->rekey_timeout.abs_value_us = 0;
2723 receiver->rekey_send_bytes = 0;
2724 receiver->ss_rekey = NULL;
2725 // destroy_all_secrets (ss, GNUNET_NO);
2726 receiver->rekeying = GNUNET_YES;
2727 receiver->rekey_acks_available = receiver->acks_available;
2728 box->rekeying = GNUNET_YES;
2729 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2730 "Sender started rekeying.\n");
2731 if (GNUNET_YES == box->rekeying)
2732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2733 "Sending rekeying with kid %s\n",
2734 GNUNET_sh2s (&box->kid));
2735 }
2736 }
2737}
2738
2739
2740static void
2741send_UDPRekey (struct ReceiverAddress *receiver, struct SharedSecret *ss)
2742{
2743 uint8_t is_ss_rekey_sequence_allowed_zero = GNUNET_NO;
2744 uint8_t is_acks_available_below = GNUNET_NO;
2745 uint8_t send_rekey = GNUNET_NO;
2746 uint16_t not_below;
2747 struct GNUNET_CRYPTO_EcdhePrivateKey epriv;
2748 struct UDPRekey *rekey;
2749 size_t dpos;
2750
2751 char rekey_dgram[sizeof(struct UDPRekey) + receiver->d_mtu];
2752
2753 if (NULL != receiver->ss_rekey)
2754 {
2755 not_below = (receiver->rekey_acks_available
2756 - (receiver->rekey_acks_available % 3)) / 3;
2757 is_ss_rekey_sequence_allowed_zero = (0 ==
2758 receiver->ss_rekey->sequence_allowed);
2759 is_acks_available_below = (receiver->acks_available >= not_below);
2760 send_rekey = (0 == (receiver->acks_available - not_below) % not_below) &&
2761 is_acks_available_below && is_ss_rekey_sequence_allowed_zero;
2762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2763 "send_rekey: %u, %u, %u\n",
2764 send_rekey,
2765 receiver->rekey_acks_available,
2766 receiver->acks_available);
2767 }
2768 else if (NULL == receiver->ss_rekey)
2769 {
2770 /* setup key material */
2771 GNUNET_CRYPTO_ecdhe_key_create (&epriv);
2772 receiver->ss_rekey = setup_shared_secret_enc (&epriv, receiver,
2773 GNUNET_NO);
2774 receiver->ss_rekey->sequence_allowed = 0;
2775 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2776 "Setup secret with cmac %s\n",
2777 GNUNET_h2s (&(receiver->ss_rekey->cmac)));
2778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2779 "Setup secret with master %s.\n",
2780 GNUNET_h2s (&(receiver->ss_rekey->master)));
2781 }
2782
2783 if (send_rekey)
2784 {
2785 GNUNET_assert (0 != receiver->number_rekeying_kce);
2786 gcry_cipher_hd_t rekey_out_cipher;
2787
2788 while (NULL != ss && ss->sequence_used >= ss->sequence_allowed)
2789 {
2790 ss = ss->prev;
2791 }
2792
2793 if (NULL != ss)
2794 {
2795 rekey = (struct UDPRekey *) rekey_dgram;
2796 rekey->sender = my_identity;
2797 ss->sequence_used++;
2798 get_kid (&ss->master, ss->sequence_used, &rekey->kid);
2799 receiver->number_rekeying_kce--;
2800 setup_cipher (&ss->master, ss->sequence_used, &rekey_out_cipher);
2801 /* Append encrypted payload to dgram */
2802 dpos = sizeof(struct UDPRekey);
2803
2804 GNUNET_assert (
2805 0 == gcry_cipher_encrypt (rekey_out_cipher, &rekey_dgram[dpos],
2806 sizeof(receiver->ss_rekey->master),
2807 &(receiver->ss_rekey->master),
2808 sizeof(receiver->ss_rekey->master)));
2809 dpos += sizeof(receiver->ss_rekey->master);
2810 /* GNUNET_assert ( */
2811 /* 0 == gcry_cipher_encrypt (rekey_out_cipher, &rekey_dgram[dpos], */
2812 /* /\*sizeof(receiver->ss_rekey->cmac), */
2813 /* &(receiver->ss_rekey->cmac), */
2814 /* sizeof(receiver->ss_rekey->cmac))); */
2815 /* dpos += sizeof(receiver->ss_rekey->cmac);*\/ */
2816 /* sizeof(receiver->ss_rekey), */
2817 /* receiver->ss_rekey, */
2818 /* sizeof(receiver->ss_rekey))); */
2819 /* dpos += sizeof(receiver->ss_rekey); */
2820 do_pad (rekey_out_cipher, &rekey_dgram[dpos], sizeof(rekey_dgram)
2821 - dpos);
2822 GNUNET_assert (0 == gcry_cipher_gettag (rekey_out_cipher,
2823 rekey->gcm_tag,
2824 sizeof(rekey->gcm_tag)));
2825 gcry_cipher_close (rekey_out_cipher);
2826
2827 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2828 "Sending rekey with kid %s and master %s\n",
2829 GNUNET_sh2s (&rekey->kid),
2830 GNUNET_h2s (&(receiver->ss_rekey->master)));
2831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2832 "Sending rekey with cmac %s\n",
2833 GNUNET_h2s (&(receiver->ss_rekey->cmac)));
2834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2835 "%u rekey kces left.\n",
2836 receiver->number_rekeying_kce);
2837
2838 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
2839 rekey_dgram,
2840 sizeof(rekey_dgram),
2841 receiver->address,
2842 receiver->address_len))
2843 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
2844
2845 receiver->acks_available--;
2846 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2847 "%u receiver->acks_available 1\n",
2848 receiver->acks_available);
2849 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2850 "Sending UDPRekey to %s\n", GNUNET_a2s (receiver->address,
2851 receiver->
2852 address_len));
2853 }
2854 }
2855}
2856
2857
2858/**
2859 * Signature of functions implementing the sending functionality of a
2860 * message queue.
2861 *
2862 * @param mq the message queue
2863 * @param msg the message to send
2864 * @param impl_state our `struct ReceiverAddress`
2865 */
2866static void
2867mq_send_d (struct GNUNET_MQ_Handle *mq,
2868 const struct GNUNET_MessageHeader *msg,
2869 void *impl_state)
2870{
2871 struct ReceiverAddress *receiver = impl_state;
2872 uint16_t msize = ntohs (msg->size);
2873
2874 GNUNET_assert (mq == receiver->d_mq);
2875 if ((msize > receiver->d_mtu) ||
2876 (0 == receiver->acks_available))
2877 {
2878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2879 "msize: %u, mtu: %lu, acks: %u\n",
2880 msize,
2881 receiver->d_mtu,
2882 receiver->acks_available);
2883
2884 GNUNET_break (0);
2885 if (GNUNET_YES != receiver->receiver_destroy_called)
2886 receiver_destroy (receiver);
2887 return;
2888 }
2889 reschedule_receiver_timeout (receiver);
2890
2891 /* begin "BOX" encryption method, scan for ACKs from tail! */
2892 for (struct SharedSecret *ss = receiver->ss_tail; NULL != ss; ss = ss->prev)
2893 {
2894 if (0 < ss->sequence_used)
2895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2896 "Trying to send UDPBox with shared secrect %s sequence_used %u and ss->sequence_allowed %u\n",
2897 GNUNET_h2s (&ss->master),
2898 ss->sequence_used,
2899 ss->sequence_allowed);
2900 // Uncomment this for alternativ 1 of backchannel functionality
2901 if (ss->sequence_used >= ss->sequence_allowed)
2902 // Until here for alternativ 1
2903 // Uncomment this for alternativ 2 of backchannel functionality
2904 // if (0 == ss->sequence_allowed)
2905 // Until here for alternativ 2
2906 {
2907 continue;
2908 }
2909 char dgram[sizeof(struct UDPBox) + receiver->d_mtu];
2910 struct UDPBox *box;
2911 gcry_cipher_hd_t out_cipher;
2912 size_t dpos;
2913
2914 box = (struct UDPBox *) dgram;
2915 ss->sequence_used++;
2916 get_kid (&ss->master, ss->sequence_used, &box->kid);
2917 setup_cipher (&ss->master, ss->sequence_used, &out_cipher);
2918 /* Append encrypted payload to dgram */
2919 dpos = sizeof(struct UDPBox);
2920 GNUNET_assert (
2921 0 == gcry_cipher_encrypt (out_cipher, &dgram[dpos], msize, msg, msize));
2922 dpos += msize;
2923 do_pad (out_cipher, &dgram[dpos], sizeof(dgram) - dpos);
2924 GNUNET_assert (0 == gcry_cipher_gettag (out_cipher,
2925 box->gcm_tag,
2926 sizeof(box->gcm_tag)));
2927 gcry_cipher_close (out_cipher);
2928
2929 receiver->rekey_send_bytes += sizeof(struct UDPBox) + receiver->d_mtu;
2930
2931 if (GNUNET_NO == receiver->rekeying)
2932 box->rekeying = GNUNET_NO;
2933 else
2934 box->rekeying = GNUNET_YES;
2935
2936 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
2937 dgram,
2938 sizeof(dgram),
2939 receiver->address,
2940 receiver->address_len))
2941 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
2942 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2943 "Sending UDPBox %u acks left\n",
2944 receiver->acks_available);
2945 GNUNET_MQ_impl_send_continue (mq);
2946 receiver->acks_available--;
2947 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2948 "%u receiver->acks_available 2\n",
2949 receiver->acks_available);
2950 check_for_rekeying (receiver, box);
2951 if (0 == receiver->acks_available - receiver->number_rekeying_kce)
2952 {
2953 /* We have no more ACKs */
2954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2955 "No more acks\n");
2956 if (GNUNET_YES == receiver->rekeying)
2957 {
2958 receiver->rekeying = GNUNET_NO;
2959 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2960 "Sender stopped rekeying\n");
2961
2962 if ((NULL != receiver->ss_rekey) && (0 <
2963 receiver->ss_rekey->
2964 sequence_allowed) )
2965 add_acks_rekey (receiver);
2966 }
2967 }
2968 else if ((GNUNET_YES == receiver->rekeying) )
2969 {
2970 send_UDPRekey (receiver, ss);
2971 }
2972
2973 return;
2974 }
2975}
2976
2977
2978/**
2979 * Signature of functions implementing the destruction of a message
2980 * queue. Implementations must not free @a mq, but should take care
2981 * of @a impl_state.
2982 *
2983 * @param mq the message queue to destroy
2984 * @param impl_state our `struct ReceiverAddress`
2985 */
2986static void
2987mq_destroy_d (struct GNUNET_MQ_Handle *mq, void *impl_state)
2988{
2989 struct ReceiverAddress *receiver = impl_state;
2990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2991 "Default MQ destroyed\n");
2992 if (mq == receiver->d_mq)
2993 {
2994 receiver->d_mq = NULL;
2995 if (GNUNET_YES != receiver->receiver_destroy_called)
2996 receiver_destroy (receiver);
2997 }
2998}
2999
3000
3001/**
3002 * Signature of functions implementing the destruction of a message
3003 * queue. Implementations must not free @a mq, but should take care
3004 * of @a impl_state.
3005 *
3006 * @param mq the message queue to destroy
3007 * @param impl_state our `struct ReceiverAddress`
3008 */
3009static void
3010mq_destroy_kx (struct GNUNET_MQ_Handle *mq, void *impl_state)
3011{
3012 struct ReceiverAddress *receiver = impl_state;
3013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3014 "KX MQ destroyed\n");
3015 if (mq == receiver->kx_mq)
3016 {
3017 receiver->kx_mq = NULL;
3018 if (GNUNET_YES != receiver->receiver_destroy_called)
3019 receiver_destroy (receiver);
3020 }
3021}
3022
3023
3024/**
3025 * Implementation function that cancels the currently sent message.
3026 *
3027 * @param mq message queue
3028 * @param impl_state our `struct RecvierAddress`
3029 */
3030static void
3031mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
3032{
3033 /* Cancellation is impossible with UDP; bail */
3034 GNUNET_assert (0);
3035}
3036
3037
3038/**
3039 * Generic error handler, called with the appropriate
3040 * error code and the same closure specified at the creation of
3041 * the message queue.
3042 * Not every message queue implementation supports an error handler.
3043 *
3044 * @param cls our `struct ReceiverAddress`
3045 * @param error error code
3046 */
3047static void
3048mq_error (void *cls, enum GNUNET_MQ_Error error)
3049{
3050 struct ReceiverAddress *receiver = cls;
3051
3052 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3053 "MQ error in queue to %s: %d\n",
3054 GNUNET_i2s (&receiver->target),
3055 (int) error);
3056 receiver_destroy (receiver);
3057}
3058
3059
3060/**
3061 * Setup the MQ for the @a receiver. If a queue exists,
3062 * the existing one is destroyed. Then the MTU is
3063 * recalculated and a fresh queue is initialized.
3064 *
3065 * @param receiver receiver to setup MQ for
3066 */
3067static void
3068setup_receiver_mq (struct ReceiverAddress *receiver)
3069{
3070 size_t base_mtu;
3071
3072 /*if (NULL != receiver->kx_qh)
3073 {
3074 GNUNET_TRANSPORT_communicator_mq_del (receiver->kx_qh);
3075 receiver->kx_qh = NULL;
3076 }
3077 if (NULL != receiver->d_qh)
3078 {
3079 GNUNET_TRANSPORT_communicator_mq_del (receiver->d_qh);
3080 receiver->d_qh = NULL;
3081 }*/
3082 // GNUNET_assert (NULL == receiver->mq);
3083 switch (receiver->address->sa_family)
3084 {
3085 case AF_INET:
3086 base_mtu = 1480 /* Ethernet MTU, 1500 - Ethernet header - VLAN tag */
3087 - sizeof(struct GNUNET_TUN_IPv4Header) /* 20 */
3088 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
3089 break;
3090
3091 case AF_INET6:
3092 base_mtu = 1280 /* Minimum MTU required by IPv6 */
3093 - sizeof(struct GNUNET_TUN_IPv6Header) /* 40 */
3094 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
3095 break;
3096
3097 default:
3098 GNUNET_assert (0);
3099 break;
3100 }
3101 /* MTU based on full KX messages */
3102 receiver->kx_mtu = base_mtu - sizeof(struct InitialKX) /* 48 */
3103 - sizeof(struct UDPConfirmation); /* 104 */
3104 /* MTU based on BOXed messages */
3105 receiver->d_mtu = base_mtu - sizeof(struct UDPBox);
3106
3107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3108 "Setting up MQs and QHs\n");
3109 /* => Effective MTU for CORE will range from 1080 (IPv6 + KX) to
3110 1404 (IPv4 + Box) bytes, depending on circumstances... */
3111 if (NULL == receiver->kx_mq)
3112 receiver->kx_mq = GNUNET_MQ_queue_for_callbacks (&mq_send_kx,
3113 &mq_destroy_kx,
3114 &mq_cancel,
3115 receiver,
3116 NULL,
3117 &mq_error,
3118 receiver);
3119 if (NULL == receiver->d_mq)
3120 receiver->d_mq = GNUNET_MQ_queue_for_callbacks (&mq_send_d,
3121 &mq_destroy_d,
3122 &mq_cancel,
3123 receiver,
3124 NULL,
3125 &mq_error,
3126 receiver);
3127
3128 receiver->kx_qh =
3129 GNUNET_TRANSPORT_communicator_mq_add (ch,
3130 &receiver->target,
3131 receiver->foreign_addr,
3132 receiver->kx_mtu,
3133 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
3134 0, /* Priority */
3135 receiver->nt,
3136 GNUNET_TRANSPORT_CS_OUTBOUND,
3137 receiver->kx_mq);
3138 receiver->d_qh =
3139 GNUNET_TRANSPORT_communicator_mq_add (ch,
3140 &receiver->target,
3141 receiver->foreign_addr,
3142 receiver->d_mtu,
3143 0, /* Initialize with 0 acks */
3144 1, /* Priority */
3145 receiver->nt,
3146 GNUNET_TRANSPORT_CS_OUTBOUND,
3147 receiver->d_mq);
3148
3149}
3150
3151
3152/**
3153 * Function called by the transport service to initialize a
3154 * message queue given address information about another peer.
3155 * If and when the communication channel is established, the
3156 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
3157 * to notify the service that the channel is now up. It is
3158 * the responsibility of the communicator to manage sane
3159 * retries and timeouts for any @a peer/@a address combination
3160 * provided by the transport service. Timeouts and retries
3161 * do not need to be signalled to the transport service.
3162 *
3163 * @param cls closure
3164 * @param peer identity of the other peer
3165 * @param address where to send the message, human-readable
3166 * communicator-specific format, 0-terminated, UTF-8
3167 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is
3168 * invalid
3169 */
3170static int
3171mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
3172{
3173 struct ReceiverAddress *receiver;
3174 const char *path;
3175 struct sockaddr *in;
3176 socklen_t in_len;
3177
3178 if (0 != strncmp (address,
3179 COMMUNICATOR_ADDRESS_PREFIX "-",
3180 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
3181 {
3182 GNUNET_break_op (0);
3183 return GNUNET_SYSERR;
3184 }
3185 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
3186 in = udp_address_to_sockaddr (path, &in_len);
3187
3188 receiver = GNUNET_new (struct ReceiverAddress);
3189 receiver->address = in;
3190 receiver->address_len = in_len;
3191 receiver->target = *peer;
3192 receiver->nt = GNUNET_NT_scanner_get_type (is, in, in_len);
3193 (void) GNUNET_CONTAINER_multipeermap_put (
3194 receivers,
3195 &receiver->target,
3196 receiver,
3197 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3198 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3199 "Added %s to receivers\n",
3200 GNUNET_i2s_full (&receiver->target));
3201 receiver->timeout =
3202 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3203 receiver->hn = GNUNET_CONTAINER_heap_insert (receivers_heap,
3204 receiver,
3205 receiver->timeout.abs_value_us);
3206 GNUNET_STATISTICS_set (stats,
3207 "# receivers active",
3208 GNUNET_CONTAINER_multipeermap_size (receivers),
3209 GNUNET_NO);
3210 receiver->foreign_addr =
3211 sockaddr_to_udpaddr_string (receiver->address, receiver->address_len);
3212 setup_receiver_mq (receiver);
3213 if (NULL == timeout_task)
3214 timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL);
3215 return GNUNET_OK;
3216}
3217
3218
3219/**
3220 * Iterator over all receivers to clean up.
3221 *
3222 * @param cls NULL
3223 * @param target unused
3224 * @param value the queue to destroy
3225 * @return #GNUNET_OK to continue to iterate
3226 */
3227static int
3228get_receiver_delete_it (void *cls,
3229 const struct GNUNET_PeerIdentity *target,
3230 void *value)
3231{
3232 struct ReceiverAddress *receiver = value;
3233
3234 (void) cls;
3235 (void) target;
3236 receiver_destroy (receiver);
3237 return GNUNET_OK;
3238}
3239
3240
3241/**
3242 * Iterator over all senders to clean up.
3243 *
3244 * @param cls NULL
3245 * @param target unused
3246 * @param value the queue to destroy
3247 * @return #GNUNET_OK to continue to iterate
3248 */
3249static int
3250get_sender_delete_it (void *cls,
3251 const struct GNUNET_PeerIdentity *target,
3252 void *value)
3253{
3254 struct SenderAddress *sender = value;
3255
3256 (void) cls;
3257 (void) target;
3258
3259 if (NULL != sender->kce_task_rekey)
3260 {
3261 GNUNET_SCHEDULER_cancel (sender->kce_task_rekey);
3262 sender->kce_task_rekey = NULL;
3263 }
3264 if (NULL != sender->kce_task)
3265 {
3266 GNUNET_SCHEDULER_cancel (sender->kce_task);
3267 sender->kce_task = NULL;
3268 }
3269
3270 sender_destroy (sender);
3271 return GNUNET_OK;
3272}
3273
3274
3275/**
3276 * Shutdown the UNIX communicator.
3277 *
3278 * @param cls NULL (always)
3279 */
3280static void
3281do_shutdown (void *cls)
3282{
3283 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3284 "do_shutdown\n");
3285 if (NULL != nat)
3286 {
3287 GNUNET_NAT_unregister (nat);
3288 nat = NULL;
3289 }
3290 while (NULL != bi_head)
3291 bi_destroy (bi_head);
3292 if (NULL != broadcast_task)
3293 {
3294 GNUNET_SCHEDULER_cancel (broadcast_task);
3295 broadcast_task = NULL;
3296 }
3297 if (NULL != timeout_task)
3298 {
3299 GNUNET_SCHEDULER_cancel (timeout_task);
3300 timeout_task = NULL;
3301 }
3302 if (NULL != read_task)
3303 {
3304 GNUNET_SCHEDULER_cancel (read_task);
3305 read_task = NULL;
3306 }
3307 if (NULL != udp_sock)
3308 {
3309 GNUNET_break (GNUNET_OK ==
3310 GNUNET_NETWORK_socket_close (udp_sock));
3311 udp_sock = NULL;
3312 }
3313 GNUNET_CONTAINER_multipeermap_iterate (receivers,
3314 &get_receiver_delete_it,
3315 NULL);
3316 GNUNET_CONTAINER_multipeermap_destroy (receivers);
3317 GNUNET_CONTAINER_multipeermap_iterate (senders,
3318 &get_sender_delete_it,
3319 NULL);
3320 GNUNET_CONTAINER_multipeermap_destroy (senders);
3321 GNUNET_CONTAINER_multishortmap_destroy (key_cache);
3322 GNUNET_CONTAINER_heap_destroy (senders_heap);
3323 GNUNET_CONTAINER_heap_destroy (receivers_heap);
3324 if (NULL != timeout_task)
3325 {
3326 GNUNET_SCHEDULER_cancel (timeout_task);
3327 timeout_task = NULL;
3328 }
3329 if (NULL != ch)
3330 {
3331 GNUNET_TRANSPORT_communicator_disconnect (ch);
3332 ch = NULL;
3333 }
3334 if (NULL != ah)
3335 {
3336 GNUNET_TRANSPORT_application_done (ah);
3337 ah = NULL;
3338 }
3339 if (NULL != stats)
3340 {
3341 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3342 stats = NULL;
3343 }
3344 if (NULL != my_private_key)
3345 {
3346 GNUNET_free (my_private_key);
3347 my_private_key = NULL;
3348 }
3349 if (NULL != is)
3350 {
3351 GNUNET_NT_scanner_done (is);
3352 is = NULL;
3353 }
3354 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3355 "do_shutdown finished\n");
3356}
3357
3358
3359/**
3360 * Function called when the transport service has received a
3361 * backchannel message for this communicator (!) via a different return
3362 * path. Should be an acknowledgement.
3363 *
3364 * @param cls closure, NULL
3365 * @param sender which peer sent the notification
3366 * @param msg payload
3367 */
3368static void
3369enc_notify_cb (void *cls,
3370 const struct GNUNET_PeerIdentity *sender,
3371 const struct GNUNET_MessageHeader *msg)
3372{
3373 const struct UDPAck *ack;
3374
3375 (void) cls;
3376 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3377 "Storing UDPAck received from backchannel from %s\n",
3378 GNUNET_i2s_full (sender));
3379 if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK) ||
3380 (ntohs (msg->size) != sizeof(struct UDPAck)))
3381 {
3382 GNUNET_break_op (0);
3383 return;
3384 }
3385 ack = (const struct UDPAck *) msg;
3386 GNUNET_CONTAINER_multipeermap_get_multiple (receivers,
3387 sender,
3388 &handle_ack,
3389 (void *) ack);
3390}
3391
3392
3393/**
3394 * Signature of the callback passed to #GNUNET_NAT_register() for
3395 * a function to call whenever our set of 'valid' addresses changes.
3396 *
3397 * @param cls closure
3398 * @param app_ctx[in,out] location where the app can store stuff
3399 * on add and retrieve it on remove
3400 * @param add_remove #GNUNET_YES to add a new public IP address,
3401 * #GNUNET_NO to remove a previous (now invalid) one
3402 * @param ac address class the address belongs to
3403 * @param addr either the previous or the new public IP address
3404 * @param addrlen actual length of the @a addr
3405 */
3406static void
3407nat_address_cb (void *cls,
3408 void **app_ctx,
3409 int add_remove,
3410 enum GNUNET_NAT_AddressClass ac,
3411 const struct sockaddr *addr,
3412 socklen_t addrlen)
3413{
3414 char *my_addr;
3415 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
3416
3417 if (GNUNET_YES == add_remove)
3418 {
3419 enum GNUNET_NetworkType nt;
3420
3421 GNUNET_asprintf (&my_addr,
3422 "%s-%s",
3423 COMMUNICATOR_ADDRESS_PREFIX,
3424 GNUNET_a2s (addr, addrlen));
3425 nt = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3426 ai =
3427 GNUNET_TRANSPORT_communicator_address_add (ch,
3428 my_addr,
3429 nt,
3430 GNUNET_TIME_UNIT_FOREVER_REL);
3431 GNUNET_free (my_addr);
3432 *app_ctx = ai;
3433 }
3434 else
3435 {
3436 ai = *app_ctx;
3437 GNUNET_TRANSPORT_communicator_address_remove (ai);
3438 *app_ctx = NULL;
3439 }
3440}
3441
3442
3443/**
3444 * Broadcast our presence on one of our interfaces.
3445 *
3446 * @param cls a `struct BroadcastInterface`
3447 */
3448static void
3449ifc_broadcast (void *cls)
3450{
3451 struct BroadcastInterface *bi = cls;
3452 struct GNUNET_TIME_Relative delay;
3453
3454 delay = BROADCAST_FREQUENCY;
3455 delay.rel_value_us =
3456 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, delay.rel_value_us);
3457 bi->broadcast_task =
3458 GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY, &ifc_broadcast, bi);
3459
3460 switch (bi->sa->sa_family)
3461 {
3462 case AF_INET: {
3463 static int yes = 1;
3464 static int no = 0;
3465 ssize_t sent;
3466
3467 if (GNUNET_OK !=
3468 GNUNET_NETWORK_socket_setsockopt (udp_sock,
3469 SOL_SOCKET,
3470 SO_BROADCAST,
3471 &yes,
3472 sizeof(int)))
3473 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3474 "setsockopt");
3475 sent = GNUNET_NETWORK_socket_sendto (udp_sock,
3476 &bi->bcm,
3477 sizeof(bi->bcm),
3478 bi->ba,
3479 bi->salen);
3480 if (-1 == sent)
3481 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3482 "sendto");
3483 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
3484 SOL_SOCKET,
3485 SO_BROADCAST,
3486 &no,
3487 sizeof(int)))
3488 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3489 "setsockopt");
3490 break;
3491 }
3492
3493 case AF_INET6: {
3494 ssize_t sent;
3495 struct sockaddr_in6 dst;
3496
3497 dst.sin6_family = AF_INET6;
3498 dst.sin6_port = htons (my_port);
3499 dst.sin6_addr = bi->mcreq.ipv6mr_multiaddr;
3500 dst.sin6_scope_id = ((struct sockaddr_in6 *) bi->ba)->sin6_scope_id;
3501
3502 sent = GNUNET_NETWORK_socket_sendto (udp_sock,
3503 &bi->bcm,
3504 sizeof(bi->bcm),
3505 (const struct sockaddr *) &dst,
3506 sizeof(dst));
3507 if (-1 == sent)
3508 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
3509 break;
3510 }
3511
3512 default:
3513 GNUNET_break (0);
3514 break;
3515 }
3516}
3517
3518
3519/**
3520 * Callback function invoked for each interface found.
3521 * Activates/deactivates broadcast interfaces.
3522 *
3523 * @param cls NULL
3524 * @param name name of the interface (can be NULL for unknown)
3525 * @param isDefault is this presumably the default interface
3526 * @param addr address of this interface (can be NULL for unknown or unassigned)
3527 * @param broadcast_addr the broadcast address (can be NULL for unknown or
3528 * unassigned)
3529 * @param netmask the network mask (can be NULL for unknown or unassigned)
3530 * @param addrlen length of the address
3531 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
3532 */
3533static int
3534iface_proc (void *cls,
3535 const char *name,
3536 int isDefault,
3537 const struct sockaddr *addr,
3538 const struct sockaddr *broadcast_addr,
3539 const struct sockaddr *netmask,
3540 socklen_t addrlen)
3541{
3542 struct BroadcastInterface *bi;
3543 enum GNUNET_NetworkType network;
3544 struct UdpBroadcastSignature ubs;
3545
3546 (void) cls;
3547 (void) netmask;
3548 if (NULL == addr)
3549 return GNUNET_YES; /* need to know our address! */
3550 network = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3551 if (GNUNET_NT_LOOPBACK == network)
3552 {
3553 /* Broadcasting on loopback does not make sense */
3554 return GNUNET_YES;
3555 }
3556 for (bi = bi_head; NULL != bi; bi = bi->next)
3557 {
3558 if ((bi->salen == addrlen) && (0 == memcmp (addr, bi->sa, addrlen)))
3559 {
3560 bi->found = GNUNET_YES;
3561 return GNUNET_OK;
3562 }
3563 }
3564
3565 if ((AF_INET6 == addr->sa_family) && (NULL == broadcast_addr))
3566 return GNUNET_OK; /* broadcast_addr is required for IPv6! */
3567 if ((AF_INET6 == addr->sa_family) && (GNUNET_YES != have_v6_socket))
3568 return GNUNET_OK; /* not using IPv6 */
3569
3570 bi = GNUNET_new (struct BroadcastInterface);
3571 bi->sa = GNUNET_memdup (addr,
3572 addrlen);
3573 if ( (NULL != broadcast_addr) &&
3574 (addrlen == sizeof (struct sockaddr_in)) )
3575 {
3576 struct sockaddr_in *ba;
3577
3578 ba = GNUNET_memdup (broadcast_addr,
3579 addrlen);
3580 ba->sin_port = htons (2086); /* always GNUnet port, ignore configuration! */
3581 bi->ba = (struct sockaddr *) ba;
3582 }
3583 bi->salen = addrlen;
3584 bi->found = GNUNET_YES;
3585 bi->bcm.sender = my_identity;
3586 ubs.purpose.purpose = htonl (GNUNET_SIGNATURE_COMMUNICATOR_UDP_BROADCAST);
3587 ubs.purpose.size = htonl (sizeof(ubs));
3588 ubs.sender = my_identity;
3589 GNUNET_CRYPTO_hash (addr, addrlen, &ubs.h_address);
3590 GNUNET_CRYPTO_eddsa_sign (my_private_key,
3591 &ubs,
3592 &bi->bcm.sender_sig);
3593 if (NULL != bi->ba)
3594 {
3595 bi->broadcast_task = GNUNET_SCHEDULER_add_now (&ifc_broadcast, bi);
3596 GNUNET_CONTAINER_DLL_insert (bi_head, bi_tail, bi);
3597 }
3598 if ((AF_INET6 == addr->sa_family) && (NULL != broadcast_addr))
3599 {
3600 /* Create IPv6 multicast request */
3601 const struct sockaddr_in6 *s6 =
3602 (const struct sockaddr_in6 *) broadcast_addr;
3603
3604 GNUNET_assert (
3605 1 == inet_pton (AF_INET6, "FF05::13B", &bi->mcreq.ipv6mr_multiaddr));
3606
3607 /* http://tools.ietf.org/html/rfc2553#section-5.2:
3608 *
3609 * IPV6_JOIN_GROUP
3610 *
3611 * Join a multicast group on a specified local interface. If the
3612 * interface index is specified as 0, the kernel chooses the local
3613 * interface. For example, some kernels look up the multicast
3614 * group in the normal IPv6 routing table and using the resulting
3615 * interface; we do this for each interface, so no need to use
3616 * zero (anymore...).
3617 */bi->mcreq.ipv6mr_interface = s6->sin6_scope_id;
3618
3619 /* Join the multicast group */
3620 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
3621 IPPROTO_IPV6,
3622 IPV6_JOIN_GROUP,
3623 &bi->mcreq,
3624 sizeof(bi->mcreq)))
3625 {
3626 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
3627 }
3628 }
3629 return GNUNET_OK;
3630}
3631
3632
3633/**
3634 * Scan interfaces to broadcast our presence on the LAN.
3635 *
3636 * @param cls NULL, unused
3637 */
3638static void
3639do_broadcast (void *cls)
3640{
3641 struct BroadcastInterface *bin;
3642
3643 (void) cls;
3644 for (struct BroadcastInterface *bi = bi_head; NULL != bi; bi = bi->next)
3645 bi->found = GNUNET_NO;
3646 GNUNET_OS_network_interfaces_list (&iface_proc, NULL);
3647 for (struct BroadcastInterface *bi = bi_head; NULL != bi; bi = bin)
3648 {
3649 bin = bi->next;
3650 if (GNUNET_NO == bi->found)
3651 bi_destroy (bi);
3652 }
3653 broadcast_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY,
3654 &do_broadcast,
3655 NULL);
3656}
3657
3658
3659/**
3660 * Setup communicator and launch network interactions.
3661 *
3662 * @param cls NULL (always)
3663 * @param args remaining command-line arguments
3664 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
3665 * @param c configuration
3666 */
3667static void
3668run (void *cls,
3669 char *const *args,
3670 const char *cfgfile,
3671 const struct GNUNET_CONFIGURATION_Handle *c)
3672{
3673 char *bindto;
3674 struct sockaddr *in;
3675 socklen_t in_len;
3676 struct sockaddr_storage in_sto;
3677 socklen_t sto_len;
3678
3679 (void) cls;
3680 cfg = c;
3681 if (GNUNET_OK !=
3682 GNUNET_CONFIGURATION_get_value_string (cfg,
3683 COMMUNICATOR_CONFIG_SECTION,
3684 "BINDTO",
3685 &bindto))
3686 {
3687 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3688 COMMUNICATOR_CONFIG_SECTION,
3689 "BINDTO");
3690 return;
3691 }
3692
3693 if (GNUNET_OK !=
3694 GNUNET_CONFIGURATION_get_value_time (cfg,
3695 COMMUNICATOR_CONFIG_SECTION,
3696 "REKEY_INTERVAL",
3697 &rekey_interval))
3698 rekey_interval = DEFAULT_REKEY_TIME_INTERVAL;
3699
3700 if (GNUNET_OK !=
3701 GNUNET_CONFIGURATION_get_value_size (cfg,
3702 COMMUNICATOR_CONFIG_SECTION,
3703 "REKEY_MAX_BYTES",
3704 &rekey_max_bytes))
3705 rekey_max_bytes = DEFAULT_REKEY_MAX_BYTES;
3706
3707 in = udp_address_to_sockaddr (bindto, &in_len);
3708 if (NULL == in)
3709 {
3710 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3711 "Failed to setup UDP socket address with path `%s'\n",
3712 bindto);
3713 GNUNET_free (bindto);
3714 return;
3715 }
3716 udp_sock =
3717 GNUNET_NETWORK_socket_create (in->sa_family,
3718 SOCK_DGRAM,
3719 IPPROTO_UDP);
3720 if (NULL == udp_sock)
3721 {
3722 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
3723 GNUNET_free (in);
3724 GNUNET_free (bindto);
3725 return;
3726 }
3727 if (AF_INET6 == in->sa_family)
3728 have_v6_socket = GNUNET_YES;
3729 if (GNUNET_OK !=
3730 GNUNET_NETWORK_socket_bind (udp_sock,
3731 in,
3732 in_len))
3733 {
3734 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
3735 "bind",
3736 bindto);
3737 GNUNET_NETWORK_socket_close (udp_sock);
3738 udp_sock = NULL;
3739 GNUNET_free (in);
3740 GNUNET_free (bindto);
3741 return;
3742 }
3743
3744 /* We might have bound to port 0, allowing the OS to figure it out;
3745 thus, get the real IN-address from the socket */
3746 sto_len = sizeof(in_sto);
3747 if (0 != getsockname (GNUNET_NETWORK_get_fd (udp_sock),
3748 (struct sockaddr *) &in_sto,
3749 &sto_len))
3750 {
3751 memcpy (&in_sto, in, in_len);
3752 sto_len = in_len;
3753 }
3754 GNUNET_free (in);
3755 GNUNET_free (bindto);
3756 in = (struct sockaddr *) &in_sto;
3757 in_len = sto_len;
3758 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3759 "Bound to `%s'\n",
3760 GNUNET_a2s ((const struct sockaddr *) &in_sto, sto_len));
3761 switch (in->sa_family)
3762 {
3763 case AF_INET:
3764 my_port = ntohs (((struct sockaddr_in *) in)->sin_port);
3765 break;
3766
3767 case AF_INET6:
3768 my_port = ntohs (((struct sockaddr_in6 *) in)->sin6_port);
3769 break;
3770
3771 default:
3772 GNUNET_break (0);
3773 my_port = 0;
3774 }
3775 stats = GNUNET_STATISTICS_create ("C-UDP", cfg);
3776 senders = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
3777 receivers = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
3778 senders_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3779 receivers_heap =
3780 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3781 key_cache = GNUNET_CONTAINER_multishortmap_create (1024, GNUNET_YES);
3782 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
3783 is = GNUNET_NT_scanner_init ();
3784 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
3785 if (NULL == my_private_key)
3786 {
3787 GNUNET_log (
3788 GNUNET_ERROR_TYPE_ERROR,
3789 _ (
3790 "Transport service is lacking key configuration settings. Exiting.\n"));
3791 GNUNET_SCHEDULER_shutdown ();
3792 return;
3793 }
3794 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
3795 /* start reading */
3796 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3797 udp_sock,
3798 &sock_read,
3799 NULL);
3800 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
3801 COMMUNICATOR_CONFIG_SECTION,
3802 COMMUNICATOR_ADDRESS_PREFIX,
3803 GNUNET_TRANSPORT_CC_UNRELIABLE,
3804 &mq_init,
3805 NULL,
3806 &enc_notify_cb,
3807 NULL);
3808 if (NULL == ch)
3809 {
3810 GNUNET_break (0);
3811 GNUNET_SCHEDULER_shutdown ();
3812 return;
3813 }
3814 ah = GNUNET_TRANSPORT_application_init (cfg);
3815 if (NULL == ah)
3816 {
3817 GNUNET_break (0);
3818 GNUNET_SCHEDULER_shutdown ();
3819 return;
3820 }
3821 /* start broadcasting */
3822 if (GNUNET_YES !=
3823 GNUNET_CONFIGURATION_get_value_yesno (cfg,
3824 COMMUNICATOR_CONFIG_SECTION,
3825 "DISABLE_BROADCAST"))
3826 {
3827 broadcast_task = GNUNET_SCHEDULER_add_now (&do_broadcast, NULL);
3828 }
3829 nat = GNUNET_NAT_register (cfg,
3830 COMMUNICATOR_CONFIG_SECTION,
3831 IPPROTO_UDP,
3832 1 /* one address */,
3833 (const struct sockaddr **) &in,
3834 &in_len,
3835 &nat_address_cb,
3836 NULL /* FIXME: support reversal: #5529 */,
3837 NULL /* closure */);
3838}
3839
3840
3841/**
3842 * The main function for the UNIX communicator.
3843 *
3844 * @param argc number of arguments from the command line
3845 * @param argv command line arguments
3846 * @return 0 ok, 1 on error
3847 */
3848int
3849main (int argc, char *const *argv)
3850{
3851 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
3852 GNUNET_GETOPT_OPTION_END
3853 };
3854 int ret;
3855
3856 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
3857 return 2;
3858
3859 ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
3860 argv,
3861 "gnunet-communicator-udp",
3862 _ ("GNUnet UDP communicator"),
3863 options,
3864 &run,
3865 NULL))
3866 ? 0
3867 : 1;
3868 GNUNET_free_nz ((void *) argv);
3869 return ret;
3870}
3871
3872
3873/* 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 a7e2a8c04..000000000
--- a/src/transport/gnunet-service-tng.c
+++ /dev/null
@@ -1,10333 +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 messages we acknowledge together in one
86 * cumulative ACK. Larger values may save a bit of bandwidth.
87 */
88#define MAX_CUMMULATIVE_ACKS 64
89
90/**
91 * What is the 1:n chance that we send a Flow control response when
92 * receiving a flow control message that did not change anything for
93 * us? Basically, this is used in the case where both peers are stuck
94 * on flow control (no window changes), but one might continue sending
95 * flow control messages to the other peer as the first FC message
96 * when things stalled got lost, and then subsequently the other peer
97 * does *usually* not respond as nothing changed. So to ensure that
98 * eventually the FC messages stop, we do send with 1/8th probability
99 * an FC message even if nothing changed. That prevents one peer
100 * being stuck in sending (useless) FC messages "forever".
101 */
102#define FC_NO_CHANGE_REPLY_PROBABILITY 8
103
104/**
105 * What is the size we assume for a read operation in the
106 * absence of an MTU for the purpose of flow control?
107 */
108#define IN_PACKET_SIZE_WITHOUT_MTU 128
109
110/**
111 * Number of slots we keep of historic data for computation of
112 * goodput / message loss ratio.
113 */
114#define GOODPUT_AGING_SLOTS 4
115
116/**
117 * How big is the flow control window size by default;
118 * limits per-neighbour RAM utilization.
119 */
120#define DEFAULT_WINDOW_SIZE (128 * 1024)
121
122/**
123 * For how many incoming connections do we try to create a
124 * virtual link for (at the same time!). This does NOT
125 * limit the number of incoming connections, just the number
126 * for which we are actively trying to find working addresses
127 * in the absence (!) of our own applications wanting the
128 * link to go up.
129 */
130#define MAX_INCOMING_REQUEST 16
131
132/**
133 * Maximum number of peers we select for forwarding DVInit
134 * messages at the same time (excluding initiator).
135 */
136#define MAX_DV_DISCOVERY_SELECTION 16
137
138/**
139 * Window size. How many messages to the same target do we pass
140 * to CORE without a RECV_OK in between? Small values limit
141 * thoughput, large values will increase latency.
142 *
143 * FIXME-OPTIMIZE: find out what good values are experimentally,
144 * maybe set adaptively (i.e. to observed available bandwidth).
145 */
146#define RECV_WINDOW_SIZE 4
147
148/**
149 * Minimum number of hops we should forward DV learn messages
150 * even if they are NOT useful for us in hope of looping
151 * back to the initiator?
152 *
153 * FIXME: allow initiator some control here instead?
154 */
155#define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
156
157/**
158 * Maximum DV distance allowed ever.
159 */
160#define MAX_DV_HOPS_ALLOWED 16
161
162/**
163 * Maximum number of DV learning activities we may
164 * have pending at the same time.
165 */
166#define MAX_DV_LEARN_PENDING 64
167
168/**
169 * Maximum number of DV paths we keep simultaneously to the same target.
170 */
171#define MAX_DV_PATHS_TO_TARGET 3
172
173/**
174 * If a queue delays the next message by more than this number
175 * of seconds we log a warning. Note: this is for testing,
176 * the value chosen here might be too aggressively low!
177 */
178#define DELAY_WARN_THRESHOLD \
179 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
180
181/**
182 * If a DVBox could not be forwarded after this number of
183 * seconds we drop it.
184 */
185#define DV_FORWARD_TIMEOUT \
186 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
187
188/**
189 * We only consider queues as "quality" connections when
190 * suppressing the generation of DV initiation messages if
191 * the latency of the queue is below this threshold.
192 */
193#define DV_QUALITY_RTT_THRESHOLD \
194 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
195
196/**
197 * How long do we consider a DV path valid if we see no
198 * further updates on it? Note: the value chosen here might be too low!
199 */
200#define DV_PATH_VALIDITY_TIMEOUT \
201 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
202
203/**
204 * How long do we cache backchannel (struct Backtalker) information
205 * after a backchannel goes inactive?
206 */
207#define BACKCHANNEL_INACTIVITY_TIMEOUT \
208 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
209
210/**
211 * How long before paths expire would we like to (re)discover DV paths? Should
212 * be below #DV_PATH_VALIDITY_TIMEOUT.
213 */
214#define DV_PATH_DISCOVERY_FREQUENCY \
215 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
216
217/**
218 * How long are ephemeral keys valid?
219 */
220#define EPHEMERAL_VALIDITY \
221 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
222
223/**
224 * How long do we keep partially reassembled messages around before giving up?
225 */
226#define REASSEMBLY_EXPIRATION \
227 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
228
229/**
230 * What is the fastest rate at which we send challenges *if* we keep learning
231 * an address (gossip, DHT, etc.)?
232 */
233#define FAST_VALIDATION_CHALLENGE_FREQ \
234 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
235
236/**
237 * What is the slowest rate at which we send challenges?
238 */
239#define MAX_VALIDATION_CHALLENGE_FREQ \
240 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
241
242/**
243 * How long until we forget about historic accumulators and thus
244 * reset the ACK counter? Should exceed the maximum time an
245 * active connection experiences without an ACK.
246 */
247#define ACK_CUMMULATOR_TIMEOUT \
248 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
249
250/**
251 * What is the non-randomized base frequency at which we
252 * would initiate DV learn messages?
253 */
254#define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
255
256/**
257 * How many good connections (confirmed, bi-directional, not DV)
258 * do we need to have to suppress initiating DV learn messages?
259 */
260#define DV_LEARN_QUALITY_THRESHOLD 100
261
262/**
263 * When do we forget an invalid address for sure?
264 */
265#define MAX_ADDRESS_VALID_UNTIL \
266 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
267
268/**
269 * How long do we consider an address valid if we just checked?
270 */
271#define ADDRESS_VALIDATION_LIFETIME \
272 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
273
274/**
275 * What is the maximum frequency at which we do address validation?
276 * A random value between 0 and this value is added when scheduling
277 * the #validation_task (both to ensure we do not validate too often,
278 * and to randomize a bit).
279 */
280#define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
281
282/**
283 * How many network RTTs before an address validation expires should we begin
284 * trying to revalidate? (Note that the RTT used here is the one that we
285 * experienced during the last validation, not necessarily the latest RTT
286 * observed).
287 */
288#define VALIDATION_RTT_BUFFER_FACTOR 3
289
290/**
291 * How many messages can we have pending for a given communicator
292 * process before we start to throttle that communicator?
293 *
294 * Used if a communicator might be CPU-bound and cannot handle the traffic.
295 */
296#define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
297
298/**
299 * How many messages can we have pending for a given queue (queue to
300 * a particular peer via a communicator) process before we start to
301 * throttle that queue?
302 */
303#define QUEUE_LENGTH_LIMIT 32
304
305
306GNUNET_NETWORK_STRUCT_BEGIN
307
308/**
309 * Unique identifier we attach to a message.
310 */
311struct MessageUUIDP
312{
313 /**
314 * Unique value, generated by incrementing the
315 * `message_uuid_ctr` of `struct Neighbour`.
316 */
317 uint64_t uuid GNUNET_PACKED;
318};
319
320
321/**
322 * Unique identifier to map an acknowledgement to a transmission.
323 */
324struct AcknowledgementUUIDP
325{
326 /**
327 * The UUID value.
328 */
329 struct GNUNET_Uuid value;
330};
331
332/**
333 * Outer layer of an encapsulated backchannel message.
334 */
335struct TransportBackchannelEncapsulationMessage
336{
337 /**
338 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
339 */
340 struct GNUNET_MessageHeader header;
341
342 /* Followed by *another* message header which is the message to
343 the communicator */
344
345 /* Followed by a 0-terminated name of the communicator */
346};
347
348
349/**
350 * Body by which a peer confirms that it is using an ephemeral key.
351 */
352struct EphemeralConfirmationPS
353{
354 /**
355 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
356 */
357 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
358
359 /**
360 * How long is this signature over the ephemeral key valid?
361 *
362 * Note that the receiver MUST IGNORE the absolute time, and only interpret
363 * the value as a mononic time and reject "older" values than the last one
364 * observed. This is necessary as we do not want to require synchronized
365 * clocks and may not have a bidirectional communication channel.
366 *
367 * Even with this, there is no real guarantee against replay achieved here,
368 * unless the latest timestamp is persisted. While persistence should be
369 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
370 * communicators must protect against replay attacks when using backchannel
371 * communication!
372 */
373 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
374
375 /**
376 * Target's peer identity.
377 */
378 struct GNUNET_PeerIdentity target;
379
380 /**
381 * Ephemeral key setup by the sender for @e target, used
382 * to encrypt the payload.
383 */
384 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
385};
386
387
388/**
389 * Plaintext of the variable-size payload that is encrypted
390 * within a `struct TransportBackchannelEncapsulationMessage`
391 */
392struct TransportDVBoxPayloadP
393{
394 /**
395 * Sender's peer identity.
396 */
397 struct GNUNET_PeerIdentity sender;
398
399 /**
400 * Signature of the sender over an
401 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
402 */
403 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
404
405 /**
406 * Current monotonic time of the sending transport service. Used to
407 * detect replayed messages. Note that the receiver should remember
408 * a list of the recently seen timestamps and only reject messages
409 * if the timestamp is in the list, or the list is "full" and the
410 * timestamp is smaller than the lowest in the list.
411 *
412 * Like the @e ephemeral_validity, the list of timestamps per peer should be
413 * persisted to guard against replays after restarts.
414 */
415 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
416
417 /* Followed by a `struct GNUNET_MessageHeader` with a message
418 for the target peer */
419};
420
421
422/**
423 * Outer layer of an encapsulated unfragmented application message sent
424 * over an unreliable channel.
425 */
426struct TransportReliabilityBoxMessage
427{
428 /**
429 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
430 */
431 struct GNUNET_MessageHeader header;
432
433 /**
434 * Number of messages still to be sent before a commulative
435 * ACK is requested. Zero if an ACK is requested immediately.
436 * In NBO. Note that the receiver may send the ACK faster
437 * if it believes that is reasonable.
438 */
439 uint32_t ack_countdown GNUNET_PACKED;
440
441 /**
442 * Unique ID of the message used for signalling receipt of
443 * messages sent over possibly unreliable channels. Should
444 * be a random.
445 */
446 struct AcknowledgementUUIDP ack_uuid;
447};
448
449
450/**
451 * Acknowledgement payload.
452 */
453struct TransportCummulativeAckPayloadP
454{
455 /**
456 * How long was the ACK delayed for generating cumulative ACKs?
457 * Used to calculate the correct network RTT by taking the receipt
458 * time of the ack minus the transmission time of the sender minus
459 * this value.
460 */
461 struct GNUNET_TIME_RelativeNBO ack_delay;
462
463 /**
464 * UUID of a message being acknowledged.
465 */
466 struct AcknowledgementUUIDP ack_uuid;
467};
468
469
470/**
471 * Confirmation that the receiver got a
472 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
473 * confirmation may be transmitted over a completely different queue,
474 * so ACKs are identified by a combination of PID of sender and
475 * message UUID, without the queue playing any role!
476 */
477struct TransportReliabilityAckMessage
478{
479 /**
480 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
481 */
482 struct GNUNET_MessageHeader header;
483
484 /**
485 * Counter of ACKs transmitted by the sender to us. Incremented
486 * by one for each ACK, used to detect how many ACKs were lost.
487 */
488 uint32_t ack_counter GNUNET_PACKED;
489
490 /* followed by any number of `struct TransportCummulativeAckPayloadP`
491 messages providing ACKs */
492};
493
494
495/**
496 * Outer layer of an encapsulated fragmented application message.
497 */
498struct TransportFragmentBoxMessage
499{
500 /**
501 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
502 */
503 struct GNUNET_MessageHeader header;
504
505 /**
506 * Offset of this fragment in the overall message.
507 */
508 uint16_t frag_off GNUNET_PACKED;
509
510 /**
511 * Total size of the message that is being fragmented.
512 */
513 uint16_t msg_size GNUNET_PACKED;
514
515 /**
516 * Unique ID of this fragment (and fragment transmission!). Will
517 * change even if a fragment is retransmitted to make each
518 * transmission attempt unique! If a client receives a duplicate
519 * fragment (same @e frag_off for same @a msg_uuid, it must send
520 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
521 */
522 struct AcknowledgementUUIDP ack_uuid;
523
524 /**
525 * Original message ID for of the message that all the fragments
526 * belong to. Must be the same for all fragments.
527 */
528 struct MessageUUIDP msg_uuid;
529};
530
531
532/**
533 * Content signed by the initator during DV learning.
534 *
535 * The signature is required to prevent DDoS attacks. A peer sending out this
536 * message is potentially generating a lot of traffic that will go back to the
537 * initator, as peers receiving this message will try to let the initiator
538 * know that they got the message.
539 *
540 * Without this signature, an attacker could abuse this mechanism for traffic
541 * amplification, sending a lot of traffic to a peer by putting out this type
542 * of message with the victim's peer identity.
543 *
544 * Even with just a signature, traffic amplification would be possible via
545 * replay attacks. The @e monotonic_time limits such replay attacks, as every
546 * potential amplificator will check the @e monotonic_time and only respond
547 * (at most) once per message.
548 */
549struct DvInitPS
550{
551 /**
552 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
553 */
554 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
555
556 /**
557 * Time at the initiator when generating the signature.
558 *
559 * Note that the receiver MUST IGNORE the absolute time, and only interpret
560 * the value as a mononic time and reject "older" values than the last one
561 * observed. This is necessary as we do not want to require synchronized
562 * clocks and may not have a bidirectional communication channel.
563 *
564 * Even with this, there is no real guarantee against replay achieved here,
565 * unless the latest timestamp is persisted. Persistence should be
566 * provided via PEERSTORE if possible.
567 */
568 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
569
570 /**
571 * Challenge value used by the initiator to re-identify the path.
572 */
573 struct ChallengeNonceP challenge;
574};
575
576
577/**
578 * Content signed by each peer during DV learning.
579 *
580 * This assues the initiator of the DV learning operation that the hop from @e
581 * pred via the signing peer to @e succ actually exists. This makes it
582 * impossible for an adversary to supply the network with bogus routes.
583 *
584 * The @e challenge is included to provide replay protection for the
585 * initiator. This way, the initiator knows that the hop existed after the
586 * original @e challenge was first transmitted, providing a freshness metric.
587 *
588 * Peers other than the initiator that passively learn paths by observing
589 * these messages do NOT benefit from this. Here, an adversary may indeed
590 * replay old messages. Thus, passively learned paths should always be
591 * immediately marked as "potentially stale".
592 */
593struct DvHopPS
594{
595 /**
596 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
597 */
598 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
599
600 /**
601 * Identity of the previous peer on the path.
602 */
603 struct GNUNET_PeerIdentity pred;
604
605 /**
606 * Identity of the next peer on the path.
607 */
608 struct GNUNET_PeerIdentity succ;
609
610 /**
611 * Challenge value used by the initiator to re-identify the path.
612 */
613 struct ChallengeNonceP challenge;
614};
615
616
617/**
618 * An entry describing a peer on a path in a
619 * `struct TransportDVLearnMessage` message.
620 */
621struct DVPathEntryP
622{
623 /**
624 * Identity of a peer on the path.
625 */
626 struct GNUNET_PeerIdentity hop;
627
628 /**
629 * Signature of this hop over the path, of purpose
630 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
631 */
632 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
633};
634
635
636/**
637 * Internal message used by transport for distance vector learning.
638 * If @e num_hops does not exceed the threshold, peers should append
639 * themselves to the peer list and flood the message (possibly only
640 * to a subset of their neighbours to limit discoverability of the
641 * network topology). To the extend that the @e bidirectional bits
642 * are set, peers may learn the inverse paths even if they did not
643 * initiate.
644 *
645 * Unless received on a bidirectional queue and @e num_hops just
646 * zero, peers that can forward to the initator should always try to
647 * forward to the initiator.
648 */
649struct TransportDVLearnMessage
650{
651 /**
652 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
653 */
654 struct GNUNET_MessageHeader header;
655
656 /**
657 * Number of hops this messages has travelled, in NBO. Zero if
658 * sent by initiator.
659 */
660 uint16_t num_hops GNUNET_PACKED;
661
662 /**
663 * Bitmask of the last 16 hops indicating whether they are confirmed
664 * available (without DV) in both directions or not, in NBO. Used
665 * to possibly instantly learn a path in both directions. Each peer
666 * should shift this value by one to the left, and then set the
667 * lowest bit IF the current sender can be reached from it (without
668 * DV routing).
669 */
670 uint16_t bidirectional GNUNET_PACKED;
671
672 /**
673 * Peers receiving this message and delaying forwarding to other
674 * peers for any reason should increment this value by the non-network
675 * delay created by the peer.
676 */
677 struct GNUNET_TIME_RelativeNBO non_network_delay;
678
679 /**
680 * Time at the initiator when generating the signature.
681 *
682 * Note that the receiver MUST IGNORE the absolute time, and only interpret
683 * the value as a mononic time and reject "older" values than the last one
684 * observed. This is necessary as we do not want to require synchronized
685 * clocks and may not have a bidirectional communication channel.
686 *
687 * Even with this, there is no real guarantee against replay achieved here,
688 * unless the latest timestamp is persisted. Persistence should be
689 * provided via PEERSTORE if possible.
690 */
691 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
692
693 /**
694 * Signature of this hop over the path, of purpose
695 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
696 */
697 struct GNUNET_CRYPTO_EddsaSignature init_sig;
698
699 /**
700 * Identity of the peer that started this learning activity.
701 */
702 struct GNUNET_PeerIdentity initiator;
703
704 /**
705 * Challenge value used by the initiator to re-identify the path.
706 */
707 struct ChallengeNonceP challenge;
708
709 /* Followed by @e num_hops `struct DVPathEntryP` values,
710 excluding the initiator of the DV trace; the last entry is the
711 current sender; the current peer must not be included. */
712};
713
714
715/**
716 * Outer layer of an encapsulated message send over multiple hops.
717 * The path given only includes the identities of the subsequent
718 * peers, i.e. it will be empty if we are the receiver. Each
719 * forwarding peer should scan the list from the end, and if it can,
720 * forward to the respective peer. The list should then be shortened
721 * by all the entries up to and including that peer. Each hop should
722 * also increment @e total_hops to allow the receiver to get a precise
723 * estimate on the number of hops the message travelled. Senders must
724 * provide a learned path that thus should work, but intermediaries
725 * know of a shortcut, they are allowed to send the message via that
726 * shortcut.
727 *
728 * If a peer finds itself still on the list, it must drop the message.
729 *
730 * The payload of the box can only be decrypted and verified by the
731 * ultimate receiver. Intermediaries do not learn the sender's
732 * identity and the path the message has taken. However, the first
733 * hop does learn the sender as @e total_hops would be zero and thus
734 * the predecessor must be the origin (so this is not really useful
735 * for anonymization).
736 */
737struct TransportDVBoxMessage
738{
739 /**
740 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
741 */
742 struct GNUNET_MessageHeader header;
743
744 /**
745 * Number of total hops this messages travelled. In NBO.
746 * @e origin sets this to zero, to be incremented at
747 * each hop. Peers should limit the @e total_hops value
748 * they accept from other peers.
749 */
750 uint16_t total_hops GNUNET_PACKED;
751
752 /**
753 * Number of hops this messages includes. In NBO. Reduced by one
754 * or more at each hop. Peers should limit the @e num_hops value
755 * they accept from other peers.
756 */
757 uint16_t num_hops GNUNET_PACKED;
758
759 /**
760 * Ephemeral key setup by the sender for target, used to encrypt the
761 * payload. Intermediaries must not change this value.
762 */
763 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
764
765 /**
766 * We use an IV here as the @e ephemeral_key is re-used for
767 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
768 * Intermediaries must not change this value.
769 */
770 struct GNUNET_ShortHashCode iv;
771
772 /**
773 * HMAC over the ciphertext of the encrypted, variable-size body
774 * that follows. Verified via DH of target and @e ephemeral_key.
775 * Intermediaries must not change this value.
776 */
777 struct GNUNET_HashCode hmac;
778
779 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
780 excluding the @e origin and the current peer, the last must be
781 the ultimate target; if @e num_hops is zero, the receiver of this
782 message is the ultimate target. */
783
784 /* Followed by encrypted, variable-size payload, which
785 must begin with a `struct TransportDVBoxPayloadP` */
786
787 /* Followed by the actual message, which itself must not be a
788 a DV_LEARN or DV_BOX message! */
789};
790
791
792/**
793 * Message send to another peer to validate that it can indeed
794 * receive messages at a particular address.
795 */
796struct TransportValidationChallengeMessage
797{
798 /**
799 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
800 */
801 struct GNUNET_MessageHeader header;
802
803 /**
804 * Always zero.
805 */
806 uint32_t reserved GNUNET_PACKED;
807
808 /**
809 * Challenge to be signed by the receiving peer.
810 */
811 struct ChallengeNonceP challenge;
812
813 /**
814 * Timestamp of the sender, to be copied into the reply to allow
815 * sender to calculate RTT. Must be monotonically increasing!
816 */
817 struct GNUNET_TIME_AbsoluteNBO sender_time;
818};
819
820
821/**
822 * Message signed by a peer to confirm that it can indeed
823 * receive messages at a particular address.
824 */
825struct TransportValidationPS
826{
827 /**
828 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
829 */
830 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
831
832 /**
833 * How long does the sender believe the address on
834 * which the challenge was received to remain valid?
835 */
836 struct GNUNET_TIME_RelativeNBO validity_duration;
837
838 /**
839 * Challenge signed by the receiving peer.
840 */
841 struct ChallengeNonceP challenge;
842};
843
844
845/**
846 * Message send to a peer to respond to a
847 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
848 */
849struct TransportValidationResponseMessage
850{
851 /**
852 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
853 */
854 struct GNUNET_MessageHeader header;
855
856 /**
857 * Always zero.
858 */
859 uint32_t reserved GNUNET_PACKED;
860
861 /**
862 * The peer's signature matching the
863 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
864 */
865 struct GNUNET_CRYPTO_EddsaSignature signature;
866
867 /**
868 * The challenge that was signed by the receiving peer.
869 */
870 struct ChallengeNonceP challenge;
871
872 /**
873 * Original timestamp of the sender (was @code{sender_time}),
874 * copied into the reply to allow sender to calculate RTT.
875 */
876 struct GNUNET_TIME_AbsoluteNBO origin_time;
877
878 /**
879 * How long does the sender believe this address to remain
880 * valid?
881 */
882 struct GNUNET_TIME_RelativeNBO validity_duration;
883};
884
885
886/**
887 * Message for Transport-to-Transport Flow control. Specifies the size
888 * of the flow control window, including how much we believe to have
889 * consumed (at transmission time), how much we believe to be allowed
890 * (at transmission time), and how much the other peer is allowed to
891 * send to us, and how much data we already received from the other
892 * peer.
893 */
894struct TransportFlowControlMessage
895{
896 /**
897 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
898 */
899 struct GNUNET_MessageHeader header;
900
901 /**
902 * Sequence number of the flow control message. Incremented by one
903 * for each message. Starts at zero when a virtual link goes up.
904 * Used to detect one-sided connection drops. On wrap-around, the
905 * flow control counters will be reset as if the connection had
906 * dropped.
907 */
908 uint32_t seq GNUNET_PACKED;
909
910 /**
911 * Flow control window size in bytes, in NBO.
912 * The receiver can send this many bytes at most.
913 */
914 uint64_t inbound_window_size GNUNET_PACKED;
915
916 /**
917 * How many bytes has the sender sent that count for flow control at
918 * this time. Used to allow the receiver to estimate the packet
919 * loss rate.
920 */
921 uint64_t outbound_sent GNUNET_PACKED;
922
923 /**
924 * Latest flow control window size we learned from the other peer,
925 * in bytes, in NBO. We are limited to sending at most this many
926 * bytes to the other peer. May help the other peer detect when
927 * flow control messages were lost and should thus be retransmitted.
928 * In particular, if the delta to @e outbound_sent is too small,
929 * this signals that we are stalled.
930 */
931 uint64_t outbound_window_size GNUNET_PACKED;
932
933 /**
934 * Timestamp of the sender. Must be monotonically increasing!
935 * Used to enable receiver to ignore out-of-order packets in
936 * combination with the @e seq. Note that @e seq will go down
937 * (back to zero) whenever either side believes the connection
938 * was dropped, allowing the peers to detect that they need to
939 * reset the counters for the number of bytes sent!
940 */
941 struct GNUNET_TIME_AbsoluteNBO sender_time;
942};
943
944
945GNUNET_NETWORK_STRUCT_END
946
947
948/**
949 * What type of client is the `struct TransportClient` about?
950 */
951enum ClientType
952{
953 /**
954 * We do not know yet (client is fresh).
955 */
956 CT_NONE = 0,
957
958 /**
959 * Is the CORE service, we need to forward traffic to it.
960 */
961 CT_CORE = 1,
962
963 /**
964 * It is a monitor, forward monitor data.
965 */
966 CT_MONITOR = 2,
967
968 /**
969 * It is a communicator, use for communication.
970 */
971 CT_COMMUNICATOR = 3,
972
973 /**
974 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
975 */
976 CT_APPLICATION = 4
977};
978
979
980/**
981 * Which transmission options are allowable for transmission?
982 * Interpreted bit-wise!
983 */
984enum RouteMessageOptions
985{
986 /**
987 * Only confirmed, non-DV direct neighbours.
988 */
989 RMO_NONE = 0,
990
991 /**
992 * We are allowed to use DV routing for this @a hdr
993 */
994 RMO_DV_ALLOWED = 1,
995
996 /**
997 * We are allowed to use unconfirmed queues or DV routes for this message
998 */
999 RMO_UNCONFIRMED_ALLOWED = 2,
1000
1001 /**
1002 * Reliable and unreliable, DV and non-DV are all acceptable.
1003 */
1004 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
1005
1006 /**
1007 * If we have multiple choices, it is OK to send this message
1008 * over multiple channels at the same time to improve loss tolerance.
1009 * (We do at most 2 transmissions.)
1010 */
1011 RMO_REDUNDANT = 4
1012};
1013
1014
1015/**
1016 * When did we launch this DV learning activity?
1017 */
1018struct LearnLaunchEntry
1019{
1020 /**
1021 * Kept (also) in a DLL sorted by launch time.
1022 */
1023 struct LearnLaunchEntry *prev;
1024
1025 /**
1026 * Kept (also) in a DLL sorted by launch time.
1027 */
1028 struct LearnLaunchEntry *next;
1029
1030 /**
1031 * Challenge that uniquely identifies this activity.
1032 */
1033 struct ChallengeNonceP challenge;
1034
1035 /**
1036 * When did we transmit the DV learn message (used to calculate RTT) and
1037 * determine freshness of paths learned via this operation.
1038 */
1039 struct GNUNET_TIME_Absolute launch_time;
1040};
1041
1042
1043/**
1044 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1045 * (or current) transmission performance.
1046 */
1047struct TransmissionHistoryEntry
1048{
1049 /**
1050 * Number of bytes actually sent in the interval.
1051 */
1052 uint64_t bytes_sent;
1053
1054 /**
1055 * Number of bytes received and acknowledged by the other peer in
1056 * the interval.
1057 */
1058 uint64_t bytes_received;
1059};
1060
1061
1062/**
1063 * Performance data for a transmission possibility.
1064 */
1065struct PerformanceData
1066{
1067 /**
1068 * Weighted average for the RTT.
1069 */
1070 struct GNUNET_TIME_Relative aged_rtt;
1071
1072 /**
1073 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1074 * entries.
1075 */
1076 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1077
1078 /**
1079 * What was the last age when we wrote to @e the? Used to clear
1080 * old entries when the age advances.
1081 */
1082 unsigned int last_age;
1083};
1084
1085
1086/**
1087 * Client connected to the transport service.
1088 */
1089struct TransportClient;
1090
1091/**
1092 * A neighbour that at least one communicator is connected to.
1093 */
1094struct Neighbour;
1095
1096/**
1097 * Entry in our #dv_routes table, representing a (set of) distance
1098 * vector routes to a particular peer.
1099 */
1100struct DistanceVector;
1101
1102/**
1103 * A queue is a message queue provided by a communicator
1104 * via which we can reach a particular neighbour.
1105 */
1106struct Queue;
1107
1108/**
1109 * Message awaiting transmission. See detailed comments below.
1110 */
1111struct PendingMessage;
1112
1113/**
1114 * One possible hop towards a DV target.
1115 */
1116struct DistanceVectorHop;
1117
1118/**
1119 * A virtual link is another reachable peer that is known to CORE. It
1120 * can be either a `struct Neighbour` with at least one confirmed
1121 * `struct Queue`, or a `struct DistanceVector` with at least one
1122 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1123 * data that is per neighbour that is not specific to how the
1124 * connectivity is established.
1125 */
1126struct VirtualLink;
1127
1128
1129/**
1130 * Context from #handle_incoming_msg(). Closure for many
1131 * message handlers below.
1132 */
1133struct CommunicatorMessageContext
1134{
1135 /**
1136 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1137 * flow control to unchoke.
1138 */
1139 struct CommunicatorMessageContext *next;
1140
1141 /**
1142 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1143 * flow control to unchoke.
1144 */
1145 struct CommunicatorMessageContext *prev;
1146
1147 /**
1148 * Which communicator provided us with the message.
1149 */
1150 struct TransportClient *tc;
1151
1152 /**
1153 * Additional information for flow control and about the sender.
1154 */
1155 struct GNUNET_TRANSPORT_IncomingMessage im;
1156
1157 /**
1158 * Number of hops the message has travelled (if DV-routed).
1159 * FIXME: make use of this in ACK handling!
1160 */
1161 uint16_t total_hops;
1162};
1163
1164
1165/**
1166 * Closure for #core_env_sent_cb.
1167 */
1168struct CoreSentContext
1169{
1170 /**
1171 * Kept in a DLL to clear @e vl in case @e vl is lost.
1172 */
1173 struct CoreSentContext *next;
1174
1175 /**
1176 * Kept in a DLL to clear @e vl in case @e vl is lost.
1177 */
1178 struct CoreSentContext *prev;
1179
1180 /**
1181 * Virtual link this is about.
1182 */
1183 struct VirtualLink *vl;
1184
1185 /**
1186 * How big was the message.
1187 */
1188 uint16_t size;
1189
1190 /**
1191 * By how much should we increment @e vl's
1192 * incoming_fc_window_size_used once we are done sending to CORE?
1193 * Use to ensure we do not increment twice if there is more than one
1194 * CORE client.
1195 */
1196 uint16_t isize;
1197};
1198
1199
1200/**
1201 * A virtual link is another reachable peer that is known to CORE. It
1202 * can be either a `struct Neighbour` with at least one confirmed
1203 * `struct Queue`, or a `struct DistanceVector` with at least one
1204 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1205 * data that is per neighbour that is not specific to how the
1206 * connectivity is established.
1207 */
1208struct VirtualLink
1209{
1210 /**
1211 * Identity of the peer at the other end of the link.
1212 */
1213 struct GNUNET_PeerIdentity target;
1214
1215 /**
1216 * Communicators blocked for receiving on @e target as we are waiting
1217 * on the @e core_recv_window to increase.
1218 */
1219 struct CommunicatorMessageContext *cmc_head;
1220
1221 /**
1222 * Communicators blocked for receiving on @e target as we are waiting
1223 * on the @e core_recv_window to increase.
1224 */
1225 struct CommunicatorMessageContext *cmc_tail;
1226
1227 /**
1228 * Head of list of messages pending for this VL.
1229 */
1230 struct PendingMessage *pending_msg_head;
1231
1232 /**
1233 * Tail of list of messages pending for this VL.
1234 */
1235 struct PendingMessage *pending_msg_tail;
1236
1237 /**
1238 * Kept in a DLL to clear @e vl in case @e vl is lost.
1239 */
1240 struct CoreSentContext *csc_tail;
1241
1242 /**
1243 * Kept in a DLL to clear @e vl in case @e vl is lost.
1244 */
1245 struct CoreSentContext *csc_head;
1246
1247 /**
1248 * Task scheduled to possibly notfiy core that this peer is no
1249 * longer counting as confirmed. Runs the #core_visibility_check(),
1250 * which checks that some DV-path or a queue exists that is still
1251 * considered confirmed.
1252 */
1253 struct GNUNET_SCHEDULER_Task *visibility_task;
1254
1255 /**
1256 * Task scheduled to periodically retransmit FC messages (in
1257 * case one got lost).
1258 */
1259 struct GNUNET_SCHEDULER_Task *fc_retransmit_task;
1260
1261 /**
1262 * Neighbour used by this virtual link, NULL if @e dv is used.
1263 */
1264 struct Neighbour *n;
1265
1266 /**
1267 * Distance vector used by this virtual link, NULL if @e n is used.
1268 */
1269 struct DistanceVector *dv;
1270
1271 /**
1272 * Sender timestamp of @e n_challenge, used to generate out-of-order
1273 * challenges (as sender's timestamps must be monotonically
1274 * increasing). FIXME: where do we need this?
1275 */
1276 struct GNUNET_TIME_Absolute n_challenge_time;
1277
1278 /**
1279 * When did we last send a
1280 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message?
1281 * Used to determine whether it is time to re-transmit the message.
1282 */
1283 struct GNUNET_TIME_Absolute last_fc_transmission;
1284
1285 /**
1286 * Sender timestamp of the last
1287 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1288 * received. Note that we do not persist this monotonic time as we
1289 * do not really have to worry about ancient flow control window
1290 * sizes after restarts.
1291 */
1292 struct GNUNET_TIME_Absolute last_fc_timestamp;
1293
1294 /**
1295 * Expected RTT from the last FC transmission. (Zero if the last
1296 * attempt failed, but could theoretically be zero even on success.)
1297 */
1298 struct GNUNET_TIME_Relative last_fc_rtt;
1299
1300 /**
1301 * Used to generate unique UUIDs for messages that are being
1302 * fragmented.
1303 */
1304 uint64_t message_uuid_ctr;
1305
1306 /**
1307 * Memory allocated for this virtual link. Expresses how much RAM
1308 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1309 * Can be adapted to dedicate more RAM to links that need it, while
1310 * sticking to some overall RAM limit. For now, set to
1311 * #DEFAULT_WINDOW_SIZE.
1312 */
1313 uint64_t available_fc_window_size;
1314
1315 /**
1316 * Memory actually used to buffer packets on this virtual link.
1317 * Expresses how much RAM we are currently using for virtual link.
1318 * Note that once CORE is done with a packet, we decrement the value
1319 * here.
1320 */
1321 uint64_t incoming_fc_window_size_ram;
1322
1323 /**
1324 * Last flow control window size we provided to the other peer, in
1325 * bytes. We are allowing the other peer to send this
1326 * many bytes.
1327 */
1328 uint64_t incoming_fc_window_size;
1329
1330 /**
1331 * How much of the window did the other peer successfully use (and
1332 * we already passed it on to CORE)? Must be below @e
1333 * incoming_fc_window_size. We should effectively signal the
1334 * other peer that the window is this much bigger at the next
1335 * opportunity / challenge.
1336 */
1337 uint64_t incoming_fc_window_size_used;
1338
1339 /**
1340 * What is our current estimate on the message loss rate for the sender?
1341 * Based on the difference between how much the sender sent according
1342 * to the last #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message
1343 * (@e outbound_sent field) and how much we actually received at that
1344 * time (@e incoming_fc_window_size_used). This delta is then
1345 * added onto the @e incoming_fc_window_size when determining the
1346 * @e outbound_window_size we send to the other peer. Initially zero.
1347 * May be negative if we (due to out-of-order delivery) actually received
1348 * more than the sender claims to have sent in its last FC message.
1349 */
1350 int64_t incoming_fc_window_size_loss;
1351
1352 /**
1353 * Our current flow control window size in bytes. We
1354 * are allowed to transmit this many bytes to @a n.
1355 */
1356 uint64_t outbound_fc_window_size;
1357
1358 /**
1359 * How much of our current flow control window size have we
1360 * used (in bytes). Must be below
1361 * @e outbound_fc_window_size.
1362 */
1363 uint64_t outbound_fc_window_size_used;
1364
1365 /**
1366 * What is the most recent FC window the other peer sent us
1367 * in `outbound_window_size`? This is basically the window
1368 * size value the other peer has definitively received from
1369 * us. If it matches @e incoming_fc_window_size, we should
1370 * not send a FC message to increase the FC window. However,
1371 * we may still send an FC message to notify the other peer
1372 * that we received the other peer's FC message.
1373 */
1374 uint64_t last_outbound_window_size_received;
1375
1376 /**
1377 * Generator for the sequence numbers of
1378 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1379 */
1380 uint32_t fc_seq_gen;
1381
1382 /**
1383 * Last sequence number of a
1384 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1385 * received.
1386 */
1387 uint32_t last_fc_seq;
1388
1389 /**
1390 * How many more messages can we send to CORE before we exhaust
1391 * the receive window of CORE for this peer? If this hits zero,
1392 * we must tell communicators to stop providing us more messages
1393 * for this peer. In fact, the window can go negative as we
1394 * have multiple communicators, so per communicator we can go
1395 * down by one into the negative range. Furthermore, we count
1396 * delivery per CORE client, so if we had multiple cores, that
1397 * might also cause a negative window size here (as one message
1398 * would decrement the window by one per CORE client).
1399 */
1400 int core_recv_window;
1401};
1402
1403
1404/**
1405 * Data structure kept when we are waiting for an acknowledgement.
1406 */
1407struct PendingAcknowledgement
1408{
1409 /**
1410 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1411 * is kept in relation to its pending message.
1412 */
1413 struct PendingAcknowledgement *next_pm;
1414
1415 /**
1416 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1417 * is kept in relation to its pending message.
1418 */
1419 struct PendingAcknowledgement *prev_pm;
1420
1421 /**
1422 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1423 * is kept in relation to the queue that was used to transmit the
1424 * @a pm.
1425 */
1426 struct PendingAcknowledgement *next_queue;
1427
1428 /**
1429 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1430 * is kept in relation to the queue that was used to transmit the
1431 * @a pm.
1432 */
1433 struct PendingAcknowledgement *prev_queue;
1434
1435 /**
1436 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1437 * is kept in relation to the DVH that was used to transmit the
1438 * @a pm.
1439 */
1440 struct PendingAcknowledgement *next_dvh;
1441
1442 /**
1443 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1444 * is kept in relation to the DVH that was used to transmit the
1445 * @a pm.
1446 */
1447 struct PendingAcknowledgement *prev_dvh;
1448
1449 /**
1450 * Pointers for the DLL of all pending acknowledgements.
1451 * This list is sorted by @e transmission time. If the list gets too
1452 * long, the oldest entries are discarded.
1453 */
1454 struct PendingAcknowledgement *next_pa;
1455
1456 /**
1457 * Pointers for the DLL of all pending acknowledgements.
1458 * This list is sorted by @e transmission time. If the list gets too
1459 * long, the oldest entries are discarded.
1460 */
1461 struct PendingAcknowledgement *prev_pa;
1462
1463 /**
1464 * Unique identifier for this transmission operation.
1465 */
1466 struct AcknowledgementUUIDP ack_uuid;
1467
1468 /**
1469 * Message that was transmitted, may be NULL if the message was ACKed
1470 * via another channel.
1471 */
1472 struct PendingMessage *pm;
1473
1474 /**
1475 * Distance vector path chosen for this transmission, NULL if transmission
1476 * was to a direct neighbour OR if the path was forgotten in the meantime.
1477 */
1478 struct DistanceVectorHop *dvh;
1479
1480 /**
1481 * Queue used for transmission, NULL if the queue has been destroyed
1482 * (which may happen before we get an acknowledgement).
1483 */
1484 struct Queue *queue;
1485
1486 /**
1487 * Time of the transmission, for RTT calculation.
1488 */
1489 struct GNUNET_TIME_Absolute transmission_time;
1490
1491 /**
1492 * Number of bytes of the original message (to calculate bandwidth).
1493 */
1494 uint16_t message_size;
1495};
1496
1497
1498/**
1499 * One possible hop towards a DV target.
1500 */
1501struct DistanceVectorHop
1502{
1503 /**
1504 * Kept in a MDLL, sorted by @e timeout.
1505 */
1506 struct DistanceVectorHop *next_dv;
1507
1508 /**
1509 * Kept in a MDLL, sorted by @e timeout.
1510 */
1511 struct DistanceVectorHop *prev_dv;
1512
1513 /**
1514 * Kept in a MDLL.
1515 */
1516 struct DistanceVectorHop *next_neighbour;
1517
1518 /**
1519 * Kept in a MDLL.
1520 */
1521 struct DistanceVectorHop *prev_neighbour;
1522
1523 /**
1524 * Head of DLL of PAs that used our @a path.
1525 */
1526 struct PendingAcknowledgement *pa_head;
1527
1528 /**
1529 * Tail of DLL of PAs that used our @a path.
1530 */
1531 struct PendingAcknowledgement *pa_tail;
1532
1533 /**
1534 * What would be the next hop to @e target?
1535 */
1536 struct Neighbour *next_hop;
1537
1538 /**
1539 * Distance vector entry this hop belongs with.
1540 */
1541 struct DistanceVector *dv;
1542
1543 /**
1544 * Array of @e distance hops to the target, excluding @e next_hop.
1545 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1546 * at the end of this struct. Excludes the target itself!
1547 */
1548 const struct GNUNET_PeerIdentity *path;
1549
1550 /**
1551 * At what time do we forget about this path unless we see it again
1552 * while learning?
1553 */
1554 struct GNUNET_TIME_Absolute timeout;
1555
1556 /**
1557 * For how long is the validation of this path considered
1558 * valid?
1559 * Set to ZERO if the path is learned by snooping on DV learn messages
1560 * initiated by other peers, and to the time at which we generated the
1561 * challenge for DV learn operations this peer initiated.
1562 */
1563 struct GNUNET_TIME_Absolute path_valid_until;
1564
1565 /**
1566 * Performance data for this transmission possibility.
1567 */
1568 struct PerformanceData pd;
1569
1570 /**
1571 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1572 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1573 * to `target`).
1574 */
1575 unsigned int distance;
1576};
1577
1578
1579/**
1580 * Entry in our #dv_routes table, representing a (set of) distance
1581 * vector routes to a particular peer.
1582 */
1583struct DistanceVector
1584{
1585 /**
1586 * To which peer is this a route?
1587 */
1588 struct GNUNET_PeerIdentity target;
1589
1590 /**
1591 * Known paths to @e target.
1592 */
1593 struct DistanceVectorHop *dv_head;
1594
1595 /**
1596 * Known paths to @e target.
1597 */
1598 struct DistanceVectorHop *dv_tail;
1599
1600 /**
1601 * Task scheduled to purge expired paths from @e dv_head MDLL.
1602 */
1603 struct GNUNET_SCHEDULER_Task *timeout_task;
1604
1605 /**
1606 * Do we have a confirmed working queue and are thus visible to
1607 * CORE? If so, this is the virtual link, otherwise NULL.
1608 */
1609 struct VirtualLink *vl;
1610
1611 /**
1612 * Signature affirming @e ephemeral_key of type
1613 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1614 */
1615 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1616
1617 /**
1618 * How long is @e sender_sig valid
1619 */
1620 struct GNUNET_TIME_Absolute ephemeral_validity;
1621
1622 /**
1623 * What time was @e sender_sig created
1624 */
1625 struct GNUNET_TIME_Absolute monotime;
1626
1627 /**
1628 * Our ephemeral key.
1629 */
1630 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1631
1632 /**
1633 * Our private ephemeral key.
1634 */
1635 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1636};
1637
1638
1639/**
1640 * Entry identifying transmission in one of our `struct
1641 * Queue` which still awaits an ACK. This is used to
1642 * ensure we do not overwhelm a communicator and limit the number of
1643 * messages outstanding per communicator (say in case communicator is
1644 * CPU bound) and per queue (in case bandwidth allocation exceeds
1645 * what the communicator can actually provide towards a particular
1646 * peer/target).
1647 */
1648struct QueueEntry
1649{
1650 /**
1651 * Kept as a DLL.
1652 */
1653 struct QueueEntry *next;
1654
1655 /**
1656 * Kept as a DLL.
1657 */
1658 struct QueueEntry *prev;
1659
1660 /**
1661 * Queue this entry is queued with.
1662 */
1663 struct Queue *queue;
1664
1665 /**
1666 * Pending message this entry is for, or NULL for none.
1667 */
1668 struct PendingMessage *pm;
1669
1670 /**
1671 * Message ID used for this message with the queue used for transmission.
1672 */
1673 uint64_t mid;
1674};
1675
1676
1677/**
1678 * A queue is a message queue provided by a communicator
1679 * via which we can reach a particular neighbour.
1680 */
1681struct Queue
1682{
1683 /**
1684 * Kept in a MDLL.
1685 */
1686 struct Queue *next_neighbour;
1687
1688 /**
1689 * Kept in a MDLL.
1690 */
1691 struct Queue *prev_neighbour;
1692
1693 /**
1694 * Kept in a MDLL.
1695 */
1696 struct Queue *prev_client;
1697
1698 /**
1699 * Kept in a MDLL.
1700 */
1701 struct Queue *next_client;
1702
1703 /**
1704 * Head of DLL of PAs that used this queue.
1705 */
1706 struct PendingAcknowledgement *pa_head;
1707
1708 /**
1709 * Tail of DLL of PAs that used this queue.
1710 */
1711 struct PendingAcknowledgement *pa_tail;
1712
1713 /**
1714 * Head of DLL of unacked transmission requests.
1715 */
1716 struct QueueEntry *queue_head;
1717
1718 /**
1719 * End of DLL of unacked transmission requests.
1720 */
1721 struct QueueEntry *queue_tail;
1722
1723 /**
1724 * Which neighbour is this queue for?
1725 */
1726 struct Neighbour *neighbour;
1727
1728 /**
1729 * Which communicator offers this queue?
1730 */
1731 struct TransportClient *tc;
1732
1733 /**
1734 * Address served by the queue.
1735 */
1736 const char *address;
1737
1738 /**
1739 * Task scheduled for the time when this queue can (likely) transmit the
1740 * next message.
1741 */
1742 struct GNUNET_SCHEDULER_Task *transmit_task;
1743
1744 /**
1745 * How long do *we* consider this @e address to be valid? In the past or
1746 * zero if we have not yet validated it. Can be updated based on
1747 * challenge-response validations (via address validation logic), or when we
1748 * receive ACKs that we can definitively map to transmissions via this
1749 * queue.
1750 */
1751 struct GNUNET_TIME_Absolute validated_until;
1752
1753 /**
1754 * Performance data for this queue.
1755 */
1756 struct PerformanceData pd;
1757
1758 /**
1759 * Message ID generator for transmissions on this queue to the
1760 * communicator.
1761 */
1762 uint64_t mid_gen;
1763
1764 /**
1765 * Unique identifier of this queue with the communicator.
1766 */
1767 uint32_t qid;
1768
1769 /**
1770 * Maximum transmission unit supported by this queue.
1771 */
1772 uint32_t mtu;
1773
1774 /**
1775 * Messages pending.
1776 */
1777 uint32_t num_msg_pending;
1778
1779 /**
1780 * Bytes pending.
1781 */
1782 uint32_t num_bytes_pending;
1783
1784 /**
1785 * Length of the DLL starting at @e queue_head.
1786 */
1787 unsigned int queue_length;
1788
1789 /**
1790 * Queue priority
1791 */
1792 uint32_t priority;
1793
1794 /**
1795 * Network type offered by this queue.
1796 */
1797 enum GNUNET_NetworkType nt;
1798
1799 /**
1800 * Connection status for this queue.
1801 */
1802 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1803
1804 /**
1805 * Set to #GNUNET_YES if this queue is idle waiting for some
1806 * virtual link to give it a pending message.
1807 */
1808 int idle;
1809};
1810
1811
1812/**
1813 * Information we keep for a message that we are reassembling.
1814 */
1815struct ReassemblyContext
1816{
1817 /**
1818 * Original message ID for of the message that all the fragments
1819 * belong to.
1820 */
1821 struct MessageUUIDP msg_uuid;
1822
1823 /**
1824 * Which neighbour is this context for?
1825 */
1826 struct Neighbour *neighbour;
1827
1828 /**
1829 * Entry in the reassembly heap (sorted by expiration).
1830 */
1831 struct GNUNET_CONTAINER_HeapNode *hn;
1832
1833 /**
1834 * Bitfield with @e msg_size bits representing the positions
1835 * where we have received fragments. When we receive a fragment,
1836 * we check the bits in @e bitfield before incrementing @e msg_missing.
1837 *
1838 * Allocated after the reassembled message.
1839 */
1840 uint8_t *bitfield;
1841
1842 /**
1843 * At what time will we give up reassembly of this message?
1844 */
1845 struct GNUNET_TIME_Absolute reassembly_timeout;
1846
1847 /**
1848 * Time we received the last fragment. @e avg_ack_delay must be
1849 * incremented by now - @e last_frag multiplied by @e num_acks.
1850 */
1851 struct GNUNET_TIME_Absolute last_frag;
1852
1853 /**
1854 * How big is the message we are reassembling in total?
1855 */
1856 uint16_t msg_size;
1857
1858 /**
1859 * How many bytes of the message are still missing? Defragmentation
1860 * is complete when @e msg_missing == 0.
1861 */
1862 uint16_t msg_missing;
1863
1864 /* Followed by @e msg_size bytes of the (partially) defragmented original
1865 * message */
1866
1867 /* Followed by @e bitfield data */
1868};
1869
1870
1871/**
1872 * A neighbour that at least one communicator is connected to.
1873 */
1874struct Neighbour
1875{
1876 /**
1877 * Which peer is this about?
1878 */
1879 struct GNUNET_PeerIdentity pid;
1880
1881 /**
1882 * Map with `struct ReassemblyContext` structs for fragments under
1883 * reassembly. May be NULL if we currently have no fragments from
1884 * this @e pid (lazy initialization).
1885 */
1886 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1887
1888 /**
1889 * Heap with `struct ReassemblyContext` structs for fragments under
1890 * reassembly. May be NULL if we currently have no fragments from
1891 * this @e pid (lazy initialization).
1892 */
1893 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1894
1895 /**
1896 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1897 */
1898 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1899
1900 /**
1901 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1902 * purged if this neighbour goes down.
1903 */
1904 struct DistanceVectorHop *dv_head;
1905
1906 /**
1907 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1908 * purged if this neighbour goes down.
1909 */
1910 struct DistanceVectorHop *dv_tail;
1911
1912 /**
1913 * Head of DLL of queues to this peer.
1914 */
1915 struct Queue *queue_head;
1916
1917 /**
1918 * Tail of DLL of queues to this peer.
1919 */
1920 struct Queue *queue_tail;
1921
1922 /**
1923 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1924 * the PEERSTORE, or NULL.
1925 */
1926 struct GNUNET_PEERSTORE_IterateContext *get;
1927
1928 /**
1929 * Handle to a PEERSTORE store operation to store this @e pid's @e
1930 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1931 */
1932 struct GNUNET_PEERSTORE_StoreContext *sc;
1933
1934 /**
1935 * Do we have a confirmed working queue and are thus visible to
1936 * CORE? If so, this is the virtual link, otherwise NULL.
1937 */
1938 struct VirtualLink *vl;
1939
1940 /**
1941 * Latest DVLearn monotonic time seen from this peer. Initialized only
1942 * if @e dl_monotime_available is #GNUNET_YES.
1943 */
1944 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1945
1946 /**
1947 * Do we have the latest value for @e last_dv_learn_monotime from
1948 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1949 */
1950 int dv_monotime_available;
1951};
1952
1953
1954/**
1955 * Another peer attempted to talk to us, we should try to establish
1956 * a connection in the other direction.
1957 */
1958struct IncomingRequest
1959{
1960 /**
1961 * Kept in a DLL.
1962 */
1963 struct IncomingRequest *next;
1964
1965 /**
1966 * Kept in a DLL.
1967 */
1968 struct IncomingRequest *prev;
1969
1970 /**
1971 * Handle for watching the peerstore for HELLOs for this peer.
1972 */
1973 struct GNUNET_PEERSTORE_WatchContext *wc;
1974
1975 /**
1976 * Which peer is this about?
1977 */
1978 struct GNUNET_PeerIdentity pid;
1979};
1980
1981
1982/**
1983 * A peer that an application (client) would like us to talk to directly.
1984 */
1985struct PeerRequest
1986{
1987 /**
1988 * Which peer is this about?
1989 */
1990 struct GNUNET_PeerIdentity pid;
1991
1992 /**
1993 * Client responsible for the request.
1994 */
1995 struct TransportClient *tc;
1996
1997 /**
1998 * Handle for watching the peerstore for HELLOs for this peer.
1999 */
2000 struct GNUNET_PEERSTORE_WatchContext *wc;
2001
2002 /**
2003 * What kind of performance preference does this @e tc have?
2004 *
2005 * TODO: use this!
2006 */
2007 enum GNUNET_MQ_PriorityPreferences pk;
2008
2009 /**
2010 * How much bandwidth would this @e tc like to see?
2011 */
2012 struct GNUNET_BANDWIDTH_Value32NBO bw;
2013};
2014
2015
2016/**
2017 * Types of different pending messages.
2018 */
2019enum PendingMessageType
2020{
2021 /**
2022 * Ordinary message received from the CORE service.
2023 */
2024 PMT_CORE = 0,
2025
2026 /**
2027 * Fragment box.
2028 */
2029 PMT_FRAGMENT_BOX = 1,
2030
2031 /**
2032 * Reliability box.
2033 */
2034 PMT_RELIABILITY_BOX = 2,
2035
2036 /**
2037 * Pending message created during #forward_dv_box().
2038 */
2039 PMT_DV_BOX = 3
2040};
2041
2042
2043/**
2044 * Transmission request that is awaiting delivery. The original
2045 * transmission requests from CORE may be too big for some queues.
2046 * In this case, a *tree* of fragments is created. At each
2047 * level of the tree, fragments are kept in a DLL ordered by which
2048 * fragment should be sent next (at the head). The tree is searched
2049 * top-down, with the original message at the root.
2050 *
2051 * To select a node for transmission, first it is checked if the
2052 * current node's message fits with the MTU. If it does not, we
2053 * either calculate the next fragment (based on @e frag_off) from the
2054 * current node, or, if all fragments have already been created,
2055 * descend to the @e head_frag. Even though the node was already
2056 * fragmented, the fragment may be too big if the fragment was
2057 * generated for a queue with a larger MTU. In this case, the node
2058 * may be fragmented again, thus creating a tree.
2059 *
2060 * When acknowledgements for fragments are received, the tree
2061 * must be pruned, removing those parts that were already
2062 * acknowledged. When fragments are sent over a reliable
2063 * channel, they can be immediately removed.
2064 *
2065 * If a message is ever fragmented, then the original "full" message
2066 * is never again transmitted (even if it fits below the MTU), and
2067 * only (remaining) fragments are sent.
2068 */
2069struct PendingMessage
2070{
2071 /**
2072 * Kept in a MDLL of messages for this @a vl.
2073 */
2074 struct PendingMessage *next_vl;
2075
2076 /**
2077 * Kept in a MDLL of messages for this @a vl.
2078 */
2079 struct PendingMessage *prev_vl;
2080
2081 /**
2082 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2083 */
2084 struct PendingMessage *next_client;
2085
2086 /**
2087 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2088 */
2089 struct PendingMessage *prev_client;
2090
2091 /**
2092 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2093 * #PMT_FRAGMENT_BOx)
2094 */
2095 struct PendingMessage *next_frag;
2096
2097 /**
2098 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2099 * #PMT_FRAGMENT_BOX)
2100 */
2101 struct PendingMessage *prev_frag;
2102
2103 /**
2104 * Head of DLL of PAs for this pending message.
2105 */
2106 struct PendingAcknowledgement *pa_head;
2107
2108 /**
2109 * Tail of DLL of PAs for this pending message.
2110 */
2111 struct PendingAcknowledgement *pa_tail;
2112
2113 /**
2114 * This message, reliability *or* DV-boxed. Only possibly available
2115 * if @e pmt is #PMT_CORE.
2116 */
2117 struct PendingMessage *bpm;
2118
2119 /**
2120 * Target of the request (always the ultimate destination!).
2121 */
2122 struct VirtualLink *vl;
2123
2124 /**
2125 * Set to non-NULL value if this message is currently being given to a
2126 * communicator and we are awaiting that communicator's acknowledgement.
2127 * Note that we must not retransmit a pending message while we're still
2128 * in the process of giving it to a communicator. If a pending message
2129 * is free'd while this entry is non-NULL, the @e qe reference to us
2130 * should simply be set to NULL.
2131 */
2132 struct QueueEntry *qe;
2133
2134 /**
2135 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
2136 */
2137 struct TransportClient *client;
2138
2139 /**
2140 * Head of a MDLL of fragments created for this core message.
2141 */
2142 struct PendingMessage *head_frag;
2143
2144 /**
2145 * Tail of a MDLL of fragments created for this core message.
2146 */
2147 struct PendingMessage *tail_frag;
2148
2149 /**
2150 * Our parent in the fragmentation tree.
2151 */
2152 struct PendingMessage *frag_parent;
2153
2154 /**
2155 * At what time should we give up on the transmission (and no longer retry)?
2156 */
2157 struct GNUNET_TIME_Absolute timeout;
2158
2159 /**
2160 * What is the earliest time for us to retry transmission of this message?
2161 */
2162 struct GNUNET_TIME_Absolute next_attempt;
2163
2164 /**
2165 * UUID to use for this message (used for reassembly of fragments, only
2166 * initialized if @e msg_uuid_set is #GNUNET_YES).
2167 */
2168 struct MessageUUIDP msg_uuid;
2169
2170 /**
2171 * UUID we use to identify this message in our logs.
2172 * Generated by incrementing the "logging_uuid_gen".
2173 */
2174 unsigned long long logging_uuid;
2175
2176 /**
2177 * Type of the pending message.
2178 */
2179 enum PendingMessageType pmt;
2180
2181 /**
2182 * Preferences for this message.
2183 * TODO: actually use this!
2184 */
2185 enum GNUNET_MQ_PriorityPreferences prefs;
2186
2187 /**
2188 * Size of the original message.
2189 */
2190 uint16_t bytes_msg;
2191
2192 /**
2193 * Offset at which we should generate the next fragment.
2194 */
2195 uint16_t frag_off;
2196
2197 /**
2198 * #GNUNET_YES once @e msg_uuid was initialized
2199 */
2200 int16_t msg_uuid_set;
2201
2202 /* Followed by @e bytes_msg to transmit */
2203};
2204
2205
2206/**
2207 * Acknowledgement payload.
2208 */
2209struct TransportCummulativeAckPayload
2210{
2211 /**
2212 * When did we receive the message we are ACKing? Used to calculate
2213 * the delay we introduced by cummulating ACKs.
2214 */
2215 struct GNUNET_TIME_Absolute receive_time;
2216
2217 /**
2218 * UUID of a message being acknowledged.
2219 */
2220 struct AcknowledgementUUIDP ack_uuid;
2221};
2222
2223
2224/**
2225 * Data structure in which we track acknowledgements still to
2226 * be sent to the
2227 */
2228struct AcknowledgementCummulator
2229{
2230 /**
2231 * Target peer for which we are accumulating ACKs here.
2232 */
2233 struct GNUNET_PeerIdentity target;
2234
2235 /**
2236 * ACK data being accumulated. Only @e num_acks slots are valid.
2237 */
2238 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2239
2240 /**
2241 * Task scheduled either to transmit the cumulative ACK message,
2242 * or to clean up this data structure after extended periods of
2243 * inactivity (if @e num_acks is zero).
2244 */
2245 struct GNUNET_SCHEDULER_Task *task;
2246
2247 /**
2248 * When is @e task run (only used if @e num_acks is non-zero)?
2249 */
2250 struct GNUNET_TIME_Absolute min_transmission_time;
2251
2252 /**
2253 * Counter to produce the `ack_counter` in the `struct
2254 * TransportReliabilityAckMessage`. Allows the receiver to detect
2255 * lost ACK messages. Incremented by @e num_acks upon transmission.
2256 */
2257 uint32_t ack_counter;
2258
2259 /**
2260 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2261 */
2262 unsigned int num_acks;
2263};
2264
2265
2266/**
2267 * One of the addresses of this peer.
2268 */
2269struct AddressListEntry
2270{
2271 /**
2272 * Kept in a DLL.
2273 */
2274 struct AddressListEntry *next;
2275
2276 /**
2277 * Kept in a DLL.
2278 */
2279 struct AddressListEntry *prev;
2280
2281 /**
2282 * Which communicator provides this address?
2283 */
2284 struct TransportClient *tc;
2285
2286 /**
2287 * The actual address.
2288 */
2289 const char *address;
2290
2291 /**
2292 * Current context for storing this address in the peerstore.
2293 */
2294 struct GNUNET_PEERSTORE_StoreContext *sc;
2295
2296 /**
2297 * Task to periodically do @e st operation.
2298 */
2299 struct GNUNET_SCHEDULER_Task *st;
2300
2301 /**
2302 * What is a typical lifetime the communicator expects this
2303 * address to have? (Always from now.)
2304 */
2305 struct GNUNET_TIME_Relative expiration;
2306
2307 /**
2308 * Address identifier used by the communicator.
2309 */
2310 uint32_t aid;
2311
2312 /**
2313 * Network type offered by this address.
2314 */
2315 enum GNUNET_NetworkType nt;
2316};
2317
2318
2319/**
2320 * Client connected to the transport service.
2321 */
2322struct TransportClient
2323{
2324 /**
2325 * Kept in a DLL.
2326 */
2327 struct TransportClient *next;
2328
2329 /**
2330 * Kept in a DLL.
2331 */
2332 struct TransportClient *prev;
2333
2334 /**
2335 * Handle to the client.
2336 */
2337 struct GNUNET_SERVICE_Client *client;
2338
2339 /**
2340 * Message queue to the client.
2341 */
2342 struct GNUNET_MQ_Handle *mq;
2343
2344 /**
2345 * What type of client is this?
2346 */
2347 enum ClientType type;
2348
2349 union
2350 {
2351 /**
2352 * Information for @e type #CT_CORE.
2353 */
2354 struct
2355 {
2356 /**
2357 * Head of list of messages pending for this client, sorted by
2358 * transmission time ("next_attempt" + possibly internal prioritization).
2359 */
2360 struct PendingMessage *pending_msg_head;
2361
2362 /**
2363 * Tail of list of messages pending for this client.
2364 */
2365 struct PendingMessage *pending_msg_tail;
2366 } core;
2367
2368 /**
2369 * Information for @e type #CT_MONITOR.
2370 */
2371 struct
2372 {
2373 /**
2374 * Peer identity to monitor the addresses of.
2375 * Zero to monitor all neighbours. Valid if
2376 * @e type is #CT_MONITOR.
2377 */
2378 struct GNUNET_PeerIdentity peer;
2379
2380 /**
2381 * Is this a one-shot monitor?
2382 */
2383 int one_shot;
2384 } monitor;
2385
2386
2387 /**
2388 * Information for @e type #CT_COMMUNICATOR.
2389 */
2390 struct
2391 {
2392 /**
2393 * If @e type is #CT_COMMUNICATOR, this communicator
2394 * supports communicating using these addresses.
2395 */
2396 char *address_prefix;
2397
2398 /**
2399 * Head of DLL of queues offered by this communicator.
2400 */
2401 struct Queue *queue_head;
2402
2403 /**
2404 * Tail of DLL of queues offered by this communicator.
2405 */
2406 struct Queue *queue_tail;
2407
2408 /**
2409 * Head of list of the addresses of this peer offered by this
2410 * communicator.
2411 */
2412 struct AddressListEntry *addr_head;
2413
2414 /**
2415 * Tail of list of the addresses of this peer offered by this
2416 * communicator.
2417 */
2418 struct AddressListEntry *addr_tail;
2419
2420 /**
2421 * Number of queue entries in all queues to this communicator. Used
2422 * throttle sending to a communicator if we see that the communicator
2423 * is globally unable to keep up.
2424 */
2425 unsigned int total_queue_length;
2426
2427 /**
2428 * Characteristics of this communicator.
2429 */
2430 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2431 } communicator;
2432
2433 /**
2434 * Information for @e type #CT_APPLICATION
2435 */
2436 struct
2437 {
2438 /**
2439 * Map of requests for peers the given client application would like to
2440 * see connections for. Maps from PIDs to `struct PeerRequest`.
2441 */
2442 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2443 } application;
2444 } details;
2445};
2446
2447
2448/**
2449 * State we keep for validation activities. Each of these
2450 * is both in the #validation_heap and the #validation_map.
2451 */
2452struct ValidationState
2453{
2454 /**
2455 * For which peer is @a address to be validated (or possibly valid)?
2456 * Serves as key in the #validation_map.
2457 */
2458 struct GNUNET_PeerIdentity pid;
2459
2460 /**
2461 * How long did the peer claim this @e address to be valid? Capped at
2462 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2463 * were told about the address and the value claimed by the other peer at
2464 * that time. May be updated similarly when validation succeeds.
2465 */
2466 struct GNUNET_TIME_Absolute valid_until;
2467
2468 /**
2469 * How long do *we* consider this @e address to be valid?
2470 * In the past or zero if we have not yet validated it.
2471 */
2472 struct GNUNET_TIME_Absolute validated_until;
2473
2474 /**
2475 * When did we FIRST use the current @e challenge in a message?
2476 * Used to sanity-check @code{origin_time} in the response when
2477 * calculating the RTT. If the @code{origin_time} is not in
2478 * the expected range, the response is discarded as malicious.
2479 */
2480 struct GNUNET_TIME_Absolute first_challenge_use;
2481
2482 /**
2483 * When did we LAST use the current @e challenge in a message?
2484 * Used to sanity-check @code{origin_time} in the response when
2485 * calculating the RTT. If the @code{origin_time} is not in
2486 * the expected range, the response is discarded as malicious.
2487 */
2488 struct GNUNET_TIME_Absolute last_challenge_use;
2489
2490 /**
2491 * Next time we will send the @e challenge to the peer, if this time is past
2492 * @e valid_until, this validation state is released at this time. If the
2493 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2494 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2495 * to re-validate before the validity actually expires.
2496 */
2497 struct GNUNET_TIME_Absolute next_challenge;
2498
2499 /**
2500 * Current backoff factor we're applying for sending the @a challenge.
2501 * Reset to 0 if the @a challenge is confirmed upon validation.
2502 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2503 * existing value if we receive an unvalidated address again over
2504 * another channel (and thus should consider the information "fresh").
2505 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2506 */
2507 struct GNUNET_TIME_Relative challenge_backoff;
2508
2509 /**
2510 * Initially set to "forever". Once @e validated_until is set, this value is
2511 * set to the RTT that tells us how long it took to receive the validation.
2512 */
2513 struct GNUNET_TIME_Relative validation_rtt;
2514
2515 /**
2516 * The challenge we sent to the peer to get it to validate the address. Note
2517 * that we rotate the challenge whenever we update @e validated_until to
2518 * avoid attacks where a peer simply replays an old challenge in the future.
2519 * (We must not rotate more often as otherwise we may discard valid answers
2520 * due to packet losses, latency and reorderings on the network).
2521 */
2522 struct ChallengeNonceP challenge;
2523
2524 /**
2525 * Claimed address of the peer.
2526 */
2527 char *address;
2528
2529 /**
2530 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2531 * heap is used to figure out when the next validation activity should be
2532 * run.
2533 */
2534 struct GNUNET_CONTAINER_HeapNode *hn;
2535
2536 /**
2537 * Handle to a PEERSTORE store operation for this @e address. NULL if
2538 * no PEERSTORE operation is pending.
2539 */
2540 struct GNUNET_PEERSTORE_StoreContext *sc;
2541
2542 /**
2543 * Self-imposed limit on the previous flow control window. (May be zero,
2544 * if we never used data from the previous window or are establishing the
2545 * connection for the first time).
2546 */
2547 uint32_t last_window_consum_limit;
2548
2549 /**
2550 * We are technically ready to send the challenge, but we are waiting for
2551 * the respective queue to become available for transmission.
2552 */
2553 int awaiting_queue;
2554};
2555
2556
2557/**
2558 * A Backtalker is a peer sending us backchannel messages. We use this
2559 * struct to detect monotonic time violations, cache ephemeral key
2560 * material (to avoid repeatedly checking signatures), and to synchronize
2561 * monotonic time with the PEERSTORE.
2562 */
2563struct Backtalker
2564{
2565 /**
2566 * Peer this is about.
2567 */
2568 struct GNUNET_PeerIdentity pid;
2569
2570 /**
2571 * Last (valid) monotonic time received from this sender.
2572 */
2573 struct GNUNET_TIME_Absolute monotonic_time;
2574
2575 /**
2576 * When will this entry time out?
2577 */
2578 struct GNUNET_TIME_Absolute timeout;
2579
2580 /**
2581 * Last (valid) ephemeral key received from this sender.
2582 */
2583 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2584
2585 /**
2586 * Task associated with this backtalker. Can be for timeout,
2587 * or other asynchronous operations.
2588 */
2589 struct GNUNET_SCHEDULER_Task *task;
2590
2591 /**
2592 * Communicator context waiting on this backchannel's @e get, or NULL.
2593 */
2594 struct CommunicatorMessageContext *cmc;
2595
2596 /**
2597 * Handle for an operation to fetch @e monotonic_time information from the
2598 * PEERSTORE, or NULL.
2599 */
2600 struct GNUNET_PEERSTORE_IterateContext *get;
2601
2602 /**
2603 * Handle to a PEERSTORE store operation for this @e pid's @e
2604 * monotonic_time. NULL if no PEERSTORE operation is pending.
2605 */
2606 struct GNUNET_PEERSTORE_StoreContext *sc;
2607
2608 /**
2609 * Number of bytes of the original message body that follows after this
2610 * struct.
2611 */
2612 size_t body_size;
2613};
2614
2615
2616/**
2617 * Head of linked list of all clients to this service.
2618 */
2619static struct TransportClient *clients_head;
2620
2621/**
2622 * Tail of linked list of all clients to this service.
2623 */
2624static struct TransportClient *clients_tail;
2625
2626/**
2627 * Statistics handle.
2628 */
2629static struct GNUNET_STATISTICS_Handle *GST_stats;
2630
2631/**
2632 * Configuration handle.
2633 */
2634static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2635
2636/**
2637 * Our public key.
2638 */
2639static struct GNUNET_PeerIdentity GST_my_identity;
2640
2641/**
2642 * Our private key.
2643 */
2644static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2645
2646/**
2647 * Map from PIDs to `struct Neighbour` entries. A peer is
2648 * a neighbour if we have an MQ to it from some communicator.
2649 */
2650static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2651
2652/**
2653 * Map from PIDs to `struct Backtalker` entries. A peer is
2654 * a backtalker if it recently send us backchannel messages.
2655 */
2656static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2657
2658/**
2659 * Map from PIDs to `struct AcknowledgementCummulator`s.
2660 * Here we track the cumulative ACKs for transmission.
2661 */
2662static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2663
2664/**
2665 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2666 * a `struct PendingAcknowledgement`.
2667 */
2668static struct GNUNET_CONTAINER_MultiUuidmap *pending_acks;
2669
2670/**
2671 * Map from PIDs to `struct DistanceVector` entries describing
2672 * known paths to the peer.
2673 */
2674static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2675
2676/**
2677 * Map from PIDs to `struct ValidationState` entries describing
2678 * addresses we are aware of and their validity state.
2679 */
2680static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2681
2682/**
2683 * Map from PIDs to `struct VirtualLink` entries describing
2684 * links CORE knows to exist.
2685 */
2686static struct GNUNET_CONTAINER_MultiPeerMap *links;
2687
2688/**
2689 * Map from challenges to `struct LearnLaunchEntry` values.
2690 */
2691static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2692
2693/**
2694 * Head of a DLL sorted by launch time.
2695 */
2696static struct LearnLaunchEntry *lle_head = NULL;
2697
2698/**
2699 * Tail of a DLL sorted by launch time.
2700 */
2701static struct LearnLaunchEntry *lle_tail = NULL;
2702
2703/**
2704 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2705 * sorting addresses we are aware of by when we should next try to (re)validate
2706 * (or expire) them.
2707 */
2708static struct GNUNET_CONTAINER_Heap *validation_heap;
2709
2710/**
2711 * Database for peer's HELLOs.
2712 */
2713static struct GNUNET_PEERSTORE_Handle *peerstore;
2714
2715/**
2716 * Task run to initiate DV learning.
2717 */
2718static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2719
2720/**
2721 * Task to run address validation.
2722 */
2723static struct GNUNET_SCHEDULER_Task *validation_task;
2724
2725/**
2726 * The most recent PA we have created, head of DLL.
2727 * The length of the DLL is kept in #pa_count.
2728 */
2729static struct PendingAcknowledgement *pa_head;
2730
2731/**
2732 * The oldest PA we have created, tail of DLL.
2733 * The length of the DLL is kept in #pa_count.
2734 */
2735static struct PendingAcknowledgement *pa_tail;
2736
2737/**
2738 * List of incoming connections where we are trying
2739 * to get a connection back established. Length
2740 * kept in #ir_total.
2741 */
2742static struct IncomingRequest *ir_head;
2743
2744/**
2745 * Tail of DLL starting at #ir_head.
2746 */
2747static struct IncomingRequest *ir_tail;
2748
2749/**
2750 * Length of the DLL starting at #ir_head.
2751 */
2752static unsigned int ir_total;
2753
2754/**
2755 * Generator of `logging_uuid` in `struct PendingMessage`.
2756 */
2757static unsigned long long logging_uuid_gen;
2758
2759/**
2760 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2761 * limit the size of the data structure.
2762 */
2763static unsigned int pa_count;
2764
2765/**
2766 * Monotonic time we use for HELLOs generated at this time. TODO: we
2767 * should increase this value from time to time (i.e. whenever a
2768 * `struct AddressListEntry` actually expires), but IF we do this, we
2769 * must also update *all* (remaining) addresses in the PEERSTORE at
2770 * that time! (So for now only increased when the peer is restarted,
2771 * which hopefully roughly matches whenever our addresses change.)
2772 */
2773static struct GNUNET_TIME_Absolute hello_mono_time;
2774
2775/**
2776 * Indication if we have received a shutdown signal
2777 * and are in the process of cleaning up.
2778 */
2779static int in_shutdown;
2780
2781/**
2782 * Get an offset into the transmission history buffer for `struct
2783 * PerformanceData`. Note that the caller must perform the required
2784 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2785 * array!
2786 *
2787 * An 'age' lasts 15 minute slots.
2788 *
2789 * @return current age of the world
2790 */
2791static unsigned int
2792get_age ()
2793{
2794 struct GNUNET_TIME_Absolute now;
2795
2796 now = GNUNET_TIME_absolute_get ();
2797 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2798}
2799
2800
2801/**
2802 * Release @a ir data structure.
2803 *
2804 * @param ir data structure to release
2805 */
2806static void
2807free_incoming_request (struct IncomingRequest *ir)
2808{
2809 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
2810 GNUNET_assert (ir_total > 0);
2811 ir_total--;
2812 GNUNET_PEERSTORE_watch_cancel (ir->wc);
2813 ir->wc = NULL;
2814 GNUNET_free (ir);
2815}
2816
2817
2818/**
2819 * Release @a pa data structure.
2820 *
2821 * @param pa data structure to release
2822 */
2823static void
2824free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2825{
2826 struct Queue *q = pa->queue;
2827 struct PendingMessage *pm = pa->pm;
2828 struct DistanceVectorHop *dvh = pa->dvh;
2829
2830 GNUNET_CONTAINER_MDLL_remove (pa, pa_head, pa_tail, pa);
2831 pa_count--;
2832 if (NULL != q)
2833 {
2834 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2835 pa->queue = NULL;
2836 }
2837 if (NULL != pm)
2838 {
2839 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2840 pa->pm = NULL;
2841 }
2842 if (NULL != dvh)
2843 {
2844 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2845 pa->queue = NULL;
2846 }
2847 GNUNET_assert (GNUNET_YES ==
2848 GNUNET_CONTAINER_multiuuidmap_remove (pending_acks,
2849 &pa->ack_uuid.value,
2850 pa));
2851 GNUNET_free (pa);
2852}
2853
2854
2855/**
2856 * Free fragment tree below @e root, excluding @e root itself.
2857 * FIXME: this does NOT seem to have the intended semantics
2858 * based on how this is called. Seems we generally DO expect
2859 * @a root to be free'ed itself as well!
2860 *
2861 * @param root root of the tree to free
2862 */
2863static void
2864free_fragment_tree (struct PendingMessage *root)
2865{
2866 struct PendingMessage *frag;
2867
2868 while (NULL != (frag = root->head_frag))
2869 {
2870 struct PendingAcknowledgement *pa;
2871
2872 free_fragment_tree (frag);
2873 while (NULL != (pa = frag->pa_head))
2874 {
2875 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
2876 pa->pm = NULL;
2877 }
2878 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2879 GNUNET_free (frag);
2880 }
2881}
2882
2883
2884/**
2885 * Release memory associated with @a pm and remove @a pm from associated
2886 * data structures. @a pm must be a top-level pending message and not
2887 * a fragment in the tree. The entire tree is freed (if applicable).
2888 *
2889 * @param pm the pending message to free
2890 */
2891static void
2892free_pending_message (struct PendingMessage *pm)
2893{
2894 struct TransportClient *tc = pm->client;
2895 struct VirtualLink *vl = pm->vl;
2896 struct PendingAcknowledgement *pa;
2897
2898 if (NULL != tc)
2899 {
2900 GNUNET_CONTAINER_MDLL_remove (client,
2901 tc->details.core.pending_msg_head,
2902 tc->details.core.pending_msg_tail,
2903 pm);
2904 }
2905 if (NULL != vl)
2906 {
2907 GNUNET_CONTAINER_MDLL_remove (vl,
2908 vl->pending_msg_head,
2909 vl->pending_msg_tail,
2910 pm);
2911 }
2912 while (NULL != (pa = pm->pa_head))
2913 {
2914 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2915 pa->pm = NULL;
2916 }
2917
2918 free_fragment_tree (pm);
2919 if (NULL != pm->qe)
2920 {
2921 GNUNET_assert (pm == pm->qe->pm);
2922 pm->qe->pm = NULL;
2923 }
2924 if (NULL != pm->bpm)
2925 {
2926 free_fragment_tree (pm->bpm);
2927 GNUNET_free (pm->bpm);
2928 }
2929 GNUNET_free (pm);
2930}
2931
2932
2933/**
2934 * Free virtual link.
2935 *
2936 * @param vl link data to free
2937 */
2938static void
2939free_virtual_link (struct VirtualLink *vl)
2940{
2941 struct PendingMessage *pm;
2942 struct CoreSentContext *csc;
2943
2944 while (NULL != (pm = vl->pending_msg_head))
2945 free_pending_message (pm);
2946 GNUNET_assert (GNUNET_YES ==
2947 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl));
2948 if (NULL != vl->visibility_task)
2949 {
2950 GNUNET_SCHEDULER_cancel (vl->visibility_task);
2951 vl->visibility_task = NULL;
2952 }
2953 if (NULL != vl->fc_retransmit_task)
2954 {
2955 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
2956 vl->fc_retransmit_task = NULL;
2957 }
2958 while (NULL != (csc = vl->csc_head))
2959 {
2960 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
2961 GNUNET_assert (vl == csc->vl);
2962 csc->vl = NULL;
2963 }
2964 GNUNET_break (NULL == vl->n);
2965 GNUNET_break (NULL == vl->dv);
2966 GNUNET_free (vl);
2967}
2968
2969
2970/**
2971 * Free validation state.
2972 *
2973 * @param vs validation state to free
2974 */
2975static void
2976free_validation_state (struct ValidationState *vs)
2977{
2978 GNUNET_assert (
2979 GNUNET_YES ==
2980 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs));
2981 GNUNET_CONTAINER_heap_remove_node (vs->hn);
2982 vs->hn = NULL;
2983 if (NULL != vs->sc)
2984 {
2985 GNUNET_PEERSTORE_store_cancel (vs->sc);
2986 vs->sc = NULL;
2987 }
2988 GNUNET_free (vs->address);
2989 GNUNET_free (vs);
2990}
2991
2992
2993/**
2994 * Lookup neighbour for peer @a pid.
2995 *
2996 * @param pid neighbour to look for
2997 * @return NULL if we do not have this peer as a neighbour
2998 */
2999static struct Neighbour *
3000lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
3001{
3002 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
3003}
3004
3005
3006/**
3007 * Lookup virtual link for peer @a pid.
3008 *
3009 * @param pid virtual link to look for
3010 * @return NULL if we do not have this peer as a virtual link
3011 */
3012static struct VirtualLink *
3013lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3014{
3015 return GNUNET_CONTAINER_multipeermap_get (links, pid);
3016}
3017
3018
3019/**
3020 * Details about what to notify monitors about.
3021 */
3022struct MonitorEvent
3023{
3024 /**
3025 * @deprecated To be discussed if we keep these...
3026 */
3027 struct GNUNET_TIME_Absolute last_validation;
3028 struct GNUNET_TIME_Absolute valid_until;
3029 struct GNUNET_TIME_Absolute next_validation;
3030
3031 /**
3032 * Current round-trip time estimate.
3033 */
3034 struct GNUNET_TIME_Relative rtt;
3035
3036 /**
3037 * Connection status.
3038 */
3039 enum GNUNET_TRANSPORT_ConnectionStatus cs;
3040
3041 /**
3042 * Messages pending.
3043 */
3044 uint32_t num_msg_pending;
3045
3046 /**
3047 * Bytes pending.
3048 */
3049 uint32_t num_bytes_pending;
3050};
3051
3052
3053/**
3054 * Free a @dvh. Callers MAY want to check if this was the last path to the
3055 * `target`, and if so call #free_dv_route to also free the associated DV
3056 * entry in #dv_routes (if not, the associated scheduler job should eventually
3057 * take care of it).
3058 *
3059 * @param dvh hop to free
3060 */
3061static void
3062free_distance_vector_hop (struct DistanceVectorHop *dvh)
3063{
3064 struct Neighbour *n = dvh->next_hop;
3065 struct DistanceVector *dv = dvh->dv;
3066 struct PendingAcknowledgement *pa;
3067
3068 while (NULL != (pa = dvh->pa_head))
3069 {
3070 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3071 pa->dvh = NULL;
3072 }
3073 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3074 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
3075 GNUNET_free (dvh);
3076}
3077
3078
3079/**
3080 * Task run to check whether the hops of the @a cls still
3081 * are validated, or if we need to core about disconnection.
3082 *
3083 * @param cls a `struct VirtualLink`
3084 */
3085static void
3086check_link_down (void *cls);
3087
3088
3089/**
3090 * Send message to CORE clients that we lost a connection.
3091 *
3092 * @param pid peer the connection was for
3093 */
3094static void
3095cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3096{
3097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3098 "Informing CORE clients about disconnect from %s\n",
3099 GNUNET_i2s (pid));
3100 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3101 {
3102 struct GNUNET_MQ_Envelope *env;
3103 struct DisconnectInfoMessage *dim;
3104
3105 if (CT_CORE != tc->type)
3106 continue;
3107 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3108 dim->peer = *pid;
3109 GNUNET_MQ_send (tc->mq, env);
3110 }
3111}
3112
3113
3114/**
3115 * Free entry in #dv_routes. First frees all hops to the target, and
3116 * if there are no entries left, frees @a dv as well.
3117 *
3118 * @param dv route to free
3119 */
3120static void
3121free_dv_route (struct DistanceVector *dv)
3122{
3123 struct DistanceVectorHop *dvh;
3124
3125 while (NULL != (dvh = dv->dv_head))
3126 free_distance_vector_hop (dvh);
3127 if (NULL == dv->dv_head)
3128 {
3129 struct VirtualLink *vl;
3130
3131 GNUNET_assert (
3132 GNUNET_YES ==
3133 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
3134 if (NULL != (vl = dv->vl))
3135 {
3136 GNUNET_assert (dv == vl->dv);
3137 vl->dv = NULL;
3138 if (NULL == vl->n)
3139 {
3140 cores_send_disconnect_info (&dv->target);
3141 free_virtual_link (vl);
3142 }
3143 else
3144 {
3145 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3146 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3147 }
3148 dv->vl = NULL;
3149 }
3150
3151 if (NULL != dv->timeout_task)
3152 {
3153 GNUNET_SCHEDULER_cancel (dv->timeout_task);
3154 dv->timeout_task = NULL;
3155 }
3156 GNUNET_free (dv);
3157 }
3158}
3159
3160
3161/**
3162 * Notify monitor @a tc about an event. That @a tc
3163 * cares about the event has already been checked.
3164 *
3165 * Send @a tc information in @a me about a @a peer's status with
3166 * respect to some @a address to all monitors that care.
3167 *
3168 * @param tc monitor to inform
3169 * @param peer peer the information is about
3170 * @param address address the information is about
3171 * @param nt network type associated with @a address
3172 * @param me detailed information to transmit
3173 */
3174static void
3175notify_monitor (struct TransportClient *tc,
3176 const struct GNUNET_PeerIdentity *peer,
3177 const char *address,
3178 enum GNUNET_NetworkType nt,
3179 const struct MonitorEvent *me)
3180{
3181 struct GNUNET_MQ_Envelope *env;
3182 struct GNUNET_TRANSPORT_MonitorData *md;
3183 size_t addr_len = strlen (address) + 1;
3184
3185 env = GNUNET_MQ_msg_extra (md,
3186 addr_len,
3187 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
3188 md->nt = htonl ((uint32_t) nt);
3189 md->peer = *peer;
3190 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
3191 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
3192 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
3193 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
3194 md->cs = htonl ((uint32_t) me->cs);
3195 md->num_msg_pending = htonl (me->num_msg_pending);
3196 md->num_bytes_pending = htonl (me->num_bytes_pending);
3197 memcpy (&md[1], address, addr_len);
3198 GNUNET_MQ_send (tc->mq, env);
3199}
3200
3201
3202/**
3203 * Send information in @a me about a @a peer's status with respect
3204 * to some @a address to all monitors that care.
3205 *
3206 * @param peer peer the information is about
3207 * @param address address the information is about
3208 * @param nt network type associated with @a address
3209 * @param me detailed information to transmit
3210 */
3211static void
3212notify_monitors (const struct GNUNET_PeerIdentity *peer,
3213 const char *address,
3214 enum GNUNET_NetworkType nt,
3215 const struct MonitorEvent *me)
3216{
3217 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3218 {
3219 if (CT_MONITOR != tc->type)
3220 continue;
3221 if (tc->details.monitor.one_shot)
3222 continue;
3223 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
3224 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
3225 continue;
3226 notify_monitor (tc, peer, address, nt, me);
3227 }
3228}
3229
3230
3231/**
3232 * Called whenever a client connects. Allocates our
3233 * data structures associated with that client.
3234 *
3235 * @param cls closure, NULL
3236 * @param client identification of the client
3237 * @param mq message queue for the client
3238 * @return our `struct TransportClient`
3239 */
3240static void *
3241client_connect_cb (void *cls,
3242 struct GNUNET_SERVICE_Client *client,
3243 struct GNUNET_MQ_Handle *mq)
3244{
3245 struct TransportClient *tc;
3246
3247 (void) cls;
3248 tc = GNUNET_new (struct TransportClient);
3249 tc->client = client;
3250 tc->mq = mq;
3251 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
3252 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
3253 return tc;
3254}
3255
3256
3257/**
3258 * Free @a rc
3259 *
3260 * @param rc data structure to free
3261 */
3262static void
3263free_reassembly_context (struct ReassemblyContext *rc)
3264{
3265 struct Neighbour *n = rc->neighbour;
3266
3267 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
3268 GNUNET_assert (GNUNET_OK ==
3269 GNUNET_CONTAINER_multihashmap32_remove (n->reassembly_map,
3270 rc->msg_uuid.uuid,
3271 rc));
3272 GNUNET_free (rc);
3273}
3274
3275
3276/**
3277 * Task run to clean up reassembly context of a neighbour that have expired.
3278 *
3279 * @param cls a `struct Neighbour`
3280 */
3281static void
3282reassembly_cleanup_task (void *cls)
3283{
3284 struct Neighbour *n = cls;
3285 struct ReassemblyContext *rc;
3286
3287 n->reassembly_timeout_task = NULL;
3288 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (n->reassembly_heap)))
3289 {
3290 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
3291 .rel_value_us)
3292 {
3293 free_reassembly_context (rc);
3294 continue;
3295 }
3296 GNUNET_assert (NULL == n->reassembly_timeout_task);
3297 n->reassembly_timeout_task =
3298 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
3299 &reassembly_cleanup_task,
3300 n);
3301 return;
3302 }
3303}
3304
3305
3306/**
3307 * function called to #free_reassembly_context().
3308 *
3309 * @param cls NULL
3310 * @param key unused
3311 * @param value a `struct ReassemblyContext` to free
3312 * @return #GNUNET_OK (continue iteration)
3313 */
3314static int
3315free_reassembly_cb (void *cls, uint32_t key, void *value)
3316{
3317 struct ReassemblyContext *rc = value;
3318
3319 (void) cls;
3320 (void) key;
3321 free_reassembly_context (rc);
3322 return GNUNET_OK;
3323}
3324
3325
3326/**
3327 * Release memory used by @a neighbour.
3328 *
3329 * @param neighbour neighbour entry to free
3330 */
3331static void
3332free_neighbour (struct Neighbour *neighbour)
3333{
3334 struct DistanceVectorHop *dvh;
3335 struct VirtualLink *vl;
3336
3337 GNUNET_assert (NULL == neighbour->queue_head);
3338 GNUNET_assert (GNUNET_YES ==
3339 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3340 &neighbour->pid,
3341 neighbour));
3342 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3343 "Freeing neighbour\n");
3344 if (NULL != neighbour->reassembly_map)
3345 {
3346 GNUNET_CONTAINER_multihashmap32_iterate (neighbour->reassembly_map,
3347 &free_reassembly_cb,
3348 NULL);
3349 GNUNET_CONTAINER_multihashmap32_destroy (neighbour->reassembly_map);
3350 neighbour->reassembly_map = NULL;
3351 GNUNET_CONTAINER_heap_destroy (neighbour->reassembly_heap);
3352 neighbour->reassembly_heap = NULL;
3353 }
3354 while (NULL != (dvh = neighbour->dv_head))
3355 {
3356 struct DistanceVector *dv = dvh->dv;
3357
3358 free_distance_vector_hop (dvh);
3359 if (NULL == dv->dv_head)
3360 free_dv_route (dv);
3361 }
3362 if (NULL != neighbour->reassembly_timeout_task)
3363 {
3364 GNUNET_SCHEDULER_cancel (neighbour->reassembly_timeout_task);
3365 neighbour->reassembly_timeout_task = NULL;
3366 }
3367 if (NULL != neighbour->get)
3368 {
3369 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
3370 neighbour->get = NULL;
3371 }
3372 if (NULL != neighbour->sc)
3373 {
3374 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3375 neighbour->sc = NULL;
3376 }
3377 if (NULL != (vl = neighbour->vl))
3378 {
3379 GNUNET_assert (neighbour == vl->n);
3380 vl->n = NULL;
3381 if (NULL == vl->dv)
3382 {
3383 cores_send_disconnect_info (&vl->target);
3384 free_virtual_link (vl);
3385 }
3386 else
3387 {
3388 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3389 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3390 }
3391 neighbour->vl = NULL;
3392 }
3393 GNUNET_free (neighbour);
3394}
3395
3396
3397/**
3398 * Send message to CORE clients that we lost a connection.
3399 *
3400 * @param tc client to inform (must be CORE client)
3401 * @param pid peer the connection is for
3402 */
3403static void
3404core_send_connect_info (struct TransportClient *tc,
3405 const struct GNUNET_PeerIdentity *pid)
3406{
3407 struct GNUNET_MQ_Envelope *env;
3408 struct ConnectInfoMessage *cim;
3409
3410 GNUNET_assert (CT_CORE == tc->type);
3411 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3412 cim->id = *pid;
3413 GNUNET_MQ_send (tc->mq, env);
3414}
3415
3416
3417/**
3418 * Send message to CORE clients that we gained a connection
3419 *
3420 * @param pid peer the queue was for
3421 */
3422static void
3423cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3424{
3425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3426 "Informing CORE clients about connection to %s\n",
3427 GNUNET_i2s (pid));
3428 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3429 {
3430 if (CT_CORE != tc->type)
3431 continue;
3432 core_send_connect_info (tc, pid);
3433 }
3434}
3435
3436
3437/**
3438 * We believe we are ready to transmit a message on a queue. Gives the
3439 * message to the communicator for transmission (updating the tracker,
3440 * and re-scheduling itself if applicable).
3441 *
3442 * @param cls the `struct Queue` to process transmissions for
3443 */
3444static void
3445transmit_on_queue (void *cls);
3446
3447
3448/**
3449 * Called whenever something changed that might effect when we
3450 * try to do the next transmission on @a queue using #transmit_on_queue().
3451 *
3452 * @param queue the queue to do scheduling for
3453 * @param p task priority to use, if @a queue is scheduled
3454 */
3455static void
3456schedule_transmit_on_queue (struct Queue *queue,
3457 enum GNUNET_SCHEDULER_Priority p)
3458{
3459 if (queue->tc->details.communicator.total_queue_length >=
3460 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3461 {
3462 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3463 "Transmission throttled due to communicator queue limit\n");
3464 GNUNET_STATISTICS_update (
3465 GST_stats,
3466 "# Transmission throttled due to communicator queue limit",
3467 1,
3468 GNUNET_NO);
3469 queue->idle = GNUNET_NO;
3470 return;
3471 }
3472 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3473 {
3474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3475 "Transmission throttled due to communicator queue length limit\n");
3476 GNUNET_STATISTICS_update (GST_stats,
3477 "# Transmission throttled due to queue queue limit",
3478 1,
3479 GNUNET_NO);
3480 queue->idle = GNUNET_NO;
3481 return;
3482 }
3483 /* queue might indeed be ready, schedule it */
3484 if (NULL != queue->transmit_task)
3485 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3486 queue->transmit_task =
3487 GNUNET_SCHEDULER_add_with_priority (p, &transmit_on_queue, queue);
3488 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3489 "Considering transmission on queue `%s' to %s\n",
3490 queue->address,
3491 GNUNET_i2s (&queue->neighbour->pid));
3492}
3493
3494
3495/**
3496 * Task run to check whether the hops of the @a cls still
3497 * are validated, or if we need to core about disconnection.
3498 *
3499 * @param cls a `struct VirtualLink`
3500 */
3501static void
3502check_link_down (void *cls)
3503{
3504 struct VirtualLink *vl = cls;
3505 struct DistanceVector *dv = vl->dv;
3506 struct Neighbour *n = vl->n;
3507 struct GNUNET_TIME_Absolute dvh_timeout;
3508 struct GNUNET_TIME_Absolute q_timeout;
3509
3510 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3511 "Checking if link is down\n");
3512 vl->visibility_task = NULL;
3513 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3514 if (NULL != dv)
3515 {
3516 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3517 pos = pos->next_dv)
3518 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
3519 pos->path_valid_until);
3520 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3521 {
3522 vl->dv->vl = NULL;
3523 vl->dv = NULL;
3524 }
3525 }
3526 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3527 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3528 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3529 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3530 {
3531 vl->n->vl = NULL;
3532 vl->n = NULL;
3533 }
3534 if ((NULL == vl->n) && (NULL == vl->dv))
3535 {
3536 cores_send_disconnect_info (&vl->target);
3537 free_virtual_link (vl);
3538 return;
3539 }
3540 vl->visibility_task =
3541 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3542 &check_link_down,
3543 vl);
3544}
3545
3546
3547/**
3548 * Free @a queue.
3549 *
3550 * @param queue the queue to free
3551 */
3552static void
3553free_queue (struct Queue *queue)
3554{
3555 struct Neighbour *neighbour = queue->neighbour;
3556 struct TransportClient *tc = queue->tc;
3557 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
3558 .rtt = GNUNET_TIME_UNIT_FOREVER_REL };
3559 struct QueueEntry *qe;
3560 int maxxed;
3561 struct PendingAcknowledgement *pa;
3562 struct VirtualLink *vl;
3563
3564 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3565 "Cleaning up queue %u\n", queue->qid);
3566 if (NULL != queue->transmit_task)
3567 {
3568 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3569 queue->transmit_task = NULL;
3570 }
3571 while (NULL != (pa = queue->pa_head))
3572 {
3573 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3574 pa->queue = NULL;
3575 }
3576
3577 GNUNET_CONTAINER_MDLL_remove (neighbour,
3578 neighbour->queue_head,
3579 neighbour->queue_tail,
3580 queue);
3581 GNUNET_CONTAINER_MDLL_remove (client,
3582 tc->details.communicator.queue_head,
3583 tc->details.communicator.queue_tail,
3584 queue);
3585 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT >=
3586 tc->details.communicator.total_queue_length);
3587 while (NULL != (qe = queue->queue_head))
3588 {
3589 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3590 queue->queue_length--;
3591 tc->details.communicator.total_queue_length--;
3592 if (NULL != qe->pm)
3593 {
3594 GNUNET_assert (qe == qe->pm->qe);
3595 qe->pm->qe = NULL;
3596 }
3597 GNUNET_free (qe);
3598 }
3599 GNUNET_assert (0 == queue->queue_length);
3600 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT <
3601 tc->details.communicator.total_queue_length))
3602 {
3603 /* Communicator dropped below threshold, resume all _other_ queues */
3604 GNUNET_STATISTICS_update (
3605 GST_stats,
3606 "# Transmission throttled due to communicator queue limit",
3607 -1,
3608 GNUNET_NO);
3609 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3610 s = s->next_client)
3611 schedule_transmit_on_queue (s, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
3612 }
3613 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3614 GNUNET_free (queue);
3615
3616 vl = lookup_virtual_link (&neighbour->pid);
3617 if ((NULL != vl) && (neighbour == vl->n))
3618 {
3619 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3620 check_link_down (vl);
3621 }
3622 if (NULL == neighbour->queue_head)
3623 {
3624 free_neighbour (neighbour);
3625 }
3626}
3627
3628
3629/**
3630 * Free @a ale
3631 *
3632 * @param ale address list entry to free
3633 */
3634static void
3635free_address_list_entry (struct AddressListEntry *ale)
3636{
3637 struct TransportClient *tc = ale->tc;
3638
3639 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3640 tc->details.communicator.addr_tail,
3641 ale);
3642 if (NULL != ale->sc)
3643 {
3644 GNUNET_PEERSTORE_store_cancel (ale->sc);
3645 ale->sc = NULL;
3646 }
3647 if (NULL != ale->st)
3648 {
3649 GNUNET_SCHEDULER_cancel (ale->st);
3650 ale->st = NULL;
3651 }
3652 GNUNET_free (ale);
3653}
3654
3655
3656/**
3657 * Stop the peer request in @a value.
3658 *
3659 * @param cls a `struct TransportClient` that no longer makes the request
3660 * @param pid the peer's identity
3661 * @param value a `struct PeerRequest`
3662 * @return #GNUNET_YES (always)
3663 */
3664static int
3665stop_peer_request (void *cls,
3666 const struct GNUNET_PeerIdentity *pid,
3667 void *value)
3668{
3669 struct TransportClient *tc = cls;
3670 struct PeerRequest *pr = value;
3671
3672 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3673 pr->wc = NULL;
3674 GNUNET_assert (
3675 GNUNET_YES ==
3676 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3677 pid,
3678 pr));
3679 GNUNET_free (pr);
3680
3681 return GNUNET_OK;
3682}
3683
3684
3685static void
3686do_shutdown (void *cls);
3687
3688/**
3689 * Called whenever a client is disconnected. Frees our
3690 * resources associated with that client.
3691 *
3692 * @param cls closure, NULL
3693 * @param client identification of the client
3694 * @param app_ctx our `struct TransportClient`
3695 */
3696static void
3697client_disconnect_cb (void *cls,
3698 struct GNUNET_SERVICE_Client *client,
3699 void *app_ctx)
3700{
3701 struct TransportClient *tc = app_ctx;
3702
3703 (void) cls;
3704 (void) client;
3705 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3706 switch (tc->type)
3707 {
3708 case CT_NONE:
3709 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3710 "Unknown Client %p disconnected, cleaning up.\n",
3711 tc);
3712 break;
3713
3714 case CT_CORE: {
3715 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3716 "CORE Client %p disconnected, cleaning up.\n",
3717 tc);
3718
3719 struct PendingMessage *pm;
3720
3721 while (NULL != (pm = tc->details.core.pending_msg_head))
3722 {
3723 GNUNET_CONTAINER_MDLL_remove (client,
3724 tc->details.core.pending_msg_head,
3725 tc->details.core.pending_msg_tail,
3726 pm);
3727 pm->client = NULL;
3728 }
3729 }
3730 break;
3731
3732 case CT_MONITOR:
3733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3734 "MONITOR Client %p disconnected, cleaning up.\n",
3735 tc);
3736
3737 break;
3738
3739 case CT_COMMUNICATOR: {
3740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3741 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
3742 tc);
3743
3744 struct Queue *q;
3745 struct AddressListEntry *ale;
3746
3747 while (NULL != (q = tc->details.communicator.queue_head))
3748 free_queue (q);
3749 while (NULL != (ale = tc->details.communicator.addr_head))
3750 free_address_list_entry (ale);
3751 GNUNET_free (tc->details.communicator.address_prefix);
3752 }
3753 break;
3754
3755 case CT_APPLICATION:
3756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3757 "APPLICATION Client %p disconnected, cleaning up.\n",
3758 tc);
3759
3760 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3761 &stop_peer_request,
3762 tc);
3763 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3764 break;
3765 }
3766 GNUNET_free (tc);
3767 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
3768 {
3769 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3770 "Our last client disconnected\n");
3771 do_shutdown (cls);
3772 }
3773}
3774
3775
3776/**
3777 * Iterator telling new CORE client about all existing
3778 * connections to peers.
3779 *
3780 * @param cls the new `struct TransportClient`
3781 * @param pid a connected peer
3782 * @param value the `struct Neighbour` with more information
3783 * @return #GNUNET_OK (continue to iterate)
3784 */
3785static int
3786notify_client_connect_info (void *cls,
3787 const struct GNUNET_PeerIdentity *pid,
3788 void *value)
3789{
3790 struct TransportClient *tc = cls;
3791
3792 (void) value;
3793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3794 "Telling new CORE client about existing connection to %s\n",
3795 GNUNET_i2s (pid));
3796 core_send_connect_info (tc, pid);
3797 return GNUNET_OK;
3798}
3799
3800
3801/**
3802 * Initialize a "CORE" client. We got a start message from this
3803 * client, so add it to the list of clients for broadcasting of
3804 * inbound messages.
3805 *
3806 * @param cls the client
3807 * @param start the start message that was sent
3808 */
3809static void
3810handle_client_start (void *cls, const struct StartMessage *start)
3811{
3812 struct TransportClient *tc = cls;
3813 uint32_t options;
3814
3815 options = ntohl (start->options);
3816 if ((0 != (1 & options)) &&
3817 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3818 {
3819 /* client thinks this is a different peer, reject */
3820 GNUNET_break (0);
3821 GNUNET_SERVICE_client_drop (tc->client);
3822 return;
3823 }
3824 if (CT_NONE != tc->type)
3825 {
3826 GNUNET_break (0);
3827 GNUNET_SERVICE_client_drop (tc->client);
3828 return;
3829 }
3830 tc->type = CT_CORE;
3831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3832 "New CORE client with PID %s registered\n",
3833 GNUNET_i2s (&start->self));
3834 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
3835 &notify_client_connect_info,
3836 tc);
3837 GNUNET_SERVICE_client_continue (tc->client);
3838}
3839
3840
3841/**
3842 * Client asked for transmission to a peer. Process the request.
3843 *
3844 * @param cls the client
3845 * @param obm the send message that was sent
3846 */
3847static int
3848check_client_send (void *cls, const struct OutboundMessage *obm)
3849{
3850 struct TransportClient *tc = cls;
3851 uint16_t size;
3852 const struct GNUNET_MessageHeader *obmm;
3853
3854 if (CT_CORE != tc->type)
3855 {
3856 GNUNET_break (0);
3857 return GNUNET_SYSERR;
3858 }
3859 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
3860 if (size < sizeof(struct GNUNET_MessageHeader))
3861 {
3862 GNUNET_break (0);
3863 return GNUNET_SYSERR;
3864 }
3865 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
3866 if (size != ntohs (obmm->size))
3867 {
3868 GNUNET_break (0);
3869 return GNUNET_SYSERR;
3870 }
3871 return GNUNET_OK;
3872}
3873
3874
3875/**
3876 * Send a response to the @a pm that we have processed a "send"
3877 * request. Sends a confirmation to the "core" client responsible for
3878 * the original request and free's @a pm.
3879 *
3880 * @param pm handle to the original pending message
3881 */
3882static void
3883client_send_response (struct PendingMessage *pm)
3884{
3885 struct TransportClient *tc = pm->client;
3886 struct VirtualLink *vl = pm->vl;
3887
3888 if (NULL != tc)
3889 {
3890 struct GNUNET_MQ_Envelope *env;
3891 struct SendOkMessage *so_msg;
3892
3893 env = GNUNET_MQ_msg (so_msg, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
3894 so_msg->peer = vl->target;
3895 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3896 "Confirming transmission of <%llu> to %s\n",
3897 pm->logging_uuid,
3898 GNUNET_i2s (&vl->target));
3899 GNUNET_MQ_send (tc->mq, env);
3900 }
3901 free_pending_message (pm);
3902}
3903
3904
3905/**
3906 * Pick @a hops_array_length random DV paths satisfying @a options
3907 *
3908 * @param dv data structure to pick paths from
3909 * @param options constraints to satisfy
3910 * @param hops_array[out] set to the result
3911 * @param hops_array_length length of the @a hops_array
3912 * @return number of entries set in @a hops_array
3913 */
3914static unsigned int
3915pick_random_dv_hops (const struct DistanceVector *dv,
3916 enum RouteMessageOptions options,
3917 struct DistanceVectorHop **hops_array,
3918 unsigned int hops_array_length)
3919{
3920 uint64_t choices[hops_array_length];
3921 uint64_t num_dv;
3922 unsigned int dv_count;
3923
3924 /* Pick random vectors, but weighted by distance, giving more weight
3925 to shorter vectors */
3926 num_dv = 0;
3927 dv_count = 0;
3928 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3929 pos = pos->next_dv)
3930 {
3931 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3932 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3933 .rel_value_us == 0))
3934 continue; /* pos unconfirmed and confirmed required */
3935 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
3936 dv_count++;
3937 }
3938 if (0 == dv_count)
3939 return 0;
3940 if (dv_count <= hops_array_length)
3941 {
3942 dv_count = 0;
3943 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3944 pos = pos->next_dv)
3945 hops_array[dv_count++] = pos;
3946 return dv_count;
3947 }
3948 for (unsigned int i = 0; i < hops_array_length; i++)
3949 {
3950 int ok = GNUNET_NO;
3951 while (GNUNET_NO == ok)
3952 {
3953 choices[i] =
3954 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
3955 ok = GNUNET_YES;
3956 for (unsigned int j = 0; j < i; j++)
3957 if (choices[i] == choices[j])
3958 {
3959 ok = GNUNET_NO;
3960 break;
3961 }
3962 }
3963 }
3964 dv_count = 0;
3965 num_dv = 0;
3966 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3967 pos = pos->next_dv)
3968 {
3969 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
3970
3971 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
3972 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
3973 .rel_value_us == 0))
3974 continue; /* pos unconfirmed and confirmed required */
3975 for (unsigned int i = 0; i < hops_array_length; i++)
3976 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
3977 hops_array[dv_count++] = pos;
3978 num_dv += delta;
3979 }
3980 return dv_count;
3981}
3982
3983
3984/**
3985 * Communicator started. Test message is well-formed.
3986 *
3987 * @param cls the client
3988 * @param cam the send message that was sent
3989 */
3990static int
3991check_communicator_available (
3992 void *cls,
3993 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
3994{
3995 struct TransportClient *tc = cls;
3996 uint16_t size;
3997
3998 if (CT_NONE != tc->type)
3999 {
4000 GNUNET_break (0);
4001 return GNUNET_SYSERR;
4002 }
4003 tc->type = CT_COMMUNICATOR;
4004 size = ntohs (cam->header.size) - sizeof(*cam);
4005 if (0 == size)
4006 return GNUNET_OK; /* receive-only communicator */
4007 GNUNET_MQ_check_zero_termination (cam);
4008 return GNUNET_OK;
4009}
4010
4011
4012/**
4013 * Send ACK to communicator (if requested) and free @a cmc.
4014 *
4015 * @param cmc context for which we are done handling the message
4016 */
4017static void
4018finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4019{
4020 if (0 != ntohl (cmc->im.fc_on))
4021 {
4022 /* send ACK when done to communicator for flow control! */
4023 struct GNUNET_MQ_Envelope *env;
4024 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4025
4026 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4027 ack->reserved = htonl (0);
4028 ack->fc_id = cmc->im.fc_id;
4029 ack->sender = cmc->im.sender;
4030 GNUNET_MQ_send (cmc->tc->mq, env);
4031 }
4032 GNUNET_SERVICE_client_continue (cmc->tc->client);
4033 GNUNET_free (cmc);
4034}
4035
4036
4037/**
4038 * Client confirms that it is done handling message(s) to a particular
4039 * peer. We may now provide more messages to CORE for this peer.
4040 *
4041 * Notifies the respective queues that more messages can now be received.
4042 *
4043 * @param cls the client
4044 * @param rom the message that was sent
4045 */
4046static void
4047handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4048{
4049 struct TransportClient *tc = cls;
4050 struct VirtualLink *vl;
4051 uint32_t delta;
4052 struct CommunicatorMessageContext *cmc;
4053
4054 if (CT_CORE != tc->type)
4055 {
4056 GNUNET_break (0);
4057 GNUNET_SERVICE_client_drop (tc->client);
4058 return;
4059 }
4060 vl = lookup_virtual_link (&rom->peer);
4061 if (NULL == vl)
4062 {
4063 GNUNET_STATISTICS_update (GST_stats,
4064 "# RECV_OK dropped: virtual link unknown",
4065 1,
4066 GNUNET_NO);
4067 GNUNET_SERVICE_client_continue (tc->client);
4068 return;
4069 }
4070 delta = ntohl (rom->increase_window_delta);
4071 vl->core_recv_window += delta;
4072 if (vl->core_recv_window <= 0)
4073 return;
4074 /* resume communicators */
4075 while (NULL != (cmc = vl->cmc_tail))
4076 {
4077 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4078 finish_cmc_handling (cmc);
4079 }
4080}
4081
4082
4083/**
4084 * Communicator started. Process the request.
4085 *
4086 * @param cls the client
4087 * @param cam the send message that was sent
4088 */
4089static void
4090handle_communicator_available (
4091 void *cls,
4092 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4093{
4094 struct TransportClient *tc = cls;
4095 uint16_t size;
4096
4097 size = ntohs (cam->header.size) - sizeof(*cam);
4098 if (0 == size)
4099 {
4100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4101 "Receive-only communicator connected\n");
4102 return; /* receive-only communicator */
4103 }
4104 tc->details.communicator.address_prefix =
4105 GNUNET_strdup ((const char *) &cam[1]);
4106 tc->details.communicator.cc =
4107 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4109 "Communicator with prefix `%s' connected\n",
4110 tc->details.communicator.address_prefix);
4111 GNUNET_SERVICE_client_continue (tc->client);
4112}
4113
4114
4115/**
4116 * Communicator requests backchannel transmission. Check the request.
4117 *
4118 * @param cls the client
4119 * @param cb the send message that was sent
4120 * @return #GNUNET_OK if message is well-formed
4121 */
4122static int
4123check_communicator_backchannel (
4124 void *cls,
4125 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4126{
4127 const struct GNUNET_MessageHeader *inbox;
4128 const char *is;
4129 uint16_t msize;
4130 uint16_t isize;
4131
4132 (void) cls;
4133 msize = ntohs (cb->header.size) - sizeof(*cb);
4134 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4135 isize = ntohs (inbox->size);
4136 if (isize >= msize)
4137 {
4138 GNUNET_break (0);
4139 return GNUNET_SYSERR;
4140 }
4141 is = (const char *) inbox;
4142 is += isize;
4143 msize -= isize;
4144 GNUNET_assert (0 < msize);
4145 if ('\0' != is[msize - 1])
4146 {
4147 GNUNET_break (0);
4148 return GNUNET_SYSERR;
4149 }
4150 return GNUNET_OK;
4151}
4152
4153
4154/**
4155 * Ensure ephemeral keys in our @a dv are current. If no current one exists,
4156 * set it up.
4157 *
4158 * @param dv[in,out] virtual link to update ephemeral for
4159 */
4160static void
4161update_ephemeral (struct DistanceVector *dv)
4162{
4163 struct EphemeralConfirmationPS ec;
4164
4165 if (0 !=
4166 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
4167 return;
4168 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4169 dv->ephemeral_validity =
4170 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4171 GNUNET_CRYPTO_ecdhe_key_create (&dv->private_key);
4172 GNUNET_CRYPTO_ecdhe_key_get_public (&dv->private_key, &dv->ephemeral_key);
4173 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4174 ec.purpose.size = htonl (sizeof(ec));
4175 ec.target = dv->target;
4176 ec.ephemeral_key = dv->ephemeral_key;
4177 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4178 &ec,
4179 &dv->sender_sig);
4180}
4181
4182
4183/**
4184 * Send the message @a payload on @a queue.
4185 *
4186 * @param queue the queue to use for transmission
4187 * @param pm pending message to update once transmission is done, may be NULL!
4188 * @param payload the payload to send (encapsulated in a
4189 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4190 * @param payload_size number of bytes in @a payload
4191 */
4192static void
4193queue_send_msg (struct Queue *queue,
4194 struct PendingMessage *pm,
4195 const void *payload,
4196 size_t payload_size)
4197{
4198 struct Neighbour *n = queue->neighbour;
4199 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4200 struct GNUNET_MQ_Envelope *env;
4201
4202 GNUNET_log (
4203 GNUNET_ERROR_TYPE_DEBUG,
4204 "Queueing %u bytes of payload for transmission <%llu> on queue %llu to %s\n",
4205 (unsigned int) payload_size,
4206 (NULL == pm) ? 0 : pm->logging_uuid,
4207 (unsigned long long) queue->qid,
4208 GNUNET_i2s (&queue->neighbour->pid));
4209 env = GNUNET_MQ_msg_extra (smt,
4210 payload_size,
4211 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4212 smt->qid = queue->qid;
4213 smt->mid = queue->mid_gen;
4214 smt->receiver = n->pid;
4215 memcpy (&smt[1], payload, payload_size);
4216 {
4217 /* Pass the env to the communicator of queue for transmission. */
4218 struct QueueEntry *qe;
4219
4220 qe = GNUNET_new (struct QueueEntry);
4221 qe->mid = queue->mid_gen++;
4222 qe->queue = queue;
4223 if (NULL != pm)
4224 {
4225 qe->pm = pm;
4226 GNUNET_assert (NULL == pm->qe);
4227 pm->qe = qe;
4228 }
4229 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4230 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4231 queue->queue_length++;
4232 queue->tc->details.communicator.total_queue_length++;
4233 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4234 queue->tc->details.communicator.total_queue_length)
4235 queue->idle = GNUNET_NO;
4236 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4237 queue->idle = GNUNET_NO;
4238 GNUNET_MQ_send (queue->tc->mq, env);
4239 }
4240}
4241
4242
4243/**
4244 * Pick a queue of @a n under constraints @a options and schedule
4245 * transmission of @a hdr.
4246 *
4247 * @param n neighbour to send to
4248 * @param hdr message to send as payload
4249 * @param options whether queues must be confirmed or not,
4250 * and whether we may pick multiple (2) queues
4251 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4252 */
4253static struct GNUNET_TIME_Relative
4254route_via_neighbour (const struct Neighbour *n,
4255 const struct GNUNET_MessageHeader *hdr,
4256 enum RouteMessageOptions options)
4257{
4258 struct GNUNET_TIME_Absolute now;
4259 unsigned int candidates;
4260 unsigned int sel1;
4261 unsigned int sel2;
4262 struct GNUNET_TIME_Relative rtt;
4263
4264 /* Pick one or two 'random' queues from n (under constraints of options) */
4265 now = GNUNET_TIME_absolute_get ();
4266 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4267 weight in the future; weight could be assigned by observed
4268 bandwidth (note: not sure if we should do this for this type
4269 of control traffic though). */
4270 candidates = 0;
4271 for (struct Queue *pos = n->queue_head; NULL != pos;
4272 pos = pos->next_neighbour)
4273 {
4274 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4275 (pos->validated_until.abs_value_us > now.abs_value_us))
4276 candidates++;
4277 }
4278 if (0 == candidates)
4279 {
4280 /* This can happen rarely if the last confirmed queue timed
4281 out just as we were beginning to process this message. */
4282 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4283 "Could not route message of type %u to %s: no valid queue\n",
4284 ntohs (hdr->type),
4285 GNUNET_i2s (&n->pid));
4286 GNUNET_STATISTICS_update (GST_stats,
4287 "# route selection failed (all no valid queue)",
4288 1,
4289 GNUNET_NO);
4290 return GNUNET_TIME_UNIT_FOREVER_REL;
4291 }
4292
4293 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4294 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4295 if (0 == (options & RMO_REDUNDANT))
4296 sel2 = candidates; /* picks none! */
4297 else
4298 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4299 candidates = 0;
4300 for (struct Queue *pos = n->queue_head; NULL != pos;
4301 pos = pos->next_neighbour)
4302 {
4303 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4304 (pos->validated_until.abs_value_us > now.abs_value_us))
4305 {
4306 if ((sel1 == candidates) || (sel2 == candidates))
4307 {
4308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4309 "Routing message of type %u to %s using %s (#%u)\n",
4310 ntohs (hdr->type),
4311 GNUNET_i2s (&n->pid),
4312 pos->address,
4313 (sel1 == candidates) ? 1 : 2);
4314 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4315 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4316 }
4317 candidates++;
4318 }
4319 }
4320 return rtt;
4321}
4322
4323
4324/**
4325 * Structure of the key material used to encrypt backchannel messages.
4326 */
4327struct DVKeyState
4328{
4329 /**
4330 * State of our block cipher.
4331 */
4332 gcry_cipher_hd_t cipher;
4333
4334 /**
4335 * Actual key material.
4336 */
4337 struct
4338 {
4339 /**
4340 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4341 */
4342 struct GNUNET_CRYPTO_AuthKey hmac_key;
4343
4344 /**
4345 * Symmetric key to use for encryption.
4346 */
4347 char aes_key[256 / 8];
4348
4349 /**
4350 * Counter value to use during setup.
4351 */
4352 char aes_ctr[128 / 8];
4353 } material;
4354};
4355
4356
4357/**
4358 * Given the key material in @a km and the initialization vector
4359 * @a iv, setup the key material for the backchannel in @a key.
4360 *
4361 * @param km raw master secret
4362 * @param iv initialization vector
4363 * @param key[out] symmetric cipher and HMAC state to generate
4364 */
4365static void
4366dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4367 const struct GNUNET_ShortHashCode *iv,
4368 struct DVKeyState *key)
4369{
4370 /* must match #dh_key_derive_eph_pub */
4371 GNUNET_assert (GNUNET_YES ==
4372 GNUNET_CRYPTO_kdf (&key->material,
4373 sizeof(key->material),
4374 "transport-backchannel-key",
4375 strlen ("transport-backchannel-key"),
4376 &km,
4377 sizeof(km),
4378 iv,
4379 sizeof(*iv)));
4380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4381 "Deriving backchannel key based on KM %s and IV %s\n",
4382 GNUNET_h2s (km),
4383 GNUNET_sh2s (iv));
4384 GNUNET_assert (0 == gcry_cipher_open (&key->cipher,
4385 GCRY_CIPHER_AES256 /* low level: go for speed */,
4386 GCRY_CIPHER_MODE_CTR,
4387 0 /* flags */));
4388 GNUNET_assert (0 == gcry_cipher_setkey (key->cipher,
4389 &key->material.aes_key,
4390 sizeof(key->material.aes_key)));
4391 gcry_cipher_setctr (key->cipher,
4392 &key->material.aes_ctr,
4393 sizeof(key->material.aes_ctr));
4394}
4395
4396
4397/**
4398 * Derive backchannel encryption key material from @a priv_ephemeral
4399 * and @a target and @a iv.
4400 *
4401 * @param priv_ephemeral ephemeral private key to use
4402 * @param target the target peer to encrypt to
4403 * @param iv unique IV to use
4404 * @param key[out] set to the key material
4405 */
4406static void
4407dh_key_derive_eph_pid (
4408 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4409 const struct GNUNET_PeerIdentity *target,
4410 const struct GNUNET_ShortHashCode *iv,
4411 struct DVKeyState *key)
4412{
4413 struct GNUNET_HashCode km;
4414
4415 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4416 &target->public_key,
4417 &km));
4418 dv_setup_key_state_from_km (&km, iv, key);
4419}
4420
4421
4422/**
4423 * Derive backchannel encryption key material from #GST_my_private_key
4424 * and @a pub_ephemeral and @a iv.
4425 *
4426 * @param priv_ephemeral ephemeral private key to use
4427 * @param target the target peer to encrypt to
4428 * @param iv unique IV to use
4429 * @param key[out] set to the key material
4430 */
4431static void
4432dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4433 const struct GNUNET_ShortHashCode *iv,
4434 struct DVKeyState *key)
4435{
4436 struct GNUNET_HashCode km;
4437
4438 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4439 pub_ephemeral,
4440 &km));
4441 dv_setup_key_state_from_km (&km, iv, key);
4442}
4443
4444
4445/**
4446 * Do HMAC calculation for backchannel messages over @a data using key
4447 * material from @a key.
4448 *
4449 * @param key key material (from DH)
4450 * @param hmac[out] set to the HMAC
4451 * @param data data to perform HMAC calculation over
4452 * @param data_size number of bytes in @a data
4453 */
4454static void
4455dv_hmac (const struct DVKeyState *key,
4456 struct GNUNET_HashCode *hmac,
4457 const void *data,
4458 size_t data_size)
4459{
4460 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4461}
4462
4463
4464/**
4465 * Perform backchannel encryption using symmetric secret in @a key
4466 * to encrypt data from @a in to @a dst.
4467 *
4468 * @param key[in,out] key material to use
4469 * @param dst where to write the result
4470 * @param in input data to encrypt (plaintext)
4471 * @param in_size number of bytes of input in @a in and available at @a dst
4472 */
4473static void
4474dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
4475{
4476 GNUNET_assert (0 ==
4477 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4478}
4479
4480
4481/**
4482 * Perform backchannel encryption using symmetric secret in @a key
4483 * to encrypt data from @a in to @a dst.
4484 *
4485 * @param key[in,out] key material to use
4486 * @param ciph cipher text to decrypt
4487 * @param out[out] output data to generate (plaintext)
4488 * @param out_size number of bytes of input in @a ciph and available in @a out
4489 */
4490static void
4491dv_decrypt (struct DVKeyState *key,
4492 void *out,
4493 const void *ciph,
4494 size_t out_size)
4495{
4496 GNUNET_assert (
4497 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4498}
4499
4500
4501/**
4502 * Clean up key material in @a key.
4503 *
4504 * @param key key material to clean up (memory must not be free'd!)
4505 */
4506static void
4507dv_key_clean (struct DVKeyState *key)
4508{
4509 gcry_cipher_close (key->cipher);
4510 GNUNET_CRYPTO_zero_keys (&key->material, sizeof(key->material));
4511}
4512
4513
4514/**
4515 * Function to call to further operate on the now DV encapsulated
4516 * message @a hdr, forwarding it via @a next_hop under respect of
4517 * @a options.
4518 *
4519 * @param cls closure
4520 * @param next_hop next hop of the DV path
4521 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
4522 * @param options options of the original message
4523 */
4524typedef void (*DVMessageHandler) (void *cls,
4525 struct Neighbour *next_hop,
4526 const struct GNUNET_MessageHeader *hdr,
4527 enum RouteMessageOptions options);
4528
4529/**
4530 * Pick a path of @a dv under constraints @a options and schedule
4531 * transmission of @a hdr.
4532 *
4533 * @param target neighbour to ultimately send to
4534 * @param num_dvhs length of the @a dvhs array
4535 * @param dvhs array of hops to send the message to
4536 * @param hdr message to send as payload
4537 * @param use function to call with the encapsulated message
4538 * @param use_cls closure for @a use
4539 * @param options whether path must be confirmed or not, to be passed to @a use
4540 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4541 */
4542static struct GNUNET_TIME_Relative
4543encapsulate_for_dv (struct DistanceVector *dv,
4544 unsigned int num_dvhs,
4545 struct DistanceVectorHop **dvhs,
4546 const struct GNUNET_MessageHeader *hdr,
4547 DVMessageHandler use,
4548 void *use_cls,
4549 enum RouteMessageOptions options)
4550{
4551 struct TransportDVBoxMessage box_hdr;
4552 struct TransportDVBoxPayloadP payload_hdr;
4553 uint16_t enc_body_size = ntohs (hdr->size);
4554 char enc[sizeof(struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
4555 struct TransportDVBoxPayloadP *enc_payload_hdr =
4556 (struct TransportDVBoxPayloadP *) enc;
4557 struct DVKeyState key;
4558 struct GNUNET_TIME_Relative rtt;
4559
4560 /* Encrypt payload */
4561 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
4562 box_hdr.total_hops = htons (0);
4563 update_ephemeral (dv);
4564 box_hdr.ephemeral_key = dv->ephemeral_key;
4565 payload_hdr.sender_sig = dv->sender_sig;
4566 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4567 &box_hdr.iv,
4568 sizeof(box_hdr.iv));
4569 dh_key_derive_eph_pid (&dv->private_key, &dv->target, &box_hdr.iv, &key);
4570 payload_hdr.sender = GST_my_identity;
4571 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4572 dv_encrypt (&key, &payload_hdr, enc_payload_hdr, sizeof(payload_hdr));
4573 dv_encrypt (&key,
4574 hdr,
4575 &enc[sizeof(struct TransportDVBoxPayloadP)],
4576 enc_body_size);
4577 dv_hmac (&key, &box_hdr.hmac, enc, sizeof(enc));
4578 dv_key_clean (&key);
4579 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4580 /* For each selected path, take the pre-computed header and body
4581 and add the path in the middle of the message; then send it. */
4582 for (unsigned int i = 0; i < num_dvhs; i++)
4583 {
4584 struct DistanceVectorHop *dvh = dvhs[i];
4585 unsigned int num_hops = dvh->distance + 1;
4586 char buf[sizeof(struct TransportDVBoxMessage)
4587 + sizeof(struct GNUNET_PeerIdentity) * num_hops
4588 + sizeof(struct TransportDVBoxPayloadP)
4589 + enc_body_size] GNUNET_ALIGN;
4590 struct GNUNET_PeerIdentity *dhops;
4591
4592 box_hdr.header.size = htons (sizeof(buf));
4593 box_hdr.num_hops = htons (num_hops);
4594 memcpy (buf, &box_hdr, sizeof(box_hdr));
4595 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
4596 memcpy (dhops,
4597 dvh->path,
4598 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
4599 dhops[dvh->distance] = dv->target;
4600 if (GNUNET_EXTRA_LOGGING > 0)
4601 {
4602 char *path;
4603
4604 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
4605 for (unsigned int j = 0; j <= num_hops; j++)
4606 {
4607 char *tmp;
4608
4609 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
4610 GNUNET_free (path);
4611 path = tmp;
4612 }
4613 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4614 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
4615 ntohs (hdr->type),
4616 GNUNET_i2s (&dv->target),
4617 i + 1,
4618 num_dvhs + 1,
4619 path);
4620 GNUNET_free (path);
4621 }
4622 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
4623 memcpy (&dhops[num_hops], enc, sizeof(enc));
4624 use (use_cls,
4625 dvh->next_hop,
4626 (const struct GNUNET_MessageHeader *) buf,
4627 options);
4628 }
4629 return rtt;
4630}
4631
4632
4633/**
4634 * Wrapper around #route_via_neighbour() that matches the
4635 * #DVMessageHandler structure.
4636 *
4637 * @param cls unused
4638 * @param next_hop where to send next
4639 * @param hdr header of the message to send
4640 * @param options message options for queue selection
4641 */
4642static void
4643send_dv_to_neighbour (void *cls,
4644 struct Neighbour *next_hop,
4645 const struct GNUNET_MessageHeader *hdr,
4646 enum RouteMessageOptions options)
4647{
4648 (void) cls;
4649 (void) route_via_neighbour (next_hop, hdr, options);
4650}
4651
4652
4653/**
4654 * We need to transmit @a hdr to @a target. If necessary, this may
4655 * involve DV routing. This function routes without applying flow
4656 * control or congestion control and should only be used for control
4657 * traffic.
4658 *
4659 * @param target peer to receive @a hdr
4660 * @param hdr header of the message to route and #GNUNET_free()
4661 * @param options which transmission channels are allowed
4662 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4663 */
4664static struct GNUNET_TIME_Relative
4665route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4666 const struct GNUNET_MessageHeader *hdr,
4667 enum RouteMessageOptions options)
4668{
4669 struct VirtualLink *vl;
4670 struct Neighbour *n;
4671 struct DistanceVector *dv;
4672 struct GNUNET_TIME_Relative rtt1;
4673 struct GNUNET_TIME_Relative rtt2;
4674
4675 vl = lookup_virtual_link (target);
4676 GNUNET_assert (NULL != vl);
4677 n = vl->n;
4678 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4679 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4680 {
4681 /* if confirmed is required, and we do not have anything
4682 confirmed, drop respective options */
4683 if (NULL == n)
4684 n = lookup_neighbour (target);
4685 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4686 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4687 }
4688 if ((NULL == n) && (NULL == dv))
4689 {
4690 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4691 "Cannot route message of type %u to %s: no route\n",
4692 ntohs (hdr->type),
4693 GNUNET_i2s (target));
4694 GNUNET_STATISTICS_update (GST_stats,
4695 "# Messages dropped in routing: no acceptable method",
4696 1,
4697 GNUNET_NO);
4698 return GNUNET_TIME_UNIT_FOREVER_REL;
4699 }
4700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4701 "Routing message of type %u to %s with options %X\n",
4702 ntohs (hdr->type),
4703 GNUNET_i2s (target),
4704 (unsigned int) options);
4705 /* If both dv and n are possible and we must choose:
4706 flip a coin for the choice between the two; for now 50/50 */
4707 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4708 {
4709 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4710 n = NULL;
4711 else
4712 dv = NULL;
4713 }
4714 if ((NULL != n) && (NULL != dv))
4715 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4716 enough for redundancy, so clear the flag. */
4717 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
4718 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
4719 if (NULL != n)
4720 {
4721 rtt1 = route_via_neighbour (n, hdr, options);
4722 }
4723 if (NULL != dv)
4724 {
4725 struct DistanceVectorHop *hops[2];
4726 unsigned int res;
4727
4728 res = pick_random_dv_hops (dv,
4729 options,
4730 hops,
4731 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4732 if (0 == res)
4733 {
4734 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4735 "Failed to route message, could not determine DV path\n");
4736 return rtt1;
4737 }
4738 rtt2 = encapsulate_for_dv (dv,
4739 res,
4740 hops,
4741 hdr,
4742 &send_dv_to_neighbour,
4743 NULL,
4744 options & (~RMO_REDUNDANT));
4745 }
4746 return GNUNET_TIME_relative_min (rtt1, rtt2);
4747}
4748
4749
4750static void
4751consider_sending_fc (void *cls);
4752
4753/**
4754 * Something changed on the virtual link with respect to flow
4755 * control. Consider retransmitting the FC window size.
4756 *
4757 * @param cls a `struct VirtualLink` to work with
4758 */
4759static void
4760task_consider_sending_fc (void *cls)
4761{
4762 struct VirtualLink *vl = cls;
4763 vl->fc_retransmit_task = NULL;
4764 consider_sending_fc (cls);
4765}
4766
4767
4768/**
4769 * Something changed on the virtual link with respect to flow
4770 * control. Consider retransmitting the FC window size.
4771 *
4772 * @param cls a `struct VirtualLink` to work with
4773 */
4774static void
4775consider_sending_fc (void *cls)
4776{
4777 struct VirtualLink *vl = cls;
4778 struct GNUNET_TIME_Absolute monotime;
4779 struct TransportFlowControlMessage fc;
4780 struct GNUNET_TIME_Relative duration;
4781 struct GNUNET_TIME_Relative rtt;
4782
4783 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
4784 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
4785 it always! */
4786 /* For example, we should probably ONLY do this if a bit more than
4787 an RTT has passed, or if the window changed "significantly" since
4788 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
4789 need an estimate for the bandwidth-delay-product for the entire
4790 VL, as that determines "significantly". We have the delay, but
4791 the bandwidth statistics need to be added for the VL!*/(void) duration;
4792
4793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4794 "Sending FC seq %u to %s with new window %llu\n",
4795 (unsigned int) vl->fc_seq_gen,
4796 GNUNET_i2s (&vl->target),
4797 (unsigned long long) vl->incoming_fc_window_size);
4798 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4799 vl->last_fc_transmission = monotime;
4800 fc.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
4801 fc.header.size = htons (sizeof(fc));
4802 fc.seq = htonl (vl->fc_seq_gen++);
4803 fc.inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size);
4804 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
4805 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
4806 fc.sender_time = GNUNET_TIME_absolute_hton (monotime);
4807 rtt = route_control_message_without_fc (&vl->target, &fc.header, RMO_NONE);
4808 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
4809 {
4810 rtt = GNUNET_TIME_UNIT_SECONDS;
4811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4812 "FC retransmission to %s failed, will retry in %s\n",
4813 GNUNET_i2s (&vl->target),
4814 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
4815 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
4816 }
4817 else
4818 {
4819 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
4820 vl->last_fc_rtt = rtt;
4821 }
4822 if (NULL != vl->fc_retransmit_task)
4823 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
4824 vl->fc_retransmit_task =
4825 GNUNET_SCHEDULER_add_delayed (rtt, &task_consider_sending_fc, vl);
4826}
4827
4828
4829/**
4830 * There is a message at the head of the pending messages for @a vl
4831 * which may be ready for transmission. Check if a queue is ready to
4832 * take it.
4833 *
4834 * This function must (1) check for flow control to ensure that we can
4835 * right now send to @a vl, (2) check that the pending message in the
4836 * queue is actually eligible, (3) determine if any applicable queue
4837 * (direct neighbour or DVH path) is ready to accept messages, and
4838 * (4) prioritize based on the preferences associated with the
4839 * pending message.
4840 *
4841 * So yeah, easy.
4842 *
4843 * @param vl virtual link where we should check for transmission
4844 */
4845static void
4846check_vl_transmission (struct VirtualLink *vl)
4847{
4848 struct Neighbour *n = vl->n;
4849 struct DistanceVector *dv = vl->dv;
4850 struct GNUNET_TIME_Absolute now;
4851 int elig;
4852
4853 /* Check that we have an eligible pending message!
4854 (cheaper than having #transmit_on_queue() find out!) */
4855 elig = GNUNET_NO;
4856 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
4857 pm = pm->next_vl)
4858 {
4859 if (NULL != pm->qe)
4860 continue; /* not eligible, is in a queue! */
4861 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
4862 vl->outbound_fc_window_size)
4863 {
4864 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4865 "Stalled transmission on VL %s due to flow control: %llu < %llu\n",
4866 GNUNET_i2s (&vl->target),
4867 (unsigned long long) vl->outbound_fc_window_size,
4868 (unsigned long long) (pm->bytes_msg
4869 + vl->outbound_fc_window_size_used));
4870 consider_sending_fc (vl);
4871 return; /* We have a message, but flow control says "nope" */
4872 }
4873 elig = GNUNET_YES;
4874 break;
4875 }
4876 if (GNUNET_NO == elig)
4877 return;
4878 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4879 "Not stalled. Scheduling transmission on queue\n");
4880 /* Notify queues at direct neighbours that we are interested */
4881 now = GNUNET_TIME_absolute_get ();
4882 if (NULL != n)
4883 {
4884 for (struct Queue *queue = n->queue_head; NULL != queue;
4885 queue = queue->next_neighbour)
4886 {
4887 if ((GNUNET_YES == queue->idle) &&
4888 (queue->validated_until.abs_value_us > now.abs_value_us))
4889 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
4890 else
4891 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4892 "Queue busy or invalid\n");
4893 }
4894 }
4895 /* Notify queues via DV that we are interested */
4896 if (NULL != dv)
4897 {
4898 /* Do DV with lower scheduler priority, which effectively means that
4899 IF a neighbour exists and is available, we prefer it. */
4900 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4901 pos = pos->next_dv)
4902 {
4903 struct Neighbour *nh = pos->next_hop;
4904
4905 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
4906 continue; /* skip this one: path not validated */
4907 for (struct Queue *queue = nh->queue_head; NULL != queue;
4908 queue = queue->next_neighbour)
4909 if ((GNUNET_YES == queue->idle) &&
4910 (queue->validated_until.abs_value_us > now.abs_value_us))
4911 schedule_transmit_on_queue (queue,
4912 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
4913 }
4914 }
4915}
4916
4917
4918/**
4919 * Client asked for transmission to a peer. Process the request.
4920 *
4921 * @param cls the client
4922 * @param obm the send message that was sent
4923 */
4924static void
4925handle_client_send (void *cls, const struct OutboundMessage *obm)
4926{
4927 struct TransportClient *tc = cls;
4928 struct PendingMessage *pm;
4929 const struct GNUNET_MessageHeader *obmm;
4930 uint32_t bytes_msg;
4931 struct VirtualLink *vl;
4932 enum GNUNET_MQ_PriorityPreferences pp;
4933
4934 GNUNET_assert (CT_CORE == tc->type);
4935 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4936 bytes_msg = ntohs (obmm->size);
4937 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
4938 vl = lookup_virtual_link (&obm->peer);
4939 if (NULL == vl)
4940 {
4941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4942 "Don't have %s as a neighbour (anymore).\n",
4943 GNUNET_i2s (&obm->peer));
4944 /* Failure: don't have this peer as a neighbour (anymore).
4945 Might have gone down asynchronously, so this is NOT
4946 a protocol violation by CORE. Still count the event,
4947 as this should be rare. */
4948 GNUNET_SERVICE_client_continue (tc->client);
4949 GNUNET_STATISTICS_update (GST_stats,
4950 "# messages dropped (neighbour unknown)",
4951 1,
4952 GNUNET_NO);
4953 return;
4954 }
4955
4956 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
4957 pm->logging_uuid = logging_uuid_gen++;
4958 pm->prefs = pp;
4959 pm->client = tc;
4960 pm->vl = vl;
4961 pm->bytes_msg = bytes_msg;
4962 memcpy (&pm[1], obmm, bytes_msg);
4963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4964 "Sending %u bytes as <%llu> to %s\n",
4965 bytes_msg,
4966 pm->logging_uuid,
4967 GNUNET_i2s (&obm->peer));
4968 GNUNET_CONTAINER_MDLL_insert (client,
4969 tc->details.core.pending_msg_head,
4970 tc->details.core.pending_msg_tail,
4971 pm);
4972 GNUNET_CONTAINER_MDLL_insert (vl,
4973 vl->pending_msg_head,
4974 vl->pending_msg_tail,
4975 pm);
4976 check_vl_transmission (vl);
4977}
4978
4979
4980/**
4981 * Communicator requests backchannel transmission. Process the request.
4982 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
4983 * (which for now has exactly the same format, only a different message type)
4984 * and passes it on for routing.
4985 *
4986 * @param cls the client
4987 * @param cb the send message that was sent
4988 */
4989static void
4990handle_communicator_backchannel (
4991 void *cls,
4992 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4993{
4994 struct TransportClient *tc = cls;
4995 const struct GNUNET_MessageHeader *inbox =
4996 (const struct GNUNET_MessageHeader *) &cb[1];
4997 uint16_t isize = ntohs (inbox->size);
4998 const char *is = ((const char *) &cb[1]) + isize;
4999 char
5000 mbuf[isize
5001 + sizeof(struct
5002 TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
5003 struct TransportBackchannelEncapsulationMessage *be =
5004 (struct TransportBackchannelEncapsulationMessage *) mbuf;
5005
5006 /* 0-termination of 'is' was checked already in
5007 #check_communicator_backchannel() */
5008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5009 "Preparing backchannel transmission to %s:%s of type %u\n",
5010 GNUNET_i2s (&cb->pid),
5011 is,
5012 ntohs (inbox->size));
5013 /* encapsulate and encrypt message */
5014 be->header.type =
5015 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
5016 be->header.size = htons (sizeof(mbuf));
5017 memcpy (&be[1], inbox, isize);
5018 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
5019 + isize],
5020 is,
5021 strlen (is) + 1);
5022 route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
5023 GNUNET_SERVICE_client_continue (tc->client);
5024}
5025
5026
5027/**
5028 * Address of our peer added. Test message is well-formed.
5029 *
5030 * @param cls the client
5031 * @param aam the send message that was sent
5032 * @return #GNUNET_OK if message is well-formed
5033 */
5034static int
5035check_add_address (void *cls,
5036 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5037{
5038 struct TransportClient *tc = cls;
5039
5040 if (CT_COMMUNICATOR != tc->type)
5041 {
5042 GNUNET_break (0);
5043 return GNUNET_SYSERR;
5044 }
5045 GNUNET_MQ_check_zero_termination (aam);
5046 return GNUNET_OK;
5047}
5048
5049
5050/**
5051 * Ask peerstore to store our address.
5052 *
5053 * @param cls an `struct AddressListEntry *`
5054 */
5055static void
5056store_pi (void *cls);
5057
5058
5059/**
5060 * Function called when peerstore is done storing our address.
5061 *
5062 * @param cls a `struct AddressListEntry`
5063 * @param success #GNUNET_YES if peerstore was successful
5064 */
5065static void
5066peerstore_store_own_cb (void *cls, int success)
5067{
5068 struct AddressListEntry *ale = cls;
5069
5070 ale->sc = NULL;
5071 if (GNUNET_YES != success)
5072 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5073 "Failed to store our own address `%s' in peerstore!\n",
5074 ale->address);
5075 else
5076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5077 "Successfully stored our own address `%s' in peerstore!\n",
5078 ale->address);
5079 /* refresh period is 1/4 of expiration time, that should be plenty
5080 without being excessive. */
5081 ale->st =
5082 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5083 4ULL),
5084 &store_pi,
5085 ale);
5086}
5087
5088
5089/**
5090 * Ask peerstore to store our address.
5091 *
5092 * @param cls an `struct AddressListEntry *`
5093 */
5094static void
5095store_pi (void *cls)
5096{
5097 struct AddressListEntry *ale = cls;
5098 void *addr;
5099 size_t addr_len;
5100 struct GNUNET_TIME_Absolute expiration;
5101
5102 ale->st = NULL;
5103 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5105 "Storing our address `%s' in peerstore until %s!\n",
5106 ale->address,
5107 GNUNET_STRINGS_absolute_time_to_string (expiration));
5108 GNUNET_HELLO_sign_address (ale->address,
5109 ale->nt,
5110 hello_mono_time,
5111 GST_my_private_key,
5112 &addr,
5113 &addr_len);
5114 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5115 "transport",
5116 &GST_my_identity,
5117 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5118 addr,
5119 addr_len,
5120 expiration,
5121 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5122 &peerstore_store_own_cb,
5123 ale);
5124 GNUNET_free (addr);
5125 if (NULL == ale->sc)
5126 {
5127 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5128 "Failed to store our address `%s' with peerstore\n",
5129 ale->address);
5130 ale->st =
5131 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
5132 }
5133}
5134
5135
5136/**
5137 * Address of our peer added. Process the request.
5138 *
5139 * @param cls the client
5140 * @param aam the send message that was sent
5141 */
5142static void
5143handle_add_address (void *cls,
5144 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5145{
5146 struct TransportClient *tc = cls;
5147 struct AddressListEntry *ale;
5148 size_t slen;
5149
5150 /* 0-termination of &aam[1] was checked in #check_add_address */
5151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5152 "Communicator added address `%s'!\n",
5153 (const char *) &aam[1]);
5154 slen = ntohs (aam->header.size) - sizeof(*aam);
5155 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
5156 ale->tc = tc;
5157 ale->address = (const char *) &ale[1];
5158 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5159 ale->aid = aam->aid;
5160 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5161 memcpy (&ale[1], &aam[1], slen);
5162 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5163 tc->details.communicator.addr_tail,
5164 ale);
5165 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5166 GNUNET_SERVICE_client_continue (tc->client);
5167}
5168
5169
5170/**
5171 * Address of our peer deleted. Process the request.
5172 *
5173 * @param cls the client
5174 * @param dam the send message that was sent
5175 */
5176static void
5177handle_del_address (void *cls,
5178 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5179{
5180 struct TransportClient *tc = cls;
5181 struct AddressListEntry *alen;
5182
5183 if (CT_COMMUNICATOR != tc->type)
5184 {
5185 GNUNET_break (0);
5186 GNUNET_SERVICE_client_drop (tc->client);
5187 return;
5188 }
5189 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5190 NULL != ale;
5191 ale = alen)
5192 {
5193 alen = ale->next;
5194 if (dam->aid != ale->aid)
5195 continue;
5196 GNUNET_assert (ale->tc == tc);
5197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5198 "Communicator deleted address `%s'!\n",
5199 ale->address);
5200 free_address_list_entry (ale);
5201 GNUNET_SERVICE_client_continue (tc->client);
5202 return;
5203 }
5204 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5205 "Communicator removed address we did not even have.\n");
5206 GNUNET_SERVICE_client_continue (tc->client);
5207 // GNUNET_SERVICE_client_drop (tc->client);
5208}
5209
5210
5211/**
5212 * Given an inbound message @a msg from a communicator @a cmc,
5213 * demultiplex it based on the type calling the right handler.
5214 *
5215 * @param cmc context for demultiplexing
5216 * @param msg message to demultiplex
5217 */
5218static void
5219demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5220 const struct GNUNET_MessageHeader *msg);
5221
5222
5223/**
5224 * Function called when we are done giving a message of a certain
5225 * size to CORE and should thus decrement the number of bytes of
5226 * RAM reserved for that peer's MQ.
5227 *
5228 * @param cls a `struct CoreSentContext`
5229 */
5230static void
5231core_env_sent_cb (void *cls)
5232{
5233 struct CoreSentContext *ctx = cls;
5234 struct VirtualLink *vl = ctx->vl;
5235
5236 if (NULL == vl)
5237 {
5238 /* lost the link in the meantime, ignore */
5239 GNUNET_free (ctx);
5240 return;
5241 }
5242 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5243 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5244 vl->incoming_fc_window_size_ram -= ctx->size;
5245 vl->incoming_fc_window_size_used += ctx->isize;
5246 consider_sending_fc (vl);
5247 GNUNET_free (ctx);
5248}
5249
5250
5251/**
5252 * Communicator gave us an unencapsulated message to pass as-is to
5253 * CORE. Process the request.
5254 *
5255 * @param cls a `struct CommunicatorMessageContext` (must call
5256 * #finish_cmc_handling() when done)
5257 * @param mh the message that was received
5258 */
5259static void
5260handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5261{
5262 struct CommunicatorMessageContext *cmc = cls;
5263 struct VirtualLink *vl;
5264 uint16_t size = ntohs (mh->size);
5265 int have_core;
5266
5267 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
5268 (size < sizeof(struct GNUNET_MessageHeader)))
5269 {
5270 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5271
5272 GNUNET_break (0);
5273 finish_cmc_handling (cmc);
5274 GNUNET_SERVICE_client_drop (client);
5275 return;
5276 }
5277 vl = lookup_virtual_link (&cmc->im.sender);
5278 if (NULL == vl)
5279 {
5280 /* FIXME: sender is giving us messages for CORE but we don't have
5281 the link up yet! I *suspect* this can happen right now (i.e.
5282 sender has verified us, but we didn't verify sender), but if
5283 we pass this on, CORE would be confused (link down, messages
5284 arrive). We should investigate more if this happens often,
5285 or in a persistent manner, and possibly do "something" about
5286 it. Thus logging as error for now. */
5287 GNUNET_break_op (0);
5288 GNUNET_STATISTICS_update (GST_stats,
5289 "# CORE messages dropped (virtual link still down)",
5290 1,
5291 GNUNET_NO);
5292
5293 finish_cmc_handling (cmc);
5294 return;
5295 }
5296 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5297 {
5298 GNUNET_STATISTICS_update (GST_stats,
5299 "# CORE messages dropped (FC arithmetic overflow)",
5300 1,
5301 GNUNET_NO);
5302
5303 finish_cmc_handling (cmc);
5304 return;
5305 }
5306 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5307 {
5308 GNUNET_STATISTICS_update (GST_stats,
5309 "# CORE messages dropped (FC window overflow)",
5310 1,
5311 GNUNET_NO);
5312 finish_cmc_handling (cmc);
5313 return;
5314 }
5315
5316 /* Forward to all CORE clients */
5317 have_core = GNUNET_NO;
5318 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5319 {
5320 struct GNUNET_MQ_Envelope *env;
5321 struct InboundMessage *im;
5322 struct CoreSentContext *ctx;
5323
5324 if (CT_CORE != tc->type)
5325 continue;
5326 vl->incoming_fc_window_size_ram += size;
5327 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5328 ctx = GNUNET_new (struct CoreSentContext);
5329 ctx->vl = vl;
5330 ctx->size = size;
5331 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5332 have_core = GNUNET_YES;
5333 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5334 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5335 im->peer = cmc->im.sender;
5336 memcpy (&im[1], mh, size);
5337 GNUNET_MQ_send (tc->mq, env);
5338 vl->core_recv_window--;
5339 }
5340 if (GNUNET_NO == have_core)
5341 {
5342 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5343 "Dropped message to CORE: no CORE client connected!\n");
5344 /* Nevertheless, count window as used, as it is from the
5345 perspective of the other peer! */
5346 vl->incoming_fc_window_size_used += size;
5347 /* TODO-M1 */
5348 finish_cmc_handling (cmc);
5349 return;
5350 }
5351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5352 "Delivered message from %s of type %u to CORE\n",
5353 GNUNET_i2s (&cmc->im.sender),
5354 ntohs (mh->type));
5355 if (vl->core_recv_window > 0)
5356 {
5357 finish_cmc_handling (cmc);
5358 return;
5359 }
5360 /* Wait with calling #finish_cmc_handling(cmc) until the message
5361 was processed by CORE MQs (for CORE flow control)! */
5362 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5363}
5364
5365
5366/**
5367 * Communicator gave us a fragment box. Check the message.
5368 *
5369 * @param cls a `struct CommunicatorMessageContext`
5370 * @param fb the send message that was sent
5371 * @return #GNUNET_YES if message is well-formed
5372 */
5373static int
5374check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5375{
5376 uint16_t size = ntohs (fb->header.size);
5377 uint16_t bsize = size - sizeof(*fb);
5378
5379 (void) cls;
5380 if (0 == bsize)
5381 {
5382 GNUNET_break_op (0);
5383 return GNUNET_SYSERR;
5384 }
5385 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5386 {
5387 GNUNET_break_op (0);
5388 return GNUNET_SYSERR;
5389 }
5390 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5391 {
5392 GNUNET_break_op (0);
5393 return GNUNET_SYSERR;
5394 }
5395 return GNUNET_YES;
5396}
5397
5398
5399/**
5400 * Clean up an idle cumulative acknowledgement data structure.
5401 *
5402 * @param cls a `struct AcknowledgementCummulator *`
5403 */
5404static void
5405destroy_ack_cummulator (void *cls)
5406{
5407 struct AcknowledgementCummulator *ac = cls;
5408
5409 ac->task = NULL;
5410 GNUNET_assert (0 == ac->num_acks);
5411 GNUNET_assert (
5412 GNUNET_YES ==
5413 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5414 GNUNET_free (ac);
5415}
5416
5417
5418/**
5419 * Do the transmission of a cumulative acknowledgement now.
5420 *
5421 * @param cls a `struct AcknowledgementCummulator *`
5422 */
5423static void
5424transmit_cummulative_ack_cb (void *cls)
5425{
5426 struct AcknowledgementCummulator *ac = cls;
5427 char buf[sizeof(struct TransportReliabilityAckMessage)
5428 + ac->ack_counter
5429 * sizeof(struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5430 struct TransportReliabilityAckMessage *ack =
5431 (struct TransportReliabilityAckMessage *) buf;
5432 struct TransportCummulativeAckPayloadP *ap;
5433
5434 ac->task = NULL;
5435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5436 "Sending ACK with %u components to %s\n",
5437 ac->ack_counter,
5438 GNUNET_i2s (&ac->target));
5439 GNUNET_assert (0 < ac->ack_counter);
5440 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5441 ack->header.size =
5442 htons (sizeof(*ack)
5443 + ac->ack_counter * sizeof(struct TransportCummulativeAckPayloadP));
5444 ack->ack_counter = htonl (ac->ack_counter++);
5445 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5446 for (unsigned int i = 0; i < ac->ack_counter; i++)
5447 {
5448 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5449 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5450 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5451 }
5452 route_control_message_without_fc (&ac->target, &ack->header, RMO_DV_ALLOWED);
5453 ac->num_acks = 0;
5454 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5455 &destroy_ack_cummulator,
5456 ac);
5457}
5458
5459
5460/**
5461 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5462 * transmission by at most @a ack_delay.
5463 *
5464 * @param pid target peer
5465 * @param ack_uuid UUID to ack
5466 * @param max_delay how long can the ACK wait
5467 */
5468static void
5469cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5470 const struct AcknowledgementUUIDP *ack_uuid,
5471 struct GNUNET_TIME_Absolute max_delay)
5472{
5473 struct AcknowledgementCummulator *ac;
5474
5475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5476 "Scheduling ACK %s for transmission to %s\n",
5477 GNUNET_uuid2s (&ack_uuid->value),
5478 GNUNET_i2s (pid));
5479 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5480 if (NULL == ac)
5481 {
5482 ac = GNUNET_new (struct AcknowledgementCummulator);
5483 ac->target = *pid;
5484 ac->min_transmission_time = max_delay;
5485 GNUNET_assert (GNUNET_YES ==
5486 GNUNET_CONTAINER_multipeermap_put (
5487 ack_cummulators,
5488 &ac->target,
5489 ac,
5490 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5491 }
5492 else
5493 {
5494 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5495 {
5496 /* must run immediately, ack buffer full! */
5497 GNUNET_SCHEDULER_cancel (ac->task);
5498 transmit_cummulative_ack_cb (ac);
5499 }
5500 GNUNET_SCHEDULER_cancel (ac->task);
5501 ac->min_transmission_time =
5502 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5503 }
5504 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5505 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5506 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5507 ac->num_acks++;
5508 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5509 &transmit_cummulative_ack_cb,
5510 ac);
5511}
5512
5513
5514/**
5515 * Closure for #find_by_message_uuid.
5516 */
5517struct FindByMessageUuidContext
5518{
5519 /**
5520 * UUID to look for.
5521 */
5522 struct MessageUUIDP message_uuid;
5523
5524 /**
5525 * Set to the reassembly context if found.
5526 */
5527 struct ReassemblyContext *rc;
5528};
5529
5530
5531/**
5532 * Iterator called to find a reassembly context by the message UUID in the
5533 * multihashmap32.
5534 *
5535 * @param cls a `struct FindByMessageUuidContext`
5536 * @param key a key (unused)
5537 * @param value a `struct ReassemblyContext`
5538 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5539 */
5540static int
5541find_by_message_uuid (void *cls, uint32_t key, void *value)
5542{
5543 struct FindByMessageUuidContext *fc = cls;
5544 struct ReassemblyContext *rc = value;
5545
5546 (void) key;
5547 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5548 {
5549 fc->rc = rc;
5550 return GNUNET_NO;
5551 }
5552 return GNUNET_YES;
5553}
5554
5555
5556/**
5557 * Communicator gave us a fragment. Process the request.
5558 *
5559 * @param cls a `struct CommunicatorMessageContext` (must call
5560 * #finish_cmc_handling() when done)
5561 * @param fb the message that was received
5562 */
5563static void
5564handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5565{
5566 struct CommunicatorMessageContext *cmc = cls;
5567 struct Neighbour *n;
5568 struct ReassemblyContext *rc;
5569 const struct GNUNET_MessageHeader *msg;
5570 uint16_t msize;
5571 uint16_t fsize;
5572 uint16_t frag_off;
5573 char *target;
5574 struct GNUNET_TIME_Relative cdelay;
5575 struct FindByMessageUuidContext fc;
5576
5577 n = lookup_neighbour (&cmc->im.sender);
5578 if (NULL == n)
5579 {
5580 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5581
5582 GNUNET_break (0);
5583 finish_cmc_handling (cmc);
5584 GNUNET_SERVICE_client_drop (client);
5585 return;
5586 }
5587 if (NULL == n->reassembly_map)
5588 {
5589 n->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5590 n->reassembly_heap =
5591 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5592 n->reassembly_timeout_task =
5593 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5594 &reassembly_cleanup_task,
5595 n);
5596 }
5597 msize = ntohs (fb->msg_size);
5598 fc.message_uuid = fb->msg_uuid;
5599 fc.rc = NULL;
5600 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (n->reassembly_map,
5601 fb->msg_uuid.uuid,
5602 &find_by_message_uuid,
5603 &fc);
5604 if (NULL == (rc = fc.rc))
5605 {
5606 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
5607 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
5608 rc->msg_uuid = fb->msg_uuid;
5609 rc->neighbour = n;
5610 rc->msg_size = msize;
5611 rc->reassembly_timeout =
5612 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5613 rc->last_frag = GNUNET_TIME_absolute_get ();
5614 rc->hn = GNUNET_CONTAINER_heap_insert (n->reassembly_heap,
5615 rc,
5616 rc->reassembly_timeout.abs_value_us);
5617 GNUNET_assert (GNUNET_OK ==
5618 GNUNET_CONTAINER_multihashmap32_put (
5619 n->reassembly_map,
5620 rc->msg_uuid.uuid,
5621 rc,
5622 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5623 target = (char *) &rc[1];
5624 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5625 rc->msg_missing = rc->msg_size;
5626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5627 "Received fragment at offset %u/%u from %s for NEW message %u\n",
5628 ntohs (fb->frag_off),
5629 msize,
5630 GNUNET_i2s (&cmc->im.sender),
5631 (unsigned int) fb->msg_uuid.uuid);
5632 }
5633 else
5634 {
5635 target = (char *) &rc[1];
5636 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5637 "Received fragment at offset %u/%u from %s for message %u\n",
5638 ntohs (fb->frag_off),
5639 msize,
5640 GNUNET_i2s (&cmc->im.sender),
5641 (unsigned int) fb->msg_uuid.uuid);
5642 }
5643 if (msize != rc->msg_size)
5644 {
5645 GNUNET_break (0);
5646 finish_cmc_handling (cmc);
5647 return;
5648 }
5649
5650 /* reassemble */
5651 fsize = ntohs (fb->header.size) - sizeof(*fb);
5652 if (0 == fsize)
5653 {
5654 GNUNET_break (0);
5655 finish_cmc_handling (cmc);
5656 return;
5657 }
5658 frag_off = ntohs (fb->frag_off);
5659 if (frag_off + fsize > msize)
5660 {
5661 /* Fragment (plus fragment size) exceeds message size! */
5662 GNUNET_break_op (0);
5663 finish_cmc_handling (cmc);
5664 return;
5665 }
5666 memcpy (&target[frag_off], &fb[1], fsize);
5667 /* update bitfield and msg_missing */
5668 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
5669 {
5670 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
5671 {
5672 rc->bitfield[i / 8] |= (1 << (i % 8));
5673 rc->msg_missing--;
5674 }
5675 }
5676
5677 /* Compute cumulative ACK */
5678 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
5679 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
5680 if (0 == rc->msg_missing)
5681 cdelay = GNUNET_TIME_UNIT_ZERO;
5682 cummulative_ack (&cmc->im.sender,
5683 &fb->ack_uuid,
5684 GNUNET_TIME_relative_to_absolute (cdelay));
5685 rc->last_frag = GNUNET_TIME_absolute_get ();
5686 /* is reassembly complete? */
5687 if (0 != rc->msg_missing)
5688 {
5689 finish_cmc_handling (cmc);
5690 return;
5691 }
5692 /* reassembly is complete, verify result */
5693 msg = (const struct GNUNET_MessageHeader *) &rc[1];
5694 if (ntohs (msg->size) != rc->msg_size)
5695 {
5696 GNUNET_break (0);
5697 free_reassembly_context (rc);
5698 finish_cmc_handling (cmc);
5699 return;
5700 }
5701 /* successful reassembly */
5702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5703 "Fragment reassembly complete for message %u\n",
5704 (unsigned int) fb->msg_uuid.uuid);
5705 /* FIXME: check that the resulting msg is NOT a
5706 DV Box or Reliability Box, as that is NOT allowed! */
5707 demultiplex_with_cmc (cmc, msg);
5708 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
5709 en-route and we forget that we finished this reassembly immediately!
5710 -> keep around until timeout?
5711 -> shorten timeout based on ACK? */
5712 free_reassembly_context (rc);
5713}
5714
5715
5716/**
5717 * Communicator gave us a reliability box. Check the message.
5718 *
5719 * @param cls a `struct CommunicatorMessageContext`
5720 * @param rb the send message that was sent
5721 * @return #GNUNET_YES if message is well-formed
5722 */
5723static int
5724check_reliability_box (void *cls,
5725 const struct TransportReliabilityBoxMessage *rb)
5726{
5727 (void) cls;
5728 GNUNET_MQ_check_boxed_message (rb);
5729 return GNUNET_YES;
5730}
5731
5732
5733/**
5734 * Communicator gave us a reliability box. Process the request.
5735 *
5736 * @param cls a `struct CommunicatorMessageContext` (must call
5737 * #finish_cmc_handling() when done)
5738 * @param rb the message that was received
5739 */
5740static void
5741handle_reliability_box (void *cls,
5742 const struct TransportReliabilityBoxMessage *rb)
5743{
5744 struct CommunicatorMessageContext *cmc = cls;
5745 const struct GNUNET_MessageHeader *inbox =
5746 (const struct GNUNET_MessageHeader *) &rb[1];
5747 struct GNUNET_TIME_Relative rtt;
5748
5749 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5750 "Received reliability box from %s with UUID %s of type %u\n",
5751 GNUNET_i2s (&cmc->im.sender),
5752 GNUNET_uuid2s (&rb->ack_uuid.value),
5753 (unsigned int) ntohs (inbox->type));
5754 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
5755 do not really have an RTT for the
5756 * incoming* queue (should we have
5757 the sender add it to the rb message?) */
5758 cummulative_ack (
5759 &cmc->im.sender,
5760 &rb->ack_uuid,
5761 (0 == ntohl (rb->ack_countdown))
5762 ? GNUNET_TIME_UNIT_ZERO_ABS
5763 : GNUNET_TIME_relative_to_absolute (
5764 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
5765 /* continue with inner message */
5766 /* FIXME: check that inbox is NOT a DV Box, fragment or another
5767 reliability box (not allowed!) */
5768 demultiplex_with_cmc (cmc, inbox);
5769}
5770
5771
5772/**
5773 * Check if we have advanced to another age since the last time. If
5774 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
5775 * the current age)
5776 *
5777 * @param pd[in,out] data to update
5778 * @param age current age
5779 */
5780static void
5781update_pd_age (struct PerformanceData *pd, unsigned int age)
5782{
5783 unsigned int sage;
5784
5785 if (age == pd->last_age)
5786 return; /* nothing to do */
5787 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
5788 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
5789 {
5790 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
5791
5792 the->bytes_sent = 0;
5793 the->bytes_received = 0;
5794 }
5795 pd->last_age = age;
5796}
5797
5798
5799/**
5800 * Update @a pd based on the latest @a rtt and the number of bytes
5801 * that were confirmed to be successfully transmitted.
5802 *
5803 * @param pd[in,out] data to update
5804 * @param rtt latest round-trip time
5805 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
5806 */
5807static void
5808update_performance_data (struct PerformanceData *pd,
5809 struct GNUNET_TIME_Relative rtt,
5810 uint16_t bytes_transmitted_ok)
5811{
5812 uint64_t nval = rtt.rel_value_us;
5813 uint64_t oval = pd->aged_rtt.rel_value_us;
5814 unsigned int age = get_age ();
5815 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
5816
5817 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
5818 pd->aged_rtt = rtt;
5819 else
5820 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
5821 update_pd_age (pd, age);
5822 the->bytes_received += bytes_transmitted_ok;
5823}
5824
5825
5826/**
5827 * We have successfully transmitted data via @a q, update metrics.
5828 *
5829 * @param q queue to update
5830 * @param rtt round trip time observed
5831 * @param bytes_transmitted_ok number of bytes successfully transmitted
5832 */
5833static void
5834update_queue_performance (struct Queue *q,
5835 struct GNUNET_TIME_Relative rtt,
5836 uint16_t bytes_transmitted_ok)
5837{
5838 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
5839}
5840
5841
5842/**
5843 * We have successfully transmitted data via @a dvh, update metrics.
5844 *
5845 * @param dvh distance vector path data to update
5846 * @param rtt round trip time observed
5847 * @param bytes_transmitted_ok number of bytes successfully transmitted
5848 */
5849static void
5850update_dvh_performance (struct DistanceVectorHop *dvh,
5851 struct GNUNET_TIME_Relative rtt,
5852 uint16_t bytes_transmitted_ok)
5853{
5854 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
5855}
5856
5857
5858/**
5859 * We have completed transmission of @a pm, remove it from
5860 * the transmission queues (and if it is a fragment, continue
5861 * up the tree as necessary).
5862 *
5863 * @param pm pending message that was transmitted
5864 */
5865static void
5866completed_pending_message (struct PendingMessage *pm)
5867{
5868 struct PendingMessage *pos;
5869
5870 switch (pm->pmt)
5871 {
5872 case PMT_CORE:
5873 case PMT_RELIABILITY_BOX:
5874 /* Full message sent, we are done */
5875 client_send_response (pm);
5876 return;
5877
5878 case PMT_FRAGMENT_BOX:
5879 /* Fragment sent over reliabile channel */
5880 free_fragment_tree (pm);
5881 pos = pm->frag_parent;
5882 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5883 GNUNET_free (pm);
5884 /* check if subtree is done */
5885 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
5886 (pos != pm))
5887 {
5888 pm = pos;
5889 pos = pm->frag_parent;
5890 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
5891 GNUNET_free (pm);
5892 }
5893
5894 /* Was this the last applicable fragmment? */
5895 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
5896 (pos->frag_off == pos->bytes_msg))
5897 client_send_response (pos);
5898 return;
5899
5900 case PMT_DV_BOX:
5901 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5902 "Completed transmission of message %llu (DV Box)\n",
5903 pm->logging_uuid);
5904 free_pending_message (pm);
5905 return;
5906 }
5907}
5908
5909
5910/**
5911 * The @a pa was acknowledged, process the acknowledgement.
5912 *
5913 * @param pa the pending acknowledgement that was satisfied
5914 * @param ack_delay artificial delay from cumulative acks created by the
5915 * other peer
5916 */
5917static void
5918handle_acknowledged (struct PendingAcknowledgement *pa,
5919 struct GNUNET_TIME_Relative ack_delay)
5920{
5921 struct GNUNET_TIME_Relative delay;
5922
5923 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
5924 if (delay.rel_value_us > ack_delay.rel_value_us)
5925 delay = GNUNET_TIME_UNIT_ZERO;
5926 else
5927 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
5928 if (NULL != pa->queue)
5929 update_queue_performance (pa->queue, delay, pa->message_size);
5930 if (NULL != pa->dvh)
5931 update_dvh_performance (pa->dvh, delay, pa->message_size);
5932 if (NULL != pa->pm)
5933 completed_pending_message (pa->pm);
5934 free_pending_acknowledgement (pa);
5935}
5936
5937
5938/**
5939 * Communicator gave us a reliability ack. Check it is well-formed.
5940 *
5941 * @param cls a `struct CommunicatorMessageContext` (unused)
5942 * @param ra the message that was received
5943 * @return #GNUNET_Ok if @a ra is well-formed
5944 */
5945static int
5946check_reliability_ack (void *cls,
5947 const struct TransportReliabilityAckMessage *ra)
5948{
5949 unsigned int n_acks;
5950
5951 (void) cls;
5952 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
5953 / sizeof(struct TransportCummulativeAckPayloadP);
5954 if (0 == n_acks)
5955 {
5956 GNUNET_break_op (0);
5957 return GNUNET_SYSERR;
5958 }
5959 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
5960 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
5961 {
5962 GNUNET_break_op (0);
5963 return GNUNET_SYSERR;
5964 }
5965 return GNUNET_OK;
5966}
5967
5968
5969/**
5970 * Communicator gave us a reliability ack. Process the request.
5971 *
5972 * @param cls a `struct CommunicatorMessageContext` (must call
5973 * #finish_cmc_handling() when done)
5974 * @param ra the message that was received
5975 */
5976static void
5977handle_reliability_ack (void *cls,
5978 const struct TransportReliabilityAckMessage *ra)
5979{
5980 struct CommunicatorMessageContext *cmc = cls;
5981 const struct TransportCummulativeAckPayloadP *ack;
5982 unsigned int n_acks;
5983 uint32_t ack_counter;
5984
5985 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
5986 / sizeof(struct TransportCummulativeAckPayloadP);
5987 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
5988 for (unsigned int i = 0; i < n_acks; i++)
5989 {
5990 struct PendingAcknowledgement *pa =
5991 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
5992 if (NULL == pa)
5993 {
5994 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5995 "Received ACK from %s with UUID %s which is unknown to us!\n",
5996 GNUNET_i2s (&cmc->im.sender),
5997 GNUNET_uuid2s (&ack[i].ack_uuid.value));
5998 GNUNET_STATISTICS_update (
5999 GST_stats,
6000 "# FRAGMENT_ACKS dropped, no matching pending message",
6001 1,
6002 GNUNET_NO);
6003 continue;
6004 }
6005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6006 "Received ACK from %s with UUID %s\n",
6007 GNUNET_i2s (&cmc->im.sender),
6008 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6009 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
6010 }
6011
6012 ack_counter = htonl (ra->ack_counter);
6013 (void) ack_counter; /* silence compiler warning for now */
6014 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
6015 // (DV and/or Neighbour?)
6016 finish_cmc_handling (cmc);
6017}
6018
6019
6020/**
6021 * Communicator gave us a backchannel encapsulation. Check the message.
6022 *
6023 * @param cls a `struct CommunicatorMessageContext`
6024 * @param be the send message that was sent
6025 * @return #GNUNET_YES if message is well-formed
6026 */
6027static int
6028check_backchannel_encapsulation (
6029 void *cls,
6030 const struct TransportBackchannelEncapsulationMessage *be)
6031{
6032 uint16_t size = ntohs (be->header.size) - sizeof(*be);
6033 const struct GNUNET_MessageHeader *inbox =
6034 (const struct GNUNET_MessageHeader *) &be[1];
6035 const char *is;
6036 uint16_t isize;
6037
6038 (void) cls;
6039 if (ntohs (inbox->size) >= size)
6040 {
6041 GNUNET_break_op (0);
6042 return GNUNET_SYSERR;
6043 }
6044 isize = ntohs (inbox->size);
6045 is = ((const char *) inbox) + isize;
6046 size -= isize;
6047 if ('\0' != is[size - 1])
6048 {
6049 GNUNET_break_op (0);
6050 return GNUNET_SYSERR;
6051 }
6052 return GNUNET_YES;
6053}
6054
6055
6056/**
6057 * Communicator gave us a backchannel encapsulation. Process the request.
6058 * (We are the destination of the backchannel here.)
6059 *
6060 * @param cls a `struct CommunicatorMessageContext` (must call
6061 * #finish_cmc_handling() when done)
6062 * @param be the message that was received
6063 */
6064static void
6065handle_backchannel_encapsulation (
6066 void *cls,
6067 const struct TransportBackchannelEncapsulationMessage *be)
6068{
6069 struct CommunicatorMessageContext *cmc = cls;
6070 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
6071 struct GNUNET_MQ_Envelope *env;
6072 struct TransportClient *tc;
6073 const struct GNUNET_MessageHeader *inbox =
6074 (const struct GNUNET_MessageHeader *) &be[1];
6075 uint16_t isize = ntohs (inbox->size);
6076 const char *target_communicator = ((const char *) inbox) + isize;
6077
6078 /* Find client providing this communicator */
6079 for (tc = clients_head; NULL != tc; tc = tc->next)
6080 if ((CT_COMMUNICATOR == tc->type) &&
6081 (0 ==
6082 strcmp (tc->details.communicator.address_prefix, target_communicator)))
6083 break;
6084 if (NULL == tc)
6085 {
6086 char *stastr;
6087
6088 GNUNET_asprintf (
6089 &stastr,
6090 "# Backchannel message dropped: target communicator `%s' unknown",
6091 target_communicator);
6092 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
6093 GNUNET_free (stastr);
6094 return;
6095 }
6096 /* Finally, deliver backchannel message to communicator */
6097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6098 "Delivering backchannel message from %s of type %u to %s\n",
6099 GNUNET_i2s (&cmc->im.sender),
6100 ntohs (inbox->type),
6101 target_communicator);
6102 env = GNUNET_MQ_msg_extra (
6103 cbi,
6104 isize,
6105 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
6106 cbi->pid = cmc->im.sender;
6107 memcpy (&cbi[1], inbox, isize);
6108 GNUNET_MQ_send (tc->mq, env);
6109}
6110
6111
6112/**
6113 * Task called when we should check if any of the DV paths
6114 * we have learned to a target are due for garbage collection.
6115 *
6116 * Collects stale paths, and possibly frees the entire DV
6117 * entry if no paths are left. Otherwise re-schedules itself.
6118 *
6119 * @param cls a `struct DistanceVector`
6120 */
6121static void
6122path_cleanup_cb (void *cls)
6123{
6124 struct DistanceVector *dv = cls;
6125 struct DistanceVectorHop *pos;
6126
6127 dv->timeout_task = NULL;
6128 while (NULL != (pos = dv->dv_head))
6129 {
6130 GNUNET_assert (dv == pos->dv);
6131 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
6132 break;
6133 free_distance_vector_hop (pos);
6134 }
6135 if (NULL == pos)
6136 {
6137 free_dv_route (dv);
6138 return;
6139 }
6140 dv->timeout_task =
6141 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6142}
6143
6144
6145/**
6146 * The @a hop is a validated path to the respective target
6147 * peer and we should tell core about it -- and schedule
6148 * a job to revoke the state.
6149 *
6150 * @param hop a path to some peer that is the reason for activation
6151 */
6152static void
6153activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6154{
6155 struct DistanceVector *dv = hop->dv;
6156 struct VirtualLink *vl;
6157
6158 vl = lookup_virtual_link (&dv->target);
6159 if (NULL != vl)
6160 {
6161 /* Link was already up, remember dv is also now available and we are done */
6162 vl->dv = dv;
6163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6164 "Virtual link to %s could now also use DV!\n",
6165 GNUNET_i2s (&dv->target));
6166 return;
6167 }
6168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6169 "Creating new virtual link to %s using DV!\n",
6170 GNUNET_i2s (&dv->target));
6171 vl = GNUNET_new (struct VirtualLink);
6172 vl->message_uuid_ctr =
6173 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6174 vl->target = dv->target;
6175 vl->dv = dv;
6176 dv->vl = vl;
6177 vl->core_recv_window = RECV_WINDOW_SIZE;
6178 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6179 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
6180 vl->visibility_task =
6181 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6182 GNUNET_break (GNUNET_YES ==
6183 GNUNET_CONTAINER_multipeermap_put (
6184 links,
6185 &vl->target,
6186 vl,
6187 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6188 consider_sending_fc (vl);
6189 /* We lacked a confirmed connection to the target
6190 before, so tell CORE about it (finally!) */
6191 cores_send_connect_info (&dv->target);
6192}
6193
6194
6195/**
6196 * We have learned a @a path through the network to some other peer, add it to
6197 * our DV data structure (returning #GNUNET_YES on success).
6198 *
6199 * We do not add paths if we have a sufficient number of shorter
6200 * paths to this target already (returning #GNUNET_NO).
6201 *
6202 * We also do not add problematic paths, like those where we lack the first
6203 * hop in our neighbour list (i.e. due to a topology change) or where some
6204 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6205 *
6206 * @param path the path we learned, path[0] should be us,
6207 * and then path contains a valid path from us to
6208 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6209 * @param path_len number of entries on the @a path, at least three!
6210 * @param network_latency how long does the message take from us to
6211 * `path[path_len-1]`? set to "forever" if unknown
6212 * @param path_valid_until how long is this path considered validated? Maybe
6213 * be zero.
6214 * @return #GNUNET_YES on success,
6215 * #GNUNET_NO if we have better path(s) to the target
6216 * #GNUNET_SYSERR if the path is useless and/or invalid
6217 * (i.e. path[1] not a direct neighbour
6218 * or path[i+1] is a direct neighbour for i>0)
6219 */
6220static int
6221learn_dv_path (const struct GNUNET_PeerIdentity *path,
6222 unsigned int path_len,
6223 struct GNUNET_TIME_Relative network_latency,
6224 struct GNUNET_TIME_Absolute path_valid_until)
6225{
6226 struct DistanceVectorHop *hop;
6227 struct DistanceVector *dv;
6228 struct Neighbour *next_hop;
6229 unsigned int shorter_distance;
6230
6231 if (path_len < 3)
6232 {
6233 /* what a boring path! not allowed! */
6234 GNUNET_break (0);
6235 return GNUNET_SYSERR;
6236 }
6237 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6238 next_hop = lookup_neighbour (&path[1]);
6239 if (NULL == next_hop)
6240 {
6241 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6242 GNUNET_break (0);
6243 return GNUNET_SYSERR;
6244 }
6245 for (unsigned int i = 2; i < path_len; i++)
6246 if (NULL != lookup_neighbour (&path[i]))
6247 {
6248 /* Useless path: we have a direct connection to some hop
6249 in the middle of the path, so this one is not even
6250 terribly useful for redundancy */
6251 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6252 "Path of %u hops useless: directly link to hop %u (%s)\n",
6253 path_len,
6254 i,
6255 GNUNET_i2s (&path[i]));
6256 GNUNET_STATISTICS_update (GST_stats,
6257 "# Useless DV path ignored: hop is neighbour",
6258 1,
6259 GNUNET_NO);
6260 return GNUNET_SYSERR;
6261 }
6262 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6263 if (NULL == dv)
6264 {
6265 dv = GNUNET_new (struct DistanceVector);
6266 dv->target = path[path_len - 1];
6267 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6268 &path_cleanup_cb,
6269 dv);
6270 GNUNET_assert (GNUNET_OK ==
6271 GNUNET_CONTAINER_multipeermap_put (
6272 dv_routes,
6273 &dv->target,
6274 dv,
6275 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6276 }
6277 /* Check if we have this path already! */
6278 shorter_distance = 0;
6279 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6280 pos = pos->next_dv)
6281 {
6282 if (pos->distance < path_len - 2)
6283 shorter_distance++;
6284 /* Note that the distances in 'pos' excludes us (path[0]) and
6285 the next_hop (path[1]), so we need to subtract two
6286 and check next_hop explicitly */
6287 if ((pos->distance == path_len - 2) && (pos->next_hop == next_hop))
6288 {
6289 int match = GNUNET_YES;
6290
6291 for (unsigned int i = 0; i < pos->distance; i++)
6292 {
6293 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6294 {
6295 match = GNUNET_NO;
6296 break;
6297 }
6298 }
6299 if (GNUNET_YES == match)
6300 {
6301 struct GNUNET_TIME_Relative last_timeout;
6302
6303 /* Re-discovered known path, update timeout */
6304 GNUNET_STATISTICS_update (GST_stats,
6305 "# Known DV path refreshed",
6306 1,
6307 GNUNET_NO);
6308 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6309 pos->timeout =
6310 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6311 pos->path_valid_until =
6312 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6313 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6314 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6315 if (0 <
6316 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6317 activate_core_visible_dv_path (pos);
6318 if (last_timeout.rel_value_us <
6319 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6320 DV_PATH_DISCOVERY_FREQUENCY)
6321 .rel_value_us)
6322 {
6323 /* Some peer send DV learn messages too often, we are learning
6324 the same path faster than it would be useful; do not forward! */
6325 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6326 "Rediscovered path too quickly, not forwarding further\n");
6327 return GNUNET_NO;
6328 }
6329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6330 "Refreshed known path to %s, forwarding further\n",
6331 GNUNET_i2s (&dv->target));
6332 return GNUNET_YES;
6333 }
6334 }
6335 }
6336 /* Count how many shorter paths we have (incl. direct
6337 neighbours) before simply giving up on this one! */
6338 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6339 {
6340 /* We have a shorter path already! */
6341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6342 "Have many shorter DV paths %s, not forwarding further\n",
6343 GNUNET_i2s (&dv->target));
6344 return GNUNET_NO;
6345 }
6346 /* create new DV path entry */
6347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6348 "Discovered new DV path to %s\n",
6349 GNUNET_i2s (&dv->target));
6350 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
6351 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 2));
6352 hop->next_hop = next_hop;
6353 hop->dv = dv;
6354 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6355 memcpy (&hop[1],
6356 &path[2],
6357 sizeof(struct GNUNET_PeerIdentity) * (path_len - 2));
6358 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6359 hop->path_valid_until = path_valid_until;
6360 hop->distance = path_len - 2;
6361 hop->pd.aged_rtt = network_latency;
6362 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6363 GNUNET_CONTAINER_MDLL_insert (neighbour,
6364 next_hop->dv_head,
6365 next_hop->dv_tail,
6366 hop);
6367 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6368 activate_core_visible_dv_path (hop);
6369 return GNUNET_YES;
6370}
6371
6372
6373/**
6374 * Communicator gave us a DV learn message. Check the message.
6375 *
6376 * @param cls a `struct CommunicatorMessageContext`
6377 * @param dvl the send message that was sent
6378 * @return #GNUNET_YES if message is well-formed
6379 */
6380static int
6381check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6382{
6383 uint16_t size = ntohs (dvl->header.size);
6384 uint16_t num_hops = ntohs (dvl->num_hops);
6385 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6386
6387 (void) cls;
6388 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
6389 {
6390 GNUNET_break_op (0);
6391 return GNUNET_SYSERR;
6392 }
6393 if (num_hops > MAX_DV_HOPS_ALLOWED)
6394 {
6395 GNUNET_break_op (0);
6396 return GNUNET_SYSERR;
6397 }
6398 for (unsigned int i = 0; i < num_hops; i++)
6399 {
6400 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6401 {
6402 GNUNET_break_op (0);
6403 return GNUNET_SYSERR;
6404 }
6405 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6406 {
6407 GNUNET_break_op (0);
6408 return GNUNET_SYSERR;
6409 }
6410 }
6411 return GNUNET_YES;
6412}
6413
6414
6415/**
6416 * Build and forward a DV learn message to @a next_hop.
6417 *
6418 * @param next_hop peer to send the message to
6419 * @param msg message received
6420 * @param bi_history bitmask specifying hops on path that were bidirectional
6421 * @param nhops length of the @a hops array
6422 * @param hops path the message traversed so far
6423 * @param in_time when did we receive the message, used to calculate network
6424 * delay
6425 */
6426static void
6427forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6428 const struct TransportDVLearnMessage *msg,
6429 uint16_t bi_history,
6430 uint16_t nhops,
6431 const struct DVPathEntryP *hops,
6432 struct GNUNET_TIME_Absolute in_time)
6433{
6434 struct DVPathEntryP *dhops;
6435 char buf[sizeof(struct TransportDVLearnMessage)
6436 + (nhops + 1) * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
6437 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
6438 struct GNUNET_TIME_Relative nnd;
6439
6440 /* compute message for forwarding */
6441 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6442 "Forwarding DV learn message originating from %s to %s\n",
6443 GNUNET_i2s (&msg->initiator),
6444 GNUNET_i2s2 (next_hop));
6445 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6446 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6447 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
6448 + (nhops + 1) * sizeof(struct DVPathEntryP));
6449 fwd->num_hops = htons (nhops + 1);
6450 fwd->bidirectional = htons (bi_history);
6451 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6452 GNUNET_TIME_relative_ntoh (
6453 msg->non_network_delay));
6454 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6455 fwd->init_sig = msg->init_sig;
6456 fwd->initiator = msg->initiator;
6457 fwd->challenge = msg->challenge;
6458 dhops = (struct DVPathEntryP *) &fwd[1];
6459 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
6460 dhops[nhops].hop = GST_my_identity;
6461 {
6462 struct DvHopPS dhp = {
6463 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6464 .purpose.size = htonl (sizeof(dhp)),
6465 .pred = dhops[nhops - 1].hop,
6466 .succ = *next_hop,
6467 .challenge = msg->challenge
6468 };
6469
6470 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6471 &dhp,
6472 &dhops[nhops].hop_sig);
6473 }
6474 route_control_message_without_fc (next_hop,
6475 &fwd->header,
6476 RMO_UNCONFIRMED_ALLOWED);
6477}
6478
6479
6480/**
6481 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6482 *
6483 * @param sender_monotonic_time monotonic time of the initiator
6484 * @param init the signer
6485 * @param challenge the challenge that was signed
6486 * @param init_sig signature presumably by @a init
6487 * @return #GNUNET_OK if the signature is valid
6488 */
6489static int
6490validate_dv_initiator_signature (
6491 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6492 const struct GNUNET_PeerIdentity *init,
6493 const struct ChallengeNonceP *challenge,
6494 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6495{
6496 struct DvInitPS ip = { .purpose.purpose = htonl (
6497 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6498 .purpose.size = htonl (sizeof(ip)),
6499 .monotonic_time = sender_monotonic_time,
6500 .challenge = *challenge };
6501
6502 if (
6503 GNUNET_OK !=
6504 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6505 &ip,
6506 init_sig,
6507 &init->public_key))
6508 {
6509 GNUNET_break_op (0);
6510 return GNUNET_SYSERR;
6511 }
6512 return GNUNET_OK;
6513}
6514
6515
6516/**
6517 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6518 */
6519struct NeighbourSelectionContext
6520{
6521 /**
6522 * Original message we received.
6523 */
6524 const struct TransportDVLearnMessage *dvl;
6525
6526 /**
6527 * The hops taken.
6528 */
6529 const struct DVPathEntryP *hops;
6530
6531 /**
6532 * Time we received the message.
6533 */
6534 struct GNUNET_TIME_Absolute in_time;
6535
6536 /**
6537 * Offsets of the selected peers.
6538 */
6539 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6540
6541 /**
6542 * Number of peers eligible for selection.
6543 */
6544 unsigned int num_eligible;
6545
6546 /**
6547 * Number of peers that were selected for forwarding.
6548 */
6549 unsigned int num_selections;
6550
6551 /**
6552 * Number of hops in @e hops
6553 */
6554 uint16_t nhops;
6555
6556 /**
6557 * Bitmap of bidirectional connections encountered.
6558 */
6559 uint16_t bi_history;
6560};
6561
6562
6563/**
6564 * Function called for each neighbour during #handle_dv_learn.
6565 *
6566 * @param cls a `struct NeighbourSelectionContext *`
6567 * @param pid identity of the peer
6568 * @param value a `struct Neighbour`
6569 * @return #GNUNET_YES (always)
6570 */
6571static int
6572dv_neighbour_selection (void *cls,
6573 const struct GNUNET_PeerIdentity *pid,
6574 void *value)
6575{
6576 struct NeighbourSelectionContext *nsc = cls;
6577
6578 (void) value;
6579 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6580 return GNUNET_YES; /* skip initiator */
6581 for (unsigned int i = 0; i < nsc->nhops; i++)
6582 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6583 return GNUNET_YES;
6584 /* skip peers on path */
6585 nsc->num_eligible++;
6586 return GNUNET_YES;
6587}
6588
6589
6590/**
6591 * Function called for each neighbour during #handle_dv_learn.
6592 * We call #forward_dv_learn() on the neighbour(s) selected
6593 * during #dv_neighbour_selection().
6594 *
6595 * @param cls a `struct NeighbourSelectionContext *`
6596 * @param pid identity of the peer
6597 * @param value a `struct Neighbour`
6598 * @return #GNUNET_YES (always)
6599 */
6600static int
6601dv_neighbour_transmission (void *cls,
6602 const struct GNUNET_PeerIdentity *pid,
6603 void *value)
6604{
6605 struct NeighbourSelectionContext *nsc = cls;
6606
6607 (void) value;
6608 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
6609 return GNUNET_YES; /* skip initiator */
6610 for (unsigned int i = 0; i < nsc->nhops; i++)
6611 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
6612 return GNUNET_YES;
6613 /* skip peers on path */
6614 for (unsigned int i = 0; i < nsc->num_selections; i++)
6615 {
6616 if (nsc->selections[i] == nsc->num_eligible)
6617 {
6618 forward_dv_learn (pid,
6619 nsc->dvl,
6620 nsc->bi_history,
6621 nsc->nhops,
6622 nsc->hops,
6623 nsc->in_time);
6624 break;
6625 }
6626 }
6627 nsc->num_eligible++;
6628 return GNUNET_YES;
6629}
6630
6631
6632/**
6633 * Computes the number of neighbours we should forward a DVInit
6634 * message to given that it has so far taken @a hops_taken hops
6635 * though the network and that the number of neighbours we have
6636 * in total is @a neighbour_count, out of which @a eligible_count
6637 * are not yet on the path.
6638 *
6639 * NOTE: technically we might want to include NSE in the formula to
6640 * get a better grip on the overall network size. However, for now
6641 * using NSE here would create a dependency issue in the build system.
6642 * => Left for later, hardcoded to 50 for now.
6643 *
6644 * The goal of the fomula is that we want to reach a total of LOG(NSE)
6645 * peers via DV (`target_total`). We want the reach to be spread out
6646 * over various distances to the origin, with a bias towards shorter
6647 * distances.
6648 *
6649 * We make the strong assumption that the network topology looks
6650 * "similar" at other hops, in particular the @a neighbour_count
6651 * should be comparable at other hops.
6652 *
6653 * If the local neighbourhood is densely connected, we expect that @a
6654 * eligible_count is close to @a neighbour_count minus @a hops_taken
6655 * as a lot of the path is already known. In that case, we should
6656 * forward to few(er) peers to try to find a path out of the
6657 * neighbourhood. OTOH, if @a eligible_count is close to @a
6658 * neighbour_count, we should forward to many peers as we are either
6659 * still close to the origin (i.e. @a hops_taken is small) or because
6660 * we managed to get beyond a local cluster. We express this as
6661 * the `boost_factor` using the square of the fraction of eligible
6662 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
6663 * 99% are eligible, the 'boost' will be almost 1).
6664 *
6665 * Second, the more hops we have taken, the larger the problem of an
6666 * exponential traffic explosion gets. So we take the `target_total`,
6667 * and compute our degree such that at each distance d 2^{-d} peers
6668 * are selected (corrected by the `boost_factor`).
6669 *
6670 * @param hops_taken number of hops DVInit has travelled so far
6671 * @param neighbour_count number of neighbours we have in total
6672 * @param eligible_count number of neighbours we could in
6673 * theory forward to
6674 */
6675static unsigned int
6676calculate_fork_degree (unsigned int hops_taken,
6677 unsigned int neighbour_count,
6678 unsigned int eligible_count)
6679{
6680 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
6681 double eligible_ratio =
6682 ((double) eligible_count) / ((double) neighbour_count);
6683 double boost_factor = eligible_ratio * eligible_ratio;
6684 unsigned int rnd;
6685 double left;
6686
6687 if (hops_taken >= 64)
6688 {
6689 GNUNET_break (0);
6690 return 0; /* precaution given bitshift below */
6691 }
6692 for (unsigned int i = 1; i < hops_taken; i++)
6693 {
6694 /* For each hop, subtract the expected number of targets
6695 reached at distance d (so what remains divided by 2^d) */
6696 target_total -= (target_total * boost_factor / (1LLU << i));
6697 }
6698 rnd =
6699 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
6700 /* round up or down probabilistically depending on how close we were
6701 when floor()ing to rnd */
6702 left = target_total - (double) rnd;
6703 if (UINT32_MAX * left >
6704 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
6705 rnd++; /* round up */
6706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6707 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
6708 hops_taken,
6709 rnd,
6710 eligible_count,
6711 neighbour_count);
6712 return rnd;
6713}
6714
6715
6716/**
6717 * Function called when peerstore is done storing a DV monotonic time.
6718 *
6719 * @param cls a `struct Neighbour`
6720 * @param success #GNUNET_YES if peerstore was successful
6721 */
6722static void
6723neighbour_store_dvmono_cb (void *cls, int success)
6724{
6725 struct Neighbour *n = cls;
6726
6727 n->sc = NULL;
6728 if (GNUNET_YES != success)
6729 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
6730 "Failed to store other peer's monotonic time in peerstore!\n");
6731}
6732
6733
6734/**
6735 * Communicator gave us a DV learn message. Process the request.
6736 *
6737 * @param cls a `struct CommunicatorMessageContext` (must call
6738 * #finish_cmc_handling() when done)
6739 * @param dvl the message that was received
6740 */
6741static void
6742handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6743{
6744 struct CommunicatorMessageContext *cmc = cls;
6745 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
6746 int bi_hop;
6747 uint16_t nhops;
6748 uint16_t bi_history;
6749 const struct DVPathEntryP *hops;
6750 int do_fwd;
6751 int did_initiator;
6752 struct GNUNET_TIME_Absolute in_time;
6753 struct Neighbour *n;
6754
6755 nhops = ntohs (dvl->bidirectional); /* 0 = sender is initiator */
6756 bi_history = ntohs (dvl->bidirectional);
6757 hops = (const struct DVPathEntryP *) &dvl[1];
6758 if (0 == nhops)
6759 {
6760 /* sanity check */
6761 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
6762 {
6763 GNUNET_break (0);
6764 finish_cmc_handling (cmc);
6765 return;
6766 }
6767 }
6768 else
6769 {
6770 /* sanity check */
6771 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
6772 {
6773 GNUNET_break (0);
6774 finish_cmc_handling (cmc);
6775 return;
6776 }
6777 }
6778
6779 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
6780 cc = cmc->tc->details.communicator.cc;
6781 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
6782 cc); // FIXME: add bi-directional flag to cc?
6783 in_time = GNUNET_TIME_absolute_get ();
6784
6785 /* continue communicator here, everything else can happen asynchronous! */
6786 finish_cmc_handling (cmc);
6787
6788 n = lookup_neighbour (&dvl->initiator);
6789 if (NULL != n)
6790 {
6791 if ((n->dv_monotime_available == GNUNET_YES) &&
6792 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
6793 n->last_dv_learn_monotime.abs_value_us))
6794 {
6795 GNUNET_STATISTICS_update (GST_stats,
6796 "# DV learn discarded due to time travel",
6797 1,
6798 GNUNET_NO);
6799 return;
6800 }
6801 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
6802 &dvl->initiator,
6803 &dvl->challenge,
6804 &dvl->init_sig))
6805 {
6806 GNUNET_break_op (0);
6807 return;
6808 }
6809 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
6810 if (GNUNET_YES == n->dv_monotime_available)
6811 {
6812 if (NULL != n->sc)
6813 GNUNET_PEERSTORE_store_cancel (n->sc);
6814 n->sc =
6815 GNUNET_PEERSTORE_store (peerstore,
6816 "transport",
6817 &dvl->initiator,
6818 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
6819 &dvl->monotonic_time,
6820 sizeof(dvl->monotonic_time),
6821 GNUNET_TIME_UNIT_FOREVER_ABS,
6822 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
6823 &neighbour_store_dvmono_cb,
6824 n);
6825 }
6826 }
6827 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
6828 If signature verification load too high, implement random drop strategy */
6829 for (unsigned int i = 0; i < nhops; i++)
6830 {
6831 struct DvHopPS dhp = { .purpose.purpose =
6832 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6833 .purpose.size = htonl (sizeof(dhp)),
6834 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
6835 .succ = (nhops == i + 1) ? GST_my_identity
6836 : hops[i + 1].hop,
6837 .challenge = dvl->challenge };
6838
6839 if (GNUNET_OK !=
6840 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
6841 &dhp,
6842 &hops[i].hop_sig,
6843 &hops[i].hop.public_key))
6844 {
6845 GNUNET_break_op (0);
6846 return;
6847 }
6848 }
6849
6850 if (GNUNET_EXTRA_LOGGING > 0)
6851 {
6852 char *path;
6853
6854 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
6855 for (unsigned int i = 0; i < nhops; i++)
6856 {
6857 char *tmp;
6858
6859 GNUNET_asprintf (&tmp,
6860 "%s%s%s",
6861 path,
6862 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
6863 GNUNET_i2s (&hops[i].hop));
6864 GNUNET_free (path);
6865 path = tmp;
6866 }
6867 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6868 "Received DVInit via %s%s%s\n",
6869 path,
6870 bi_hop ? "<->" : "-->",
6871 GNUNET_i2s (&GST_my_identity));
6872 GNUNET_free (path);
6873 }
6874
6875 do_fwd = GNUNET_YES;
6876 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
6877 {
6878 struct GNUNET_PeerIdentity path[nhops + 1];
6879 struct GNUNET_TIME_Relative host_latency_sum;
6880 struct GNUNET_TIME_Relative latency;
6881 struct GNUNET_TIME_Relative network_latency;
6882
6883 /* We initiated this, learn the forward path! */
6884 path[0] = GST_my_identity;
6885 path[1] = hops[0].hop;
6886 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
6887
6888 // Need also something to lookup initiation time
6889 // to compute RTT! -> add RTT argument here?
6890 latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
6891 // (based on dvl->challenge, we can identify time of origin!)
6892
6893 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
6894 /* assumption: latency on all links is the same */
6895 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
6896
6897 for (unsigned int i = 2; i <= nhops; i++)
6898 {
6899 struct GNUNET_TIME_Relative ilat;
6900
6901 /* assumption: linear latency increase per hop */
6902 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
6903 path[i] = hops[i - 1].hop;
6904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6905 "Learned path with %u hops to %s with latency %s\n",
6906 i,
6907 GNUNET_i2s (&path[i]),
6908 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
6909 learn_dv_path (path,
6910 i,
6911 ilat,
6912 GNUNET_TIME_relative_to_absolute (
6913 ADDRESS_VALIDATION_LIFETIME));
6914 }
6915 /* as we initiated, do not forward again (would be circular!) */
6916 do_fwd = GNUNET_NO;
6917 return;
6918 }
6919 if (bi_hop)
6920 {
6921 /* last hop was bi-directional, we could learn something here! */
6922 struct GNUNET_PeerIdentity path[nhops + 2];
6923
6924 path[0] = GST_my_identity;
6925 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
6926 for (unsigned int i = 0; i < nhops; i++)
6927 {
6928 int iret;
6929
6930 if (0 == (bi_history & (1 << i)))
6931 break; /* i-th hop not bi-directional, stop learning! */
6932 if (i == nhops - 1)
6933 {
6934 path[i + 2] = dvl->initiator;
6935 }
6936 else
6937 {
6938 path[i + 2] = hops[nhops - i - 2].hop;
6939 }
6940
6941 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6942 "Learned inverse path with %u hops to %s\n",
6943 i + 1,
6944 GNUNET_i2s (&path[i + 2]));
6945 iret = learn_dv_path (path,
6946 i + 2,
6947 GNUNET_TIME_UNIT_FOREVER_REL,
6948 GNUNET_TIME_UNIT_ZERO_ABS);
6949 if (GNUNET_SYSERR == iret)
6950 {
6951 /* path invalid or too long to be interesting for US, thus should also
6952 not be interesting to our neighbours, cut path when forwarding to
6953 'i' hops, except of course for the one that goes back to the
6954 initiator */
6955 GNUNET_STATISTICS_update (GST_stats,
6956 "# DV learn not forwarded due invalidity of path",
6957 1,
6958 GNUNET_NO);
6959 do_fwd = GNUNET_NO;
6960 break;
6961 }
6962 if ((GNUNET_NO == iret) && (nhops == i + 1))
6963 {
6964 /* we have better paths, and this is the longest target,
6965 so there cannot be anything interesting later */
6966 GNUNET_STATISTICS_update (GST_stats,
6967 "# DV learn not forwarded, got better paths",
6968 1,
6969 GNUNET_NO);
6970 do_fwd = GNUNET_NO;
6971 break;
6972 }
6973 }
6974 }
6975
6976 if (MAX_DV_HOPS_ALLOWED == nhops)
6977 {
6978 /* At limit, we're out of here! */
6979 return;
6980 }
6981
6982 /* Forward to initiator, if path non-trivial and possible */
6983 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
6984 did_initiator = GNUNET_NO;
6985 if ((1 < nhops) &&
6986 (GNUNET_YES ==
6987 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
6988 {
6989 /* send back to origin! */
6990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6991 "Sending DVL back to initiator %s\n",
6992 GNUNET_i2s (&dvl->initiator));
6993 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
6994 did_initiator = GNUNET_YES;
6995 }
6996 /* We forward under two conditions: either we still learned something
6997 ourselves (do_fwd), or the path was darn short and thus the initiator is
6998 likely to still be very interested in this (and we did NOT already
6999 send it back to the initiator) */
7000 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
7001 (GNUNET_NO == did_initiator)))
7002 {
7003 /* Pick random neighbours that are not yet on the path */
7004 struct NeighbourSelectionContext nsc;
7005 unsigned int n_cnt;
7006
7007 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
7008 nsc.nhops = nhops;
7009 nsc.dvl = dvl;
7010 nsc.bi_history = bi_history;
7011 nsc.hops = hops;
7012 nsc.in_time = in_time;
7013 nsc.num_eligible = 0;
7014 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7015 &dv_neighbour_selection,
7016 &nsc);
7017 if (0 == nsc.num_eligible)
7018 return; /* done here, cannot forward to anyone else */
7019 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
7020 nsc.num_selections =
7021 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
7022 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7023 "Forwarding DVL to %u other peers\n",
7024 nsc.num_selections);
7025 for (unsigned int i = 0; i < nsc.num_selections; i++)
7026 nsc.selections[i] =
7027 (nsc.num_selections == n_cnt)
7028 ? i /* all were selected, avoid collisions by chance */
7029 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
7030 nsc.num_eligible = 0;
7031 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7032 &dv_neighbour_transmission,
7033 &nsc);
7034 }
7035}
7036
7037
7038/**
7039 * Communicator gave us a DV box. Check the message.
7040 *
7041 * @param cls a `struct CommunicatorMessageContext`
7042 * @param dvb the send message that was sent
7043 * @return #GNUNET_YES if message is well-formed
7044 */
7045static int
7046check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7047{
7048 uint16_t size = ntohs (dvb->header.size);
7049 uint16_t num_hops = ntohs (dvb->num_hops);
7050 const struct GNUNET_PeerIdentity *hops =
7051 (const struct GNUNET_PeerIdentity *) &dvb[1];
7052
7053 (void) cls;
7054 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
7055 + sizeof(struct GNUNET_MessageHeader))
7056 {
7057 GNUNET_break_op (0);
7058 return GNUNET_SYSERR;
7059 }
7060 /* This peer must not be on the path */
7061 for (unsigned int i = 0; i < num_hops; i++)
7062 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7063 {
7064 GNUNET_break_op (0);
7065 return GNUNET_SYSERR;
7066 }
7067 return GNUNET_YES;
7068}
7069
7070
7071/**
7072 * Create a DV Box message and queue it for transmission to
7073 * @ea next_hop.
7074 *
7075 * @param next_hop peer to receive the message next
7076 * @param total_hops how many hops did the message take so far
7077 * @param num_hops length of the @a hops array
7078 * @param origin origin of the message
7079 * @param hops next peer(s) to the destination, including destination
7080 * @param payload payload of the box
7081 * @param payload_size number of bytes in @a payload
7082 */
7083static void
7084forward_dv_box (struct Neighbour *next_hop,
7085 const struct TransportDVBoxMessage *hdr,
7086 uint16_t total_hops,
7087 uint16_t num_hops,
7088 const struct GNUNET_PeerIdentity *hops,
7089 const void *enc_payload,
7090 uint16_t enc_payload_size)
7091{
7092 struct VirtualLink *vl = next_hop->vl;
7093 struct PendingMessage *pm;
7094 size_t msg_size;
7095 char *buf;
7096 struct GNUNET_PeerIdentity *dhops;
7097
7098 GNUNET_assert (NULL != vl);
7099 msg_size = sizeof(struct TransportDVBoxMessage)
7100 + num_hops * sizeof(struct GNUNET_PeerIdentity) + enc_payload_size;
7101 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
7102 pm->pmt = PMT_DV_BOX;
7103 pm->vl = vl;
7104 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
7105 pm->logging_uuid = logging_uuid_gen++;
7106 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
7107 pm->bytes_msg = msg_size;
7108 buf = (char *) &pm[1];
7109 memcpy (buf, hdr, sizeof(*hdr));
7110 dhops =
7111 (struct GNUNET_PeerIdentity *) &buf[sizeof(struct TransportDVBoxMessage)];
7112 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
7113 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
7114 GNUNET_CONTAINER_MDLL_insert (vl,
7115 vl->pending_msg_head,
7116 vl->pending_msg_tail,
7117 pm);
7118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7119 "Created pending message %llu for DV Box with next hop %s (%u/%u)\n",
7120 pm->logging_uuid,
7121 GNUNET_i2s (&next_hop->pid),
7122 (unsigned int) num_hops,
7123 (unsigned int) total_hops);
7124 check_vl_transmission (vl);
7125}
7126
7127
7128/**
7129 * Free data structures associated with @a b.
7130 *
7131 * @param b data structure to release
7132 */
7133static void
7134free_backtalker (struct Backtalker *b)
7135{
7136 if (NULL != b->get)
7137 {
7138 GNUNET_PEERSTORE_iterate_cancel (b->get);
7139 b->get = NULL;
7140 GNUNET_assert (NULL != b->cmc);
7141 finish_cmc_handling (b->cmc);
7142 b->cmc = NULL;
7143 }
7144 if (NULL != b->task)
7145 {
7146 GNUNET_SCHEDULER_cancel (b->task);
7147 b->task = NULL;
7148 }
7149 if (NULL != b->sc)
7150 {
7151 GNUNET_PEERSTORE_store_cancel (b->sc);
7152 b->sc = NULL;
7153 }
7154 GNUNET_assert (
7155 GNUNET_YES ==
7156 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
7157 GNUNET_free (b);
7158}
7159
7160
7161/**
7162 * Callback to free backtalker records.
7163 *
7164 * @param cls NULL
7165 * @param pid unused
7166 * @param value a `struct Backtalker`
7167 * @return #GNUNET_OK (always)
7168 */
7169static int
7170free_backtalker_cb (void *cls,
7171 const struct GNUNET_PeerIdentity *pid,
7172 void *value)
7173{
7174 struct Backtalker *b = value;
7175
7176 (void) cls;
7177 (void) pid;
7178 free_backtalker (b);
7179 return GNUNET_OK;
7180}
7181
7182
7183/**
7184 * Function called when it is time to clean up a backtalker.
7185 *
7186 * @param cls a `struct Backtalker`
7187 */
7188static void
7189backtalker_timeout_cb (void *cls)
7190{
7191 struct Backtalker *b = cls;
7192
7193 b->task = NULL;
7194 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
7195 {
7196 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7197 return;
7198 }
7199 GNUNET_assert (NULL == b->sc);
7200 free_backtalker (b);
7201}
7202
7203
7204/**
7205 * Function called with the monotonic time of a backtalker
7206 * by PEERSTORE. Updates the time and continues processing.
7207 *
7208 * @param cls a `struct Backtalker`
7209 * @param record the information found, NULL for the last call
7210 * @param emsg error message
7211 */
7212static void
7213backtalker_monotime_cb (void *cls,
7214 const struct GNUNET_PEERSTORE_Record *record,
7215 const char *emsg)
7216{
7217 struct Backtalker *b = cls;
7218 struct GNUNET_TIME_AbsoluteNBO *mtbe;
7219 struct GNUNET_TIME_Absolute mt;
7220
7221 (void) emsg;
7222 if (NULL == record)
7223 {
7224 /* we're done with #backtalker_monotime_cb() invocations,
7225 continue normal processing */
7226 b->get = NULL;
7227 GNUNET_assert (NULL != b->cmc);
7228 if (0 != b->body_size)
7229 demultiplex_with_cmc (b->cmc,
7230 (const struct GNUNET_MessageHeader *) &b[1]);
7231 else
7232 finish_cmc_handling (b->cmc);
7233 b->cmc = NULL;
7234 return;
7235 }
7236 if (sizeof(*mtbe) != record->value_size)
7237 {
7238 GNUNET_break (0);
7239 return;
7240 }
7241 mtbe = record->value;
7242 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
7243 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
7244 {
7245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7246 "Backtalker message from %s dropped, monotime in the past\n",
7247 GNUNET_i2s (&b->pid));
7248 GNUNET_STATISTICS_update (
7249 GST_stats,
7250 "# Backchannel messages dropped: monotonic time not increasing",
7251 1,
7252 GNUNET_NO);
7253 b->monotonic_time = mt;
7254 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
7255 */
7256 b->body_size = 0;
7257 return;
7258 }
7259}
7260
7261
7262/**
7263 * Function called by PEERSTORE when the store operation of
7264 * a backtalker's monotonic time is complete.
7265 *
7266 * @param cls the `struct Backtalker`
7267 * @param success #GNUNET_OK on success
7268 */
7269static void
7270backtalker_monotime_store_cb (void *cls, int success)
7271{
7272 struct Backtalker *b = cls;
7273
7274 if (GNUNET_OK != success)
7275 {
7276 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7277 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
7278 }
7279 b->sc = NULL;
7280 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7281}
7282
7283
7284/**
7285 * The backtalker @a b monotonic time changed. Update PEERSTORE.
7286 *
7287 * @param b a backtalker with updated monotonic time
7288 */
7289static void
7290update_backtalker_monotime (struct Backtalker *b)
7291{
7292 struct GNUNET_TIME_AbsoluteNBO mtbe;
7293
7294 if (NULL != b->sc)
7295 {
7296 GNUNET_PEERSTORE_store_cancel (b->sc);
7297 b->sc = NULL;
7298 }
7299 else
7300 {
7301 GNUNET_SCHEDULER_cancel (b->task);
7302 b->task = NULL;
7303 }
7304 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
7305 b->sc =
7306 GNUNET_PEERSTORE_store (peerstore,
7307 "transport",
7308 &b->pid,
7309 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7310 &mtbe,
7311 sizeof(mtbe),
7312 GNUNET_TIME_UNIT_FOREVER_ABS,
7313 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7314 &backtalker_monotime_store_cb,
7315 b);
7316}
7317
7318
7319/**
7320 * Communicator gave us a DV box. Process the request.
7321 *
7322 * @param cls a `struct CommunicatorMessageContext` (must call
7323 * #finish_cmc_handling() when done)
7324 * @param dvb the message that was received
7325 */
7326static void
7327handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7328{
7329 struct CommunicatorMessageContext *cmc = cls;
7330 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
7331 uint16_t num_hops = ntohs (dvb->num_hops);
7332 const struct GNUNET_PeerIdentity *hops =
7333 (const struct GNUNET_PeerIdentity *) &dvb[1];
7334 const char *enc_payload = (const char *) &hops[num_hops];
7335 uint16_t enc_payload_size =
7336 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
7337 struct DVKeyState key;
7338 struct GNUNET_HashCode hmac;
7339 const char *hdr;
7340 size_t hdr_len;
7341
7342 if (GNUNET_EXTRA_LOGGING > 0)
7343 {
7344 char *path;
7345
7346 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
7347 for (unsigned int i = 0; i < num_hops; i++)
7348 {
7349 char *tmp;
7350
7351 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7352 GNUNET_free (path);
7353 path = tmp;
7354 }
7355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7356 "Received DVBox with remaining path %s\n",
7357 path);
7358 GNUNET_free (path);
7359 }
7360
7361 if (num_hops > 0)
7362 {
7363 /* We're trying from the end of the hops array, as we may be
7364 able to find a shortcut unknown to the origin that way */
7365 for (int i = num_hops - 1; i >= 0; i--)
7366 {
7367 struct Neighbour *n;
7368
7369 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7370 {
7371 GNUNET_break_op (0);
7372 finish_cmc_handling (cmc);
7373 return;
7374 }
7375 n = lookup_neighbour (&hops[i]);
7376 if (NULL == n)
7377 continue;
7378 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7379 "Skipping %u/%u hops ahead while routing DV Box\n",
7380 i,
7381 num_hops);
7382 forward_dv_box (n,
7383 dvb,
7384 ntohs (dvb->total_hops) + 1,
7385 num_hops - i - 1, /* number of hops left */
7386 &hops[i + 1], /* remaining hops */
7387 enc_payload,
7388 enc_payload_size);
7389 GNUNET_STATISTICS_update (GST_stats,
7390 "# DV hops skipped routing boxes",
7391 i,
7392 GNUNET_NO);
7393 GNUNET_STATISTICS_update (GST_stats,
7394 "# DV boxes routed (total)",
7395 1,
7396 GNUNET_NO);
7397 finish_cmc_handling (cmc);
7398 return;
7399 }
7400 /* Woopsie, next hop not in neighbours, drop! */
7401 GNUNET_STATISTICS_update (GST_stats,
7402 "# DV Boxes dropped: next hop unknown",
7403 1,
7404 GNUNET_NO);
7405 finish_cmc_handling (cmc);
7406 return;
7407 }
7408 /* We are the target. Unbox and handle message. */
7409 GNUNET_STATISTICS_update (GST_stats,
7410 "# DV boxes opened (ultimate target)",
7411 1,
7412 GNUNET_NO);
7413 cmc->total_hops = ntohs (dvb->total_hops);
7414
7415 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, &key);
7416 hdr = (const char *) &dvb[1];
7417 hdr_len = ntohs (dvb->header.size) - sizeof(*dvb);
7418 dv_hmac (&key, &hmac, hdr, hdr_len);
7419 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
7420 {
7421 /* HMAC mismatch, discard! */
7422 GNUNET_break_op (0);
7423 finish_cmc_handling (cmc);
7424 return;
7425 }
7426 /* begin actual decryption */
7427 {
7428 struct Backtalker *b;
7429 struct GNUNET_TIME_Absolute monotime;
7430 struct TransportDVBoxPayloadP ppay;
7431 char body[hdr_len - sizeof(ppay)] GNUNET_ALIGN;
7432 const struct GNUNET_MessageHeader *mh =
7433 (const struct GNUNET_MessageHeader *) body;
7434
7435 GNUNET_assert (hdr_len >=
7436 sizeof(ppay) + sizeof(struct GNUNET_MessageHeader));
7437 dv_decrypt (&key, &ppay, hdr, sizeof(ppay));
7438 dv_decrypt (&key, &body, &hdr[sizeof(ppay)], hdr_len - sizeof(ppay));
7439 dv_key_clean (&key);
7440 if (ntohs (mh->size) != sizeof(body))
7441 {
7442 GNUNET_break_op (0);
7443 finish_cmc_handling (cmc);
7444 return;
7445 }
7446 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
7447 switch (ntohs (mh->type))
7448 {
7449 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
7450 GNUNET_break_op (0);
7451 finish_cmc_handling (cmc);
7452 return;
7453
7454 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
7455 GNUNET_break_op (0);
7456 finish_cmc_handling (cmc);
7457 return;
7458
7459 default:
7460 /* permitted, continue */
7461 break;
7462 }
7463 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
7464 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7465 "Decrypted backtalk from %s\n",
7466 GNUNET_i2s (&ppay.sender));
7467 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
7468 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
7469 {
7470 GNUNET_STATISTICS_update (
7471 GST_stats,
7472 "# Backchannel messages dropped: monotonic time not increasing",
7473 1,
7474 GNUNET_NO);
7475 finish_cmc_handling (cmc);
7476 return;
7477 }
7478 if ((NULL == b) ||
7479 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
7480 {
7481 /* Check signature */
7482 struct EphemeralConfirmationPS ec;
7483
7484 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
7485 ec.purpose.size = htonl (sizeof(ec));
7486 ec.target = GST_my_identity;
7487 ec.ephemeral_key = dvb->ephemeral_key;
7488 if (
7489 GNUNET_OK !=
7490 GNUNET_CRYPTO_eddsa_verify (
7491 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
7492 &ec,
7493 &ppay.sender_sig,
7494 &ppay.sender.public_key))
7495 {
7496 /* Signature invalid, discard! */
7497 GNUNET_break_op (0);
7498 finish_cmc_handling (cmc);
7499 return;
7500 }
7501 }
7502 /* Update sender, we now know the real origin! */
7503 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7504 "DVBox received for me from %s via %s\n",
7505 GNUNET_i2s2 (&ppay.sender),
7506 GNUNET_i2s (&cmc->im.sender));
7507 cmc->im.sender = ppay.sender;
7508
7509 if (NULL != b)
7510 {
7511 /* update key cache and mono time */
7512 b->last_ephemeral = dvb->ephemeral_key;
7513 b->monotonic_time = monotime;
7514 update_backtalker_monotime (b);
7515 b->timeout =
7516 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7517
7518 demultiplex_with_cmc (cmc, mh);
7519 return;
7520 }
7521 /* setup data structure to cache signature AND check
7522 monotonic time with PEERSTORE before forwarding backchannel payload */
7523 b = GNUNET_malloc (sizeof(struct Backtalker) + sizeof(body));
7524 b->pid = ppay.sender;
7525 b->body_size = sizeof(body);
7526 memcpy (&b[1], body, sizeof(body));
7527 GNUNET_assert (GNUNET_YES ==
7528 GNUNET_CONTAINER_multipeermap_put (
7529 backtalkers,
7530 &b->pid,
7531 b,
7532 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7533 b->monotonic_time = monotime; /* NOTE: to be checked still! */
7534 b->cmc = cmc;
7535 b->timeout =
7536 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
7537 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7538 b->get =
7539 GNUNET_PEERSTORE_iterate (peerstore,
7540 "transport",
7541 &b->pid,
7542 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7543 &backtalker_monotime_cb,
7544 b);
7545 } /* end actual decryption */
7546}
7547
7548
7549/**
7550 * Client notified us about transmission from a peer. Process the request.
7551 *
7552 * @param cls a `struct TransportClient` which sent us the message
7553 * @param obm the send message that was sent
7554 * @return #GNUNET_YES if message is well-formed
7555 */
7556static int
7557check_incoming_msg (void *cls,
7558 const struct GNUNET_TRANSPORT_IncomingMessage *im)
7559{
7560 struct TransportClient *tc = cls;
7561
7562 if (CT_COMMUNICATOR != tc->type)
7563 {
7564 GNUNET_break (0);
7565 return GNUNET_SYSERR;
7566 }
7567 GNUNET_MQ_check_boxed_message (im);
7568 return GNUNET_OK;
7569}
7570
7571
7572/**
7573 * Closure for #check_known_address.
7574 */
7575struct CheckKnownAddressContext
7576{
7577 /**
7578 * Set to the address we are looking for.
7579 */
7580 const char *address;
7581
7582 /**
7583 * Set to a matching validation state, if one was found.
7584 */
7585 struct ValidationState *vs;
7586};
7587
7588
7589/**
7590 * Test if the validation state in @a value matches the
7591 * address from @a cls.
7592 *
7593 * @param cls a `struct CheckKnownAddressContext`
7594 * @param pid unused (must match though)
7595 * @param value a `struct ValidationState`
7596 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7597 */
7598static int
7599check_known_address (void *cls,
7600 const struct GNUNET_PeerIdentity *pid,
7601 void *value)
7602{
7603 struct CheckKnownAddressContext *ckac = cls;
7604 struct ValidationState *vs = value;
7605
7606 (void) pid;
7607 if (0 != strcmp (vs->address, ckac->address))
7608 return GNUNET_OK;
7609 ckac->vs = vs;
7610 return GNUNET_NO;
7611}
7612
7613
7614/**
7615 * Task run periodically to validate some address based on #validation_heap.
7616 *
7617 * @param cls NULL
7618 */
7619static void
7620validation_start_cb (void *cls);
7621
7622
7623/**
7624 * Set the time for next_challenge of @a vs to @a new_time.
7625 * Updates the heap and if necessary reschedules the job.
7626 *
7627 * @param vs validation state to update
7628 * @param new_time new time for revalidation
7629 */
7630static void
7631update_next_challenge_time (struct ValidationState *vs,
7632 struct GNUNET_TIME_Absolute new_time)
7633{
7634 struct GNUNET_TIME_Relative delta;
7635
7636 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
7637 return; /* be lazy */
7638 vs->next_challenge = new_time;
7639 if (NULL == vs->hn)
7640 vs->hn =
7641 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
7642 else
7643 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
7644 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
7645 (NULL != validation_task))
7646 return;
7647 if (NULL != validation_task)
7648 GNUNET_SCHEDULER_cancel (validation_task);
7649 /* randomize a bit */
7650 delta.rel_value_us =
7651 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
7652 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
7653 new_time = GNUNET_TIME_absolute_add (new_time, delta);
7654 validation_task =
7655 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
7656}
7657
7658
7659/**
7660 * Start address validation.
7661 *
7662 * @param pid peer the @a address is for
7663 * @param address an address to reach @a pid (presumably)
7664 */
7665static void
7666start_address_validation (const struct GNUNET_PeerIdentity *pid,
7667 const char *address)
7668{
7669 struct GNUNET_TIME_Absolute now;
7670 struct ValidationState *vs;
7671 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
7672
7673 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7674 pid,
7675 &check_known_address,
7676 &ckac);
7677 if (NULL != (vs = ckac.vs))
7678 {
7679 /* if 'vs' is not currently valid, we need to speed up retrying the
7680 * validation */
7681 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
7682 {
7683 /* reduce backoff as we got a fresh advertisement */
7684 vs->challenge_backoff =
7685 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
7686 GNUNET_TIME_relative_divide (
7687 vs->challenge_backoff,
7688 2));
7689 update_next_challenge_time (vs,
7690 GNUNET_TIME_relative_to_absolute (
7691 vs->challenge_backoff));
7692 }
7693 return;
7694 }
7695 now = GNUNET_TIME_absolute_get ();
7696 vs = GNUNET_new (struct ValidationState);
7697 vs->pid = *pid;
7698 vs->valid_until =
7699 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
7700 vs->first_challenge_use = now;
7701 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
7702 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
7703 &vs->challenge,
7704 sizeof(vs->challenge));
7705 vs->address = GNUNET_strdup (address);
7706 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7707 "Starting address validation `%s' of peer %s using challenge %s\n",
7708 address,
7709 GNUNET_i2s (pid),
7710 GNUNET_sh2s (&vs->challenge.value));
7711 GNUNET_assert (GNUNET_YES ==
7712 GNUNET_CONTAINER_multipeermap_put (
7713 validation_map,
7714 &vs->pid,
7715 vs,
7716 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
7717 update_next_challenge_time (vs, now);
7718}
7719
7720
7721/**
7722 * Function called by PEERSTORE for each matching record.
7723 *
7724 * @param cls closure, a `struct IncomingRequest`
7725 * @param record peerstore record information
7726 * @param emsg error message, or NULL if no errors
7727 */
7728static void
7729handle_hello_for_incoming (void *cls,
7730 const struct GNUNET_PEERSTORE_Record *record,
7731 const char *emsg)
7732{
7733 struct IncomingRequest *ir = cls;
7734 const char *val;
7735
7736 if (NULL != emsg)
7737 {
7738 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
7739 "Got failure from PEERSTORE: %s\n",
7740 emsg);
7741 return;
7742 }
7743 val = record->value;
7744 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
7745 {
7746 GNUNET_break (0);
7747 return;
7748 }
7749 start_address_validation (&ir->pid, (const char *) record->value);
7750}
7751
7752
7753/**
7754 * Communicator gave us a transport address validation challenge. Process the
7755 * request.
7756 *
7757 * @param cls a `struct CommunicatorMessageContext` (must call
7758 * #finish_cmc_handling() when done)
7759 * @param tvc the message that was received
7760 */
7761static void
7762handle_validation_challenge (
7763 void *cls,
7764 const struct TransportValidationChallengeMessage *tvc)
7765{
7766 struct CommunicatorMessageContext *cmc = cls;
7767 struct TransportValidationResponseMessage tvr;
7768 struct VirtualLink *vl;
7769 struct GNUNET_TIME_RelativeNBO validity_duration;
7770 struct IncomingRequest *ir;
7771 struct Neighbour *n;
7772 struct GNUNET_PeerIdentity sender;
7773
7774 /* DV-routed messages are not allowed for validation challenges */
7775 if (cmc->total_hops > 0)
7776 {
7777 GNUNET_break_op (0);
7778 finish_cmc_handling (cmc);
7779 return;
7780 }
7781 validity_duration = cmc->im.expected_address_validity;
7782 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7783 "Received address validation challenge %s\n",
7784 GNUNET_sh2s (&tvc->challenge.value));
7785 /* If we have a virtual link, we use this mechanism to signal the
7786 size of the flow control window, and to allow the sender
7787 to ask for increases. If for us the virtual link is still down,
7788 we will always give a window size of zero. */
7789 tvr.header.type =
7790 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
7791 tvr.header.size = htons (sizeof(tvr));
7792 tvr.reserved = htonl (0);
7793 tvr.challenge = tvc->challenge;
7794 tvr.origin_time = tvc->sender_time;
7795 tvr.validity_duration = validity_duration;
7796 {
7797 /* create signature */
7798 struct TransportValidationPS tvp = {
7799 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
7800 .purpose.size = htonl (sizeof(tvp)),
7801 .validity_duration = validity_duration,
7802 .challenge = tvc->challenge
7803 };
7804
7805 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7806 &tvp,
7807 &tvr.signature);
7808 }
7809 sender = cmc->im.sender;
7810 vl = lookup_virtual_link (&sender);
7811 if (NULL != vl)
7812 {
7813 route_control_message_without_fc (&cmc->im.sender,
7814 &tvr.header,
7815 RMO_ANYTHING_GOES | RMO_REDUNDANT);
7816 }
7817 else
7818 {
7819 /* Use route via neighbour */
7820 n = lookup_neighbour (&sender);
7821 if (NULL != n)
7822 route_via_neighbour (n, &tvr.header,
7823 RMO_ANYTHING_GOES | RMO_REDUNDANT
7824 | RMO_UNCONFIRMED_ALLOWED);
7825 }
7826
7827 finish_cmc_handling (cmc);
7828 if (NULL != vl)
7829 return;
7830
7831 /* For us, the link is still down, but we need bi-directional
7832 connections (for flow-control and for this to be useful for
7833 CORE), so we must try to bring the link up! */
7834
7835 /* (1) Check existing queues, if any, we may be lucky! */
7836 n = lookup_neighbour (&sender);
7837 if (NULL != n)
7838 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
7839 start_address_validation (&sender, q->address);
7840 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
7841 we could use */
7842 for (ir = ir_head; NULL != ir; ir = ir->next)
7843 if (0 == GNUNET_memcmp (&ir->pid, &sender))
7844 return;
7845 /* we are already trying */
7846 ir = GNUNET_new (struct IncomingRequest);
7847 ir->pid = sender;
7848 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
7849 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
7850 "transport",
7851 &ir->pid,
7852 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
7853 &handle_hello_for_incoming,
7854 ir);
7855 ir_total++;
7856 /* Bound attempts we do in parallel here, might otherwise get excessive */
7857 while (ir_total > MAX_INCOMING_REQUEST)
7858 free_incoming_request (ir_head);
7859}
7860
7861
7862/**
7863 * Closure for #check_known_challenge.
7864 */
7865struct CheckKnownChallengeContext
7866{
7867 /**
7868 * Set to the challenge we are looking for.
7869 */
7870 const struct ChallengeNonceP *challenge;
7871
7872 /**
7873 * Set to a matching validation state, if one was found.
7874 */
7875 struct ValidationState *vs;
7876};
7877
7878
7879/**
7880 * Test if the validation state in @a value matches the
7881 * challenge from @a cls.
7882 *
7883 * @param cls a `struct CheckKnownChallengeContext`
7884 * @param pid unused (must match though)
7885 * @param value a `struct ValidationState`
7886 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
7887 */
7888static int
7889check_known_challenge (void *cls,
7890 const struct GNUNET_PeerIdentity *pid,
7891 void *value)
7892{
7893 struct CheckKnownChallengeContext *ckac = cls;
7894 struct ValidationState *vs = value;
7895
7896 (void) pid;
7897 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
7898 return GNUNET_OK;
7899 ckac->vs = vs;
7900 return GNUNET_NO;
7901}
7902
7903
7904/**
7905 * Function called when peerstore is done storing a
7906 * validated address.
7907 *
7908 * @param cls a `struct ValidationState`
7909 * @param success #GNUNET_YES on success
7910 */
7911static void
7912peerstore_store_validation_cb (void *cls, int success)
7913{
7914 struct ValidationState *vs = cls;
7915
7916 vs->sc = NULL;
7917 if (GNUNET_YES == success)
7918 return;
7919 GNUNET_STATISTICS_update (GST_stats,
7920 "# Peerstore failed to store foreign address",
7921 1,
7922 GNUNET_NO);
7923}
7924
7925
7926/**
7927 * Find the queue matching @a pid and @a address.
7928 *
7929 * @param pid peer the queue must go to
7930 * @param address address the queue must use
7931 * @return NULL if no such queue exists
7932 */
7933static struct Queue *
7934find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
7935{
7936 struct Neighbour *n;
7937
7938 n = lookup_neighbour (pid);
7939 if (NULL == n)
7940 return NULL;
7941 for (struct Queue *pos = n->queue_head; NULL != pos;
7942 pos = pos->next_neighbour)
7943 {
7944 if (0 == strcmp (pos->address, address))
7945 return pos;
7946 }
7947 return NULL;
7948}
7949
7950
7951/**
7952 * Communicator gave us a transport address validation response. Process the
7953 * request.
7954 *
7955 * @param cls a `struct CommunicatorMessageContext` (must call
7956 * #finish_cmc_handling() when done)
7957 * @param tvr the message that was received
7958 */
7959static void
7960handle_validation_response (
7961 void *cls,
7962 const struct TransportValidationResponseMessage *tvr)
7963{
7964 struct CommunicatorMessageContext *cmc = cls;
7965 struct ValidationState *vs;
7966 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
7967 .vs = NULL };
7968 struct GNUNET_TIME_Absolute origin_time;
7969 struct Queue *q;
7970 struct Neighbour *n;
7971 struct VirtualLink *vl;
7972
7973 /* check this is one of our challenges */
7974 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
7975 &cmc->im.sender,
7976 &check_known_challenge,
7977 &ckac);
7978 if (NULL == (vs = ckac.vs))
7979 {
7980 /* This can happen simply if we 'forgot' the challenge by now,
7981 i.e. because we received the validation response twice */
7982 GNUNET_STATISTICS_update (GST_stats,
7983 "# Validations dropped, challenge unknown",
7984 1,
7985 GNUNET_NO);
7986 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7987 "Validation response %s dropped, challenge unknown\n",
7988 GNUNET_sh2s (&tvr->challenge.value));
7989 finish_cmc_handling (cmc);
7990 return;
7991 }
7992
7993 /* sanity check on origin time */
7994 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
7995 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
7996 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
7997 {
7998 GNUNET_break_op (0);
7999 finish_cmc_handling (cmc);
8000 return;
8001 }
8002
8003 {
8004 /* check signature */
8005 struct TransportValidationPS tvp = {
8006 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
8007 .purpose.size = htonl (sizeof(tvp)),
8008 .validity_duration = tvr->validity_duration,
8009 .challenge = tvr->challenge
8010 };
8011
8012 if (
8013 GNUNET_OK !=
8014 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
8015 &tvp,
8016 &tvr->signature,
8017 &cmc->im.sender.public_key))
8018 {
8019 GNUNET_break_op (0);
8020 finish_cmc_handling (cmc);
8021 return;
8022 }
8023 }
8024
8025 /* validity is capped by our willingness to keep track of the
8026 validation entry and the maximum the other peer allows */
8027 vs->valid_until = GNUNET_TIME_relative_to_absolute (
8028 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
8029 tvr->validity_duration),
8030 MAX_ADDRESS_VALID_UNTIL));
8031 vs->validated_until =
8032 GNUNET_TIME_absolute_min (vs->valid_until,
8033 GNUNET_TIME_relative_to_absolute (
8034 ADDRESS_VALIDATION_LIFETIME));
8035 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
8036 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
8037 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8038 &vs->challenge,
8039 sizeof(vs->challenge));
8040 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
8041 vs->validated_until,
8042 GNUNET_TIME_relative_multiply (vs->validation_rtt,
8043 VALIDATION_RTT_BUFFER_FACTOR));
8044 vs->last_challenge_use =
8045 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
8046 update_next_challenge_time (vs, vs->first_challenge_use);
8047 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8048 "Validation response %s accepted, address valid until %s\n",
8049 GNUNET_sh2s (&tvr->challenge.value),
8050 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
8051 vs->sc = GNUNET_PEERSTORE_store (peerstore,
8052 "transport",
8053 &cmc->im.sender,
8054 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8055 vs->address,
8056 strlen (vs->address) + 1,
8057 vs->valid_until,
8058 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
8059 &peerstore_store_validation_cb,
8060 vs);
8061 finish_cmc_handling (cmc);
8062
8063 /* Finally, we now possibly have a confirmed (!) working queue,
8064 update queue status (if queue still is around) */
8065 q = find_queue (&vs->pid, vs->address);
8066 if (NULL == q)
8067 {
8068 GNUNET_STATISTICS_update (GST_stats,
8069 "# Queues lost at time of successful validation",
8070 1,
8071 GNUNET_NO);
8072 return;
8073 }
8074 q->validated_until = vs->validated_until;
8075 q->pd.aged_rtt = vs->validation_rtt;
8076 n = q->neighbour;
8077 vl = lookup_virtual_link (&vs->pid);
8078 if (NULL != vl)
8079 {
8080 /* Link was already up, remember n is also now available and we are done */
8081 if (NULL == vl->n)
8082 {
8083 vl->n = n;
8084 n->vl = vl;
8085 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8086 "Virtual link to %s could now also direct neighbour!\n",
8087 GNUNET_i2s (&vs->pid));
8088 }
8089 else
8090 {
8091 GNUNET_assert (n == vl->n);
8092 }
8093 return;
8094 }
8095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8096 "Creating new virtual link to %s using direct neighbour!\n",
8097 GNUNET_i2s (&vs->pid));
8098 vl = GNUNET_new (struct VirtualLink);
8099 vl->target = n->pid;
8100 vl->n = n;
8101 n->vl = vl;
8102 q->idle = GNUNET_YES;
8103 vl->core_recv_window = RECV_WINDOW_SIZE;
8104 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8105 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
8106 vl->visibility_task =
8107 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8108 GNUNET_break (GNUNET_YES ==
8109 GNUNET_CONTAINER_multipeermap_put (
8110 links,
8111 &vl->target,
8112 vl,
8113 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8114 consider_sending_fc (vl);
8115 /* We lacked a confirmed connection to the target
8116 before, so tell CORE about it (finally!) */
8117 cores_send_connect_info (&n->pid);
8118}
8119
8120
8121/**
8122 * Incoming meessage. Process the request.
8123 *
8124 * @param im the send message that was received
8125 */
8126static void
8127handle_incoming_msg (void *cls,
8128 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8129{
8130 struct TransportClient *tc = cls;
8131 struct CommunicatorMessageContext *cmc =
8132 GNUNET_new (struct CommunicatorMessageContext);
8133
8134 cmc->tc = tc;
8135 cmc->im = *im;
8136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8137 "Received message via communicator from peer %s\n",
8138 GNUNET_i2s (&im->sender));
8139 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
8140}
8141
8142
8143/**
8144 * Communicator gave us a transport address validation response. Process the
8145 * request.
8146 *
8147 * @param cls a `struct CommunicatorMessageContext` (must call
8148 * #finish_cmc_handling() when done)
8149 * @param fc the message that was received
8150 */
8151static void
8152handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
8153{
8154 struct CommunicatorMessageContext *cmc = cls;
8155 struct VirtualLink *vl;
8156 uint32_t seq;
8157 struct GNUNET_TIME_Absolute st;
8158 uint64_t os;
8159 uint64_t wnd;
8160
8161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8162 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
8163 vl = lookup_virtual_link (&cmc->im.sender);
8164 if (NULL == vl)
8165 {
8166 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8167 "FC dropped: VL unknown\n");
8168 GNUNET_STATISTICS_update (GST_stats,
8169 "# FC dropped: Virtual link unknown",
8170 1,
8171 GNUNET_NO);
8172 finish_cmc_handling (cmc);
8173 return;
8174 }
8175 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
8176 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
8177 {
8178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8179 "FC dropped: Message out of order\n");
8180 /* out of order, drop */
8181 GNUNET_STATISTICS_update (GST_stats,
8182 "# FC dropped: message out of order",
8183 1,
8184 GNUNET_NO);
8185 finish_cmc_handling (cmc);
8186 return;
8187 }
8188 seq = ntohl (fc->seq);
8189 if (seq < vl->last_fc_seq)
8190 {
8191 /* Wrap-around/reset of other peer; start all counters from zero */
8192 vl->outbound_fc_window_size_used = 0;
8193 }
8194 vl->last_fc_seq = seq;
8195 vl->last_fc_timestamp = st;
8196 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
8197 os = GNUNET_ntohll (fc->outbound_sent);
8198 vl->incoming_fc_window_size_loss =
8199 (int64_t) (os - vl->incoming_fc_window_size_used);
8200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8201 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
8202 GNUNET_i2s (&vl->target),
8203 (unsigned int) seq,
8204 (unsigned long long) vl->outbound_fc_window_size,
8205 (long long) vl->incoming_fc_window_size_loss);
8206 wnd = GNUNET_ntohll (fc->outbound_window_size);
8207 if ((wnd < vl->incoming_fc_window_size) ||
8208 (vl->last_outbound_window_size_received != wnd) ||
8209 (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX)
8210 % FC_NO_CHANGE_REPLY_PROBABILITY))
8211 {
8212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8213 "Consider re-sending our FC message, as clearly the other peer's idea of the window is not up-to-date (%llu vs %llu)\n",
8214 (unsigned long long) wnd,
8215 (unsigned long long) vl->incoming_fc_window_size);
8216 consider_sending_fc (vl);
8217 }
8218 if ((wnd == vl->incoming_fc_window_size) &&
8219 (vl->last_outbound_window_size_received == wnd) &&
8220 (NULL != vl->fc_retransmit_task))
8221 {
8222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8223 "Stopping FC retransmission to %s: peer is current at window %llu\n",
8224 GNUNET_i2s (&vl->target),
8225 (unsigned long long) wnd);
8226 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
8227 vl->fc_retransmit_task = NULL;
8228 }
8229 vl->last_outbound_window_size_received = wnd;
8230 /* FC window likely increased, check transmission possibilities! */
8231 check_vl_transmission (vl);
8232 finish_cmc_handling (cmc);
8233}
8234
8235
8236/**
8237 * Given an inbound message @a msg from a communicator @a cmc,
8238 * demultiplex it based on the type calling the right handler.
8239 *
8240 * @param cmc context for demultiplexing
8241 * @param msg message to demultiplex
8242 */
8243static void
8244demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
8245 const struct GNUNET_MessageHeader *msg)
8246{
8247 struct GNUNET_MQ_MessageHandler handlers[] =
8248 { GNUNET_MQ_hd_var_size (fragment_box,
8249 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
8250 struct TransportFragmentBoxMessage,
8251 cmc),
8252 GNUNET_MQ_hd_var_size (reliability_box,
8253 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
8254 struct TransportReliabilityBoxMessage,
8255 cmc),
8256 GNUNET_MQ_hd_var_size (reliability_ack,
8257 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
8258 struct TransportReliabilityAckMessage,
8259 cmc),
8260 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
8261 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
8262 struct TransportBackchannelEncapsulationMessage,
8263 cmc),
8264 GNUNET_MQ_hd_var_size (dv_learn,
8265 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
8266 struct TransportDVLearnMessage,
8267 cmc),
8268 GNUNET_MQ_hd_var_size (dv_box,
8269 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
8270 struct TransportDVBoxMessage,
8271 cmc),
8272 GNUNET_MQ_hd_fixed_size (
8273 validation_challenge,
8274 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
8275 struct TransportValidationChallengeMessage,
8276 cmc),
8277 GNUNET_MQ_hd_fixed_size (flow_control,
8278 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
8279 struct TransportFlowControlMessage,
8280 cmc),
8281 GNUNET_MQ_hd_fixed_size (
8282 validation_response,
8283 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
8284 struct TransportValidationResponseMessage,
8285 cmc),
8286 GNUNET_MQ_handler_end () };
8287 int ret;
8288
8289 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8290 "Handling message of type %u with %u bytes\n",
8291 (unsigned int) ntohs (msg->type),
8292 (unsigned int) ntohs (msg->size));
8293 ret = GNUNET_MQ_handle_message (handlers, msg);
8294 if (GNUNET_SYSERR == ret)
8295 {
8296 GNUNET_break (0);
8297 GNUNET_SERVICE_client_drop (cmc->tc->client);
8298 GNUNET_free (cmc);
8299 return;
8300 }
8301 if (GNUNET_NO == ret)
8302 {
8303 /* unencapsulated 'raw' message */
8304 handle_raw_message (cmc, msg);
8305 }
8306}
8307
8308
8309/**
8310 * New queue became available. Check message.
8311 *
8312 * @param cls the client
8313 * @param aqm the send message that was sent
8314 */
8315static int
8316check_add_queue_message (void *cls,
8317 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8318{
8319 struct TransportClient *tc = cls;
8320
8321 if (CT_COMMUNICATOR != tc->type)
8322 {
8323 GNUNET_break (0);
8324 return GNUNET_SYSERR;
8325 }
8326 GNUNET_MQ_check_zero_termination (aqm);
8327 return GNUNET_OK;
8328}
8329
8330
8331/**
8332 * If necessary, generates the UUID for a @a pm
8333 *
8334 * @param pm pending message to generate UUID for.
8335 */
8336static void
8337set_pending_message_uuid (struct PendingMessage *pm)
8338{
8339 if (pm->msg_uuid_set)
8340 return;
8341 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
8342 pm->msg_uuid_set = GNUNET_YES;
8343}
8344
8345
8346/**
8347 * Setup data structure waiting for acknowledgements.
8348 *
8349 * @param queue queue the @a pm will be sent over
8350 * @param dvh path the message will take, may be NULL
8351 * @param pm the pending message for transmission
8352 * @return corresponding fresh pending acknowledgement
8353 */
8354static struct PendingAcknowledgement *
8355prepare_pending_acknowledgement (struct Queue *queue,
8356 struct DistanceVectorHop *dvh,
8357 struct PendingMessage *pm)
8358{
8359 struct PendingAcknowledgement *pa;
8360
8361 pa = GNUNET_new (struct PendingAcknowledgement);
8362 pa->queue = queue;
8363 pa->dvh = dvh;
8364 pa->pm = pm;
8365 do
8366 {
8367 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8368 &pa->ack_uuid,
8369 sizeof(pa->ack_uuid));
8370 }
8371 while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
8372 pending_acks,
8373 &pa->ack_uuid.value,
8374 pa,
8375 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8376 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
8377 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
8378 if (NULL != dvh)
8379 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
8380 pa->transmission_time = GNUNET_TIME_absolute_get ();
8381 pa->message_size = pm->bytes_msg;
8382 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8383 "Waiting for ACKnowledgment `%s' for <%llu>\n",
8384 GNUNET_uuid2s (&pa->ack_uuid.value),
8385 pm->logging_uuid);
8386 return pa;
8387}
8388
8389
8390/**
8391 * Fragment the given @a pm to the given @a mtu. Adds
8392 * additional fragments to the neighbour as well. If the
8393 * @a mtu is too small, generates and error for the @a pm
8394 * and returns NULL.
8395 *
8396 * @param queue which queue to fragment for
8397 * @param dvh path the message will take, or NULL
8398 * @param pm pending message to fragment for transmission
8399 * @return new message to transmit
8400 */
8401static struct PendingMessage *
8402fragment_message (struct Queue *queue,
8403 struct DistanceVectorHop *dvh,
8404 struct PendingMessage *pm)
8405{
8406 struct PendingAcknowledgement *pa;
8407 struct PendingMessage *ff;
8408 uint16_t mtu;
8409
8410 mtu = (0 == queue->mtu)
8411 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
8412 : queue->mtu;
8413 set_pending_message_uuid (pm);
8414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8415 "Fragmenting message %llu <%llu> to %s for MTU %u\n",
8416 (unsigned long long) pm->msg_uuid.uuid,
8417 pm->logging_uuid,
8418 GNUNET_i2s (&pm->vl->target),
8419 (unsigned int) mtu);
8420 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8421
8422 /* This invariant is established in #handle_add_queue_message() */
8423 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
8424
8425 /* select fragment for transmission, descending the tree if it has
8426 been expanded until we are at a leaf or at a fragment that is small
8427 enough
8428 */
8429 ff = pm;
8430 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
8431 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
8432 {
8433 ff = ff->head_frag; /* descent into fragmented fragments */
8434 }
8435
8436 if (((ff->bytes_msg > mtu) || (pm == ff)) && (pm->frag_off < pm->bytes_msg))
8437 {
8438 /* Did not yet calculate all fragments, calculate next fragment */
8439 struct PendingMessage *frag;
8440 struct TransportFragmentBoxMessage tfb;
8441 const char *orig;
8442 char *msg;
8443 uint16_t fragmax;
8444 uint16_t fragsize;
8445 uint16_t msize;
8446 uint16_t xoff = 0;
8447
8448 orig = (const char *) &ff[1];
8449 msize = ff->bytes_msg;
8450 if (pm != ff)
8451 {
8452 const struct TransportFragmentBoxMessage *tfbo;
8453
8454 tfbo = (const struct TransportFragmentBoxMessage *) orig;
8455 orig += sizeof(struct TransportFragmentBoxMessage);
8456 msize -= sizeof(struct TransportFragmentBoxMessage);
8457 xoff = ntohs (tfbo->frag_off);
8458 }
8459 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
8460 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
8461 frag =
8462 GNUNET_malloc (sizeof(struct PendingMessage)
8463 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
8464 frag->logging_uuid = logging_uuid_gen++;
8465 frag->vl = pm->vl;
8466 frag->frag_parent = ff;
8467 frag->timeout = pm->timeout;
8468 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
8469 frag->pmt = PMT_FRAGMENT_BOX;
8470 msg = (char *) &frag[1];
8471 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
8472 tfb.header.size =
8473 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
8474 tfb.ack_uuid = pa->ack_uuid;
8475 tfb.msg_uuid = pm->msg_uuid;
8476 tfb.frag_off = htons (ff->frag_off + xoff);
8477 tfb.msg_size = htons (pm->bytes_msg);
8478 memcpy (msg, &tfb, sizeof(tfb));
8479 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
8480 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag, ff->tail_frag, frag);
8481 ff->frag_off += fragsize;
8482 ff = frag;
8483 }
8484
8485 /* Move head to the tail and return it */
8486 GNUNET_CONTAINER_MDLL_remove (frag,
8487 ff->frag_parent->head_frag,
8488 ff->frag_parent->tail_frag,
8489 ff);
8490 GNUNET_CONTAINER_MDLL_insert_tail (frag,
8491 ff->frag_parent->head_frag,
8492 ff->frag_parent->tail_frag,
8493 ff);
8494 return ff;
8495}
8496
8497
8498/**
8499 * Reliability-box the given @a pm. On error (can there be any), NULL
8500 * may be returned, otherwise the "replacement" for @a pm (which
8501 * should then be added to the respective neighbour's queue instead of
8502 * @a pm). If the @a pm is already fragmented or reliability boxed,
8503 * or itself an ACK, this function simply returns @a pm.
8504 *
8505 * @param queue which queue to prepare transmission for
8506 * @param dvh path the message will take, or NULL
8507 * @param pm pending message to box for transmission over unreliabile queue
8508 * @return new message to transmit
8509 */
8510static struct PendingMessage *
8511reliability_box_message (struct Queue *queue,
8512 struct DistanceVectorHop *dvh,
8513 struct PendingMessage *pm)
8514{
8515 struct TransportReliabilityBoxMessage rbox;
8516 struct PendingAcknowledgement *pa;
8517 struct PendingMessage *bpm;
8518 char *msg;
8519
8520 if (PMT_CORE != pm->pmt)
8521 return pm; /* already fragmented or reliability boxed, or control message:
8522 do nothing */
8523 if (NULL != pm->bpm)
8524 return pm->bpm; /* already computed earlier: do nothing */
8525 GNUNET_assert (NULL == pm->head_frag);
8526 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
8527 {
8528 /* failed hard */
8529 GNUNET_break (0);
8530 client_send_response (pm);
8531 return NULL;
8532 }
8533 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8534 "Preparing reliability box for message <%llu> to %s on queue %s\n",
8535 pm->logging_uuid,
8536 GNUNET_i2s (&pm->vl->target),
8537 queue->address);
8538 pa = prepare_pending_acknowledgement (queue, dvh, pm);
8539
8540 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
8541 + pm->bytes_msg);
8542 bpm->logging_uuid = logging_uuid_gen++;
8543 bpm->vl = pm->vl;
8544 bpm->frag_parent = pm;
8545 GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
8546 bpm->timeout = pm->timeout;
8547 bpm->pmt = PMT_RELIABILITY_BOX;
8548 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
8549 set_pending_message_uuid (bpm);
8550 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
8551 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
8552 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
8553
8554 rbox.ack_uuid = pa->ack_uuid;
8555 msg = (char *) &bpm[1];
8556 memcpy (msg, &rbox, sizeof(rbox));
8557 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
8558 pm->bpm = bpm;
8559 return bpm;
8560}
8561
8562
8563/**
8564 * Change the value of the `next_attempt` field of @a pm
8565 * to @a next_attempt and re-order @a pm in the transmission
8566 * list as required by the new timestamp.
8567 *
8568 * @param pm a pending message to update
8569 * @param next_attempt timestamp to use
8570 */
8571static void
8572update_pm_next_attempt (struct PendingMessage *pm,
8573 struct GNUNET_TIME_Absolute next_attempt)
8574{
8575 struct VirtualLink *vl = pm->vl;
8576
8577 pm->next_attempt = next_attempt;
8578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8579 "Next attempt for message <%llu> set to %s\n",
8580 pm->logging_uuid,
8581 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
8582
8583 if (NULL == pm->frag_parent)
8584 {
8585 struct PendingMessage *pos;
8586
8587 /* re-insert sort in neighbour list */
8588 GNUNET_CONTAINER_MDLL_remove (vl,
8589 vl->pending_msg_head,
8590 vl->pending_msg_tail,
8591 pm);
8592 pos = vl->pending_msg_tail;
8593 while ((NULL != pos) &&
8594 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8595 pos = pos->prev_vl;
8596 GNUNET_CONTAINER_MDLL_insert_after (vl,
8597 vl->pending_msg_head,
8598 vl->pending_msg_tail,
8599 pos,
8600 pm);
8601 }
8602 else
8603 {
8604 /* re-insert sort in fragment list */
8605 struct PendingMessage *fp = pm->frag_parent;
8606 struct PendingMessage *pos;
8607
8608 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
8609 pos = fp->tail_frag;
8610 while ((NULL != pos) &&
8611 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
8612 pos = pos->prev_frag;
8613 GNUNET_CONTAINER_MDLL_insert_after (frag,
8614 fp->head_frag,
8615 fp->tail_frag,
8616 pos,
8617 pm);
8618 }
8619}
8620
8621
8622/**
8623 * Context for #select_best_pending_from_link().
8624 */
8625struct PendingMessageScoreContext
8626{
8627 /**
8628 * Set to the best message that was found, NULL for none.
8629 */
8630 struct PendingMessage *best;
8631
8632 /**
8633 * DVH that @e best should take, or NULL for direct transmission.
8634 */
8635 struct DistanceVectorHop *dvh;
8636
8637 /**
8638 * What is the estimated total overhead for this message?
8639 */
8640 size_t real_overhead;
8641
8642 /**
8643 * Number of pending messages we seriously considered this time.
8644 */
8645 unsigned int consideration_counter;
8646
8647 /**
8648 * Did we have to fragment?
8649 */
8650 int frag;
8651
8652 /**
8653 * Did we have to reliability box?
8654 */
8655 int relb;
8656};
8657
8658
8659/**
8660 * Select the best pending message from @a vl for transmission
8661 * via @a queue.
8662 *
8663 * @param sc[in,out] best message so far (NULL for none), plus scoring data
8664 * @param queue the queue that will be used for transmission
8665 * @param vl the virtual link providing the messages
8666 * @param dvh path we are currently considering, or NULL for none
8667 * @param overhead number of bytes of overhead to be expected
8668 * from DV encapsulation (0 for without DV)
8669 */
8670static void
8671select_best_pending_from_link (struct PendingMessageScoreContext *sc,
8672 struct Queue *queue,
8673 struct VirtualLink *vl,
8674 struct DistanceVectorHop *dvh,
8675 size_t overhead)
8676{
8677 struct GNUNET_TIME_Absolute now;
8678
8679 now = GNUNET_TIME_absolute_get ();
8680 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
8681 pos = pos->next_vl)
8682 {
8683 size_t real_overhead = overhead;
8684 int frag;
8685 int relb;
8686
8687 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
8688 continue; /* DV messages must not be DV-routed to next hop! */
8689 if (pos->next_attempt.abs_value_us > now.abs_value_us)
8690 break; /* too early for all messages, they are sorted by next_attempt */
8691 if (NULL != pos->qe)
8692 continue; /* not eligible */
8693 sc->consideration_counter++;
8694 /* determine if we have to fragment, if so add fragmentation
8695 overhead! */
8696 frag = GNUNET_NO;
8697 if (((0 != queue->mtu) &&
8698 (pos->bytes_msg + real_overhead > queue->mtu)) ||
8699 (pos->bytes_msg > UINT16_MAX - sizeof(struct
8700 GNUNET_TRANSPORT_SendMessageTo))
8701 ||
8702 (NULL != pos->head_frag /* fragments already exist, should
8703 respect that even if MTU is 0 for
8704 this queue */))
8705 {
8706 frag = GNUNET_YES;
8707 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
8708 {
8709 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
8710 header without the ACK UUID when using a *reliable* channel! */
8711 }
8712 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
8713 }
8714 /* determine if we have to reliability-box, if so add reliability box
8715 overhead */
8716 relb = GNUNET_NO;
8717 if ((GNUNET_NO == frag) &&
8718 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
8719 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
8720 {
8721 relb = GNUNET_YES;
8722 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
8723 }
8724
8725 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
8726 message would beat it! */
8727 if (NULL != sc->best)
8728 {
8729 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
8730 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
8731 experimentally validated. There may be some huge potential for
8732 improvement here. Also, we right now only compare how well the
8733 given message fits _this_ queue, and do not consider how well other
8734 queues might suit the message. Taking other queues into consideration
8735 may further improve the result, but could also be expensive
8736 in terms of CPU time. */long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
8737 long long pm_score = frag * 40 + relb * 20 + real_overhead;
8738 long long time_delta =
8739 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
8740 / 1000LL;
8741
8742 /* "time_delta" considers which message has been 'ready' for transmission
8743 for longer, if a message has a preference for low latency, increase
8744 the weight of the time_delta by 10x if it is favorable for that message */
8745 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8746 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
8747 time_delta *= 10; /* increase weight (always, both are low latency) */
8748 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8749 (time_delta > 0))
8750 time_delta *=
8751 10; /* increase weight, favors 'pos', which is low latency */
8752 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
8753 (time_delta < 0))
8754 time_delta *=
8755 10; /* increase weight, favors 'sc->best', which is low latency */
8756 if (0 != queue->mtu)
8757 {
8758 /* Grant bonus if we are below MTU, larger bonus the closer we will
8759 be to the MTU */
8760 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
8761 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
8762 if (queue->mtu > real_overhead + pos->bytes_msg)
8763 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
8764 }
8765 if (sc_score + time_delta > pm_score)
8766 continue; /* sc_score larger, keep sc->best */
8767 }
8768 sc->best = pos;
8769 sc->dvh = dvh;
8770 sc->frag = frag;
8771 sc->relb = relb;
8772 }
8773}
8774
8775
8776/**
8777 * Function to call to further operate on the now DV encapsulated
8778 * message @a hdr, forwarding it via @a next_hop under respect of
8779 * @a options.
8780 *
8781 * @param cls a `struct PendingMessageScoreContext`
8782 * @param next_hop next hop of the DV path
8783 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
8784 * @param options options of the original message
8785 */
8786static void
8787extract_box_cb (void *cls,
8788 struct Neighbour *next_hop,
8789 const struct GNUNET_MessageHeader *hdr,
8790 enum RouteMessageOptions options)
8791{
8792 struct PendingMessageScoreContext *sc = cls;
8793 struct PendingMessage *pm = sc->best;
8794 struct PendingMessage *bpm;
8795 uint16_t bsize = ntohs (hdr->size);
8796
8797 GNUNET_assert (NULL == pm->bpm);
8798 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
8799 bpm->logging_uuid = logging_uuid_gen++;
8800 bpm->pmt = PMT_DV_BOX;
8801 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8802 "Creating DV Box %llu for original message %llu (next hop is %s)\n",
8803 bpm->logging_uuid,
8804 pm->logging_uuid,
8805 GNUNET_i2s (&next_hop->pid));
8806 memcpy (&bpm[1], hdr, bsize);
8807 pm->bpm = bpm;
8808}
8809
8810
8811/**
8812 * We believe we are ready to transmit a `struct PendingMessage` on a
8813 * queue, the big question is which one! We need to see if there is
8814 * one pending that is allowed by flow control and congestion control
8815 * and (ideally) matches our queue's performance profile.
8816 *
8817 * If such a message is found, we give the message to the communicator
8818 * for transmission (updating the tracker, and re-scheduling ourselves
8819 * if applicable).
8820 *
8821 * If no such message is found, the queue's `idle` field must be set
8822 * to #GNUNET_YES.
8823 *
8824 * @param cls the `struct Queue` to process transmissions for
8825 */
8826static void
8827transmit_on_queue (void *cls)
8828{
8829 struct Queue *queue = cls;
8830 struct Neighbour *n = queue->neighbour;
8831 struct PendingMessageScoreContext sc;
8832 struct PendingMessage *pm;
8833
8834 queue->transmit_task = NULL;
8835 if (NULL == n->vl)
8836 {
8837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8838 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
8839 GNUNET_i2s (&n->pid),
8840 queue->address);
8841 queue->idle = GNUNET_YES;
8842 return;
8843 }
8844 memset (&sc, 0, sizeof(sc));
8845 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
8846 if (NULL == sc.best)
8847 {
8848 /* Also look at DVH that have the n as first hop! */
8849 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
8850 dvh = dvh->next_neighbour)
8851 {
8852 select_best_pending_from_link (&sc,
8853 queue,
8854 dvh->dv->vl,
8855 dvh,
8856 sizeof(struct GNUNET_PeerIdentity)
8857 * (1 + dvh->distance)
8858 + sizeof(struct TransportDVBoxMessage)
8859 + sizeof(struct TransportDVBoxPayloadP));
8860 }
8861 }
8862 if (NULL == sc.best)
8863 {
8864 /* no message pending, nothing to do here! */
8865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8866 "No pending messages, queue `%s' to %s now idle\n",
8867 queue->address,
8868 GNUNET_i2s (&n->pid));
8869 queue->idle = GNUNET_YES;
8870 return;
8871 }
8872 /* There is a message pending, we are certainly not idle */
8873 queue->idle = GNUNET_NO;
8874
8875 /* Given selection in `sc`, do transmission */
8876 pm = sc.best;
8877 if (NULL != sc.dvh)
8878 {
8879 GNUNET_assert (PMT_DV_BOX != pm->pmt);
8880 if (NULL != sc.best->bpm)
8881 {
8882 /* We did this boxing before, but possibly for a different path!
8883 Discard old DV box! OPTIMIZE-ME: we might want to check if
8884 it is the same and then not re-build the message... */
8885 free_pending_message (sc.best->bpm);
8886 sc.best->bpm = NULL;
8887 }
8888 encapsulate_for_dv (sc.dvh->dv,
8889 1,
8890 &sc.dvh,
8891 (const struct GNUNET_MessageHeader *) &sc.best[1],
8892 &extract_box_cb,
8893 &sc,
8894 RMO_NONE);
8895 GNUNET_assert (NULL != sc.best->bpm);
8896 pm = sc.best->bpm;
8897 }
8898 if (GNUNET_YES == sc.frag)
8899 {
8900 pm = fragment_message (queue, sc.dvh, pm);
8901 if (NULL == pm)
8902 {
8903 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8904 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
8905 queue->address,
8906 GNUNET_i2s (&n->pid),
8907 sc.best->logging_uuid);
8908 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8909 return;
8910 }
8911 }
8912 else if (GNUNET_YES == sc.relb)
8913 {
8914 pm = reliability_box_message (queue, sc.dvh, pm);
8915 if (NULL == pm)
8916 {
8917 /* Reliability boxing failed, try next message... */
8918 GNUNET_log (
8919 GNUNET_ERROR_TYPE_DEBUG,
8920 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
8921 queue->address,
8922 GNUNET_i2s (&n->pid),
8923 sc.best->logging_uuid);
8924 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8925 return;
8926 }
8927 }
8928
8929 /* Pass 'pm' for transission to the communicator */
8930 GNUNET_log (
8931 GNUNET_ERROR_TYPE_DEBUG,
8932 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
8933 pm->logging_uuid,
8934 queue->address,
8935 GNUNET_i2s (&n->pid),
8936 sc.consideration_counter);
8937
8938 /* Flow control: increment amount of traffic sent; if we are routing
8939 via DV (and thus the ultimate target of the pending message is for
8940 a different virtual link than the one of the queue), then we need
8941 to use up not only the window of the direct link but also the
8942 flow control window for the DV link! */
8943 pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
8944
8945 if (pm->vl != queue->neighbour->vl)
8946 {
8947 /* If the virtual link of the queue differs, this better be distance
8948 vector routing! */
8949 GNUNET_assert (NULL != sc.dvh);
8950 /* If we do distance vector routing, we better not do this for a
8951 message that was itself DV-routed */
8952 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
8953 /* We use the size of the unboxed message here, to avoid counting
8954 the DV-Box header which is eaten up on the way by intermediaries */
8955 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
8956 }
8957 else
8958 {
8959 GNUNET_assert (NULL == sc.dvh);
8960 }
8961
8962 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
8963
8964 /* Check if this transmission somehow conclusively finished handing 'pm'
8965 even without any explicit ACKs */
8966 if ((PMT_CORE == pm->pmt) ||
8967 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
8968 {
8969 completed_pending_message (pm);
8970 }
8971 else
8972 {
8973 /* Message not finished, waiting for acknowledgement.
8974 Update time by which we might retransmit 's' based on queue
8975 characteristics (i.e. RTT); it takes one RTT for the message to
8976 arrive and the ACK to come back in the best case; but the other
8977 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
8978 retransmitting.
8979
8980 OPTIMIZE: Note that in the future this heuristic should likely
8981 be improved further (measure RTT stability, consider message
8982 urgency and size when delaying ACKs, etc.) */
8983 update_pm_next_attempt (pm,
8984 GNUNET_TIME_relative_to_absolute (
8985 GNUNET_TIME_relative_multiply (queue->pd.aged_rtt,
8986 4)));
8987 }
8988 /* finally, re-schedule queue transmission task itself */
8989 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
8990}
8991
8992
8993/**
8994 * Queue to a peer went down. Process the request.
8995 *
8996 * @param cls the client
8997 * @param dqm the send message that was sent
8998 */
8999static void
9000handle_del_queue_message (void *cls,
9001 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
9002{
9003 struct TransportClient *tc = cls;
9004
9005 if (CT_COMMUNICATOR != tc->type)
9006 {
9007 GNUNET_break (0);
9008 GNUNET_SERVICE_client_drop (tc->client);
9009 return;
9010 }
9011 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
9012 queue = queue->next_client)
9013 {
9014 struct Neighbour *neighbour = queue->neighbour;
9015
9016 if ((dqm->qid != queue->qid) ||
9017 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
9018 continue;
9019 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9020 "Dropped queue %s to peer %s\n",
9021 queue->address,
9022 GNUNET_i2s (&neighbour->pid));
9023 free_queue (queue);
9024 GNUNET_SERVICE_client_continue (tc->client);
9025 return;
9026 }
9027 GNUNET_break (0);
9028 GNUNET_SERVICE_client_drop (tc->client);
9029}
9030
9031
9032/**
9033 * Message was transmitted. Process the request.
9034 *
9035 * @param cls the client
9036 * @param sma the send message that was sent
9037 */
9038static void
9039handle_send_message_ack (void *cls,
9040 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
9041{
9042 struct TransportClient *tc = cls;
9043 struct QueueEntry *qe;
9044 struct PendingMessage *pm;
9045
9046 if (CT_COMMUNICATOR != tc->type)
9047 {
9048 GNUNET_break (0);
9049 GNUNET_SERVICE_client_drop (tc->client);
9050 return;
9051 }
9052
9053 /* find our queue entry matching the ACK */
9054 qe = NULL;
9055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9056 "Looking for queue for PID %s\n",
9057 GNUNET_i2s (&sma->receiver));
9058 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
9059 queue = queue->next_client)
9060 {
9061 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
9062 continue;
9063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9064 "Found PID %s\n",
9065 GNUNET_i2s (&queue->neighbour->pid));
9066
9067
9068 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
9069 qep = qep->next)
9070 {
9071 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9072 "QueueEntry MID: %llu, Ack MID: %llu\n",
9073 (unsigned long long) qep->mid,
9074 (unsigned long long) sma->mid);
9075 if (qep->mid != sma->mid)
9076 continue;
9077 qe = qep;
9078 break;
9079 }
9080 }
9081 if (NULL == qe)
9082 {
9083 /* this should never happen */
9084 GNUNET_break (0);
9085 GNUNET_SERVICE_client_drop (tc->client);
9086 return;
9087 }
9088 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
9089 qe->queue->queue_tail,
9090 qe);
9091 qe->queue->queue_length--;
9092 tc->details.communicator.total_queue_length--;
9093 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9094 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
9095 qe->queue->address,
9096 GNUNET_i2s (&qe->queue->neighbour->pid),
9097 qe->queue->queue_length,
9098 tc->details.communicator.total_queue_length);
9099 GNUNET_SERVICE_client_continue (tc->client);
9100
9101 /* if applicable, resume transmissions that waited on ACK */
9102 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
9103 tc->details.communicator.total_queue_length)
9104 {
9105 /* Communicator dropped below threshold, resume all queues
9106 incident with this client! */
9107 GNUNET_STATISTICS_update (
9108 GST_stats,
9109 "# Transmission throttled due to communicator queue limit",
9110 -1,
9111 GNUNET_NO);
9112 for (struct Queue *queue = tc->details.communicator.queue_head;
9113 NULL != queue;
9114 queue = queue->next_client)
9115 {
9116 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9117 }
9118 }
9119 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
9120 {
9121 /* queue dropped below threshold; only resume this one queue */
9122 GNUNET_STATISTICS_update (GST_stats,
9123 "# Transmission throttled due to queue queue limit",
9124 -1,
9125 GNUNET_NO);
9126 schedule_transmit_on_queue (qe->queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9127 }
9128
9129 if (NULL != (pm = qe->pm))
9130 {
9131 struct VirtualLink *vl;
9132
9133 GNUNET_assert (qe == pm->qe);
9134 pm->qe = NULL;
9135 /* If waiting for this communicator may have blocked transmission
9136 of pm on other queues for this neighbour, force schedule
9137 transmit on queue for queues of the neighbour */
9138 vl = pm->vl;
9139 if (vl->pending_msg_head == pm)
9140 check_vl_transmission (vl);
9141 }
9142 GNUNET_free (qe);
9143}
9144
9145
9146/**
9147 * Iterator telling new MONITOR client about all existing
9148 * queues to peers.
9149 *
9150 * @param cls the new `struct TransportClient`
9151 * @param pid a connected peer
9152 * @param value the `struct Neighbour` with more information
9153 * @return #GNUNET_OK (continue to iterate)
9154 */
9155static int
9156notify_client_queues (void *cls,
9157 const struct GNUNET_PeerIdentity *pid,
9158 void *value)
9159{
9160 struct TransportClient *tc = cls;
9161 struct Neighbour *neighbour = value;
9162
9163 GNUNET_assert (CT_MONITOR == tc->type);
9164 for (struct Queue *q = neighbour->queue_head; NULL != q;
9165 q = q->next_neighbour)
9166 {
9167 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
9168 .cs = q->cs,
9169 .num_msg_pending = q->num_msg_pending,
9170 .num_bytes_pending = q->num_bytes_pending };
9171
9172 notify_monitor (tc, pid, q->address, q->nt, &me);
9173 }
9174 return GNUNET_OK;
9175}
9176
9177
9178/**
9179 * Initialize a monitor client.
9180 *
9181 * @param cls the client
9182 * @param start the start message that was sent
9183 */
9184static void
9185handle_monitor_start (void *cls,
9186 const struct GNUNET_TRANSPORT_MonitorStart *start)
9187{
9188 struct TransportClient *tc = cls;
9189
9190 if (CT_NONE != tc->type)
9191 {
9192 GNUNET_break (0);
9193 GNUNET_SERVICE_client_drop (tc->client);
9194 return;
9195 }
9196 tc->type = CT_MONITOR;
9197 tc->details.monitor.peer = start->peer;
9198 tc->details.monitor.one_shot = ntohl (start->one_shot);
9199 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &notify_client_queues, tc);
9200 GNUNET_SERVICE_client_mark_monitor (tc->client);
9201 GNUNET_SERVICE_client_continue (tc->client);
9202}
9203
9204
9205/**
9206 * Find transport client providing communication service
9207 * for the protocol @a prefix.
9208 *
9209 * @param prefix communicator name
9210 * @return NULL if no such transport client is available
9211 */
9212static struct TransportClient *
9213lookup_communicator (const char *prefix)
9214{
9215 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
9216 {
9217 if (CT_COMMUNICATOR != tc->type)
9218 continue;
9219 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
9220 return tc;
9221 }
9222 GNUNET_log (
9223 GNUNET_ERROR_TYPE_WARNING,
9224 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
9225 prefix);
9226 return NULL;
9227}
9228
9229
9230/**
9231 * Signature of a function called with a communicator @a address of a peer
9232 * @a pid that an application wants us to connect to.
9233 *
9234 * @param pid target peer
9235 * @param address the address to try
9236 */
9237static void
9238suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
9239{
9240 static uint32_t idgen;
9241 struct TransportClient *tc;
9242 char *prefix;
9243 struct GNUNET_TRANSPORT_CreateQueue *cqm;
9244 struct GNUNET_MQ_Envelope *env;
9245 size_t alen;
9246
9247 prefix = GNUNET_HELLO_address_to_prefix (address);
9248 if (NULL == prefix)
9249 {
9250 GNUNET_break (0); /* We got an invalid address!? */
9251 return;
9252 }
9253 tc = lookup_communicator (prefix);
9254 if (NULL == tc)
9255 {
9256 GNUNET_STATISTICS_update (GST_stats,
9257 "# Suggestions ignored due to missing communicator",
9258 1,
9259 GNUNET_NO);
9260 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9261 "Cannot connect to %s at `%s', no matching communicator present\n",
9262 GNUNET_i2s (pid),
9263 address);
9264 GNUNET_free (prefix);
9265 return;
9266 }
9267 /* forward suggestion for queue creation to communicator */
9268 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9269 "Request #%u for `%s' communicator to create queue to `%s'\n",
9270 (unsigned int) idgen,
9271 prefix,
9272 address);
9273 GNUNET_free (prefix);
9274 alen = strlen (address) + 1;
9275 env =
9276 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
9277 cqm->request_id = htonl (idgen++);
9278 cqm->receiver = *pid;
9279 memcpy (&cqm[1], address, alen);
9280 GNUNET_MQ_send (tc->mq, env);
9281}
9282
9283
9284/**
9285 * The queue @a q (which matches the peer and address in @a vs) is
9286 * ready for queueing. We should now queue the validation request.
9287 *
9288 * @param q queue to send on
9289 * @param vs state to derive validation challenge from
9290 */
9291static void
9292validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
9293{
9294 struct TransportValidationChallengeMessage tvc;
9295
9296 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
9297 tvc.header.type =
9298 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
9299 tvc.header.size = htons (sizeof(tvc));
9300 tvc.reserved = htonl (0);
9301 tvc.challenge = vs->challenge;
9302 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
9303 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9304 "Sending address validation challenge %s to %s\n",
9305 GNUNET_sh2s (&tvc.challenge.value),
9306 GNUNET_i2s (&q->neighbour->pid));
9307 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
9308}
9309
9310
9311/**
9312 * Task run periodically to validate some address based on #validation_heap.
9313 *
9314 * @param cls NULL
9315 */
9316static void
9317validation_start_cb (void *cls)
9318{
9319 struct ValidationState *vs;
9320 struct Queue *q;
9321
9322 (void) cls;
9323 validation_task = NULL;
9324 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9325 /* drop validations past their expiration */
9326 while (
9327 (NULL != vs) &&
9328 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
9329 {
9330 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9331 "Validation response %s cleaned up\n",
9332 GNUNET_sh2s (&vs->challenge.value));
9333 free_validation_state (vs);
9334 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
9335 }
9336 if (NULL == vs)
9337 {
9338 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
9339 "Address validation task not scheduled anymore, nothing to do\n");
9340 return; /* woopsie, no more addresses known, should only
9341 happen if we're really a lonely peer */
9342 }
9343 q = find_queue (&vs->pid, vs->address);
9344 if (NULL == q)
9345 {
9346 vs->awaiting_queue = GNUNET_YES;
9347 suggest_to_connect (&vs->pid, vs->address);
9348 }
9349 else
9350 validation_transmit_on_queue (q, vs);
9351 /* Finally, reschedule next attempt */
9352 vs->challenge_backoff =
9353 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
9354 MAX_VALIDATION_CHALLENGE_FREQ);
9355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9356 "Address validation task will run again in %s\n",
9357 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
9358 GNUNET_YES));
9359 update_next_challenge_time (vs,
9360 GNUNET_TIME_relative_to_absolute (
9361 vs->challenge_backoff));
9362}
9363
9364
9365/**
9366 * Closure for #check_connection_quality.
9367 */
9368struct QueueQualityContext
9369{
9370 /**
9371 * Set to the @e k'th queue encountered.
9372 */
9373 struct Queue *q;
9374
9375 /**
9376 * Set to the number of quality queues encountered.
9377 */
9378 unsigned int quality_count;
9379
9380 /**
9381 * Set to the total number of queues encountered.
9382 */
9383 unsigned int num_queues;
9384
9385 /**
9386 * Decremented for each queue, for selection of the
9387 * k-th queue in @e q.
9388 */
9389 unsigned int k;
9390};
9391
9392
9393/**
9394 * Check whether any queue to the given neighbour is
9395 * of a good "quality" and if so, increment the counter.
9396 * Also counts the total number of queues, and returns
9397 * the k-th queue found.
9398 *
9399 * @param cls a `struct QueueQualityContext *` with counters
9400 * @param pid peer this is about
9401 * @param value a `struct Neighbour`
9402 * @return #GNUNET_OK (continue to iterate)
9403 */
9404static int
9405check_connection_quality (void *cls,
9406 const struct GNUNET_PeerIdentity *pid,
9407 void *value)
9408{
9409 struct QueueQualityContext *ctx = cls;
9410 struct Neighbour *n = value;
9411 int do_inc;
9412
9413 (void) pid;
9414 do_inc = GNUNET_NO;
9415 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
9416 {
9417 ctx->num_queues++;
9418 if (0 == ctx->k--)
9419 ctx->q = q;
9420 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
9421 statistics and consider those as well here? */
9422 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
9423 do_inc = GNUNET_YES;
9424 }
9425 if (GNUNET_YES == do_inc)
9426 ctx->quality_count++;
9427 return GNUNET_OK;
9428}
9429
9430
9431/**
9432 * Task run when we CONSIDER initiating a DV learn
9433 * process. We first check that sending out a message is
9434 * even possible (queues exist), then that it is desirable
9435 * (if not, reschedule the task for later), and finally
9436 * we may then begin the job. If there are too many
9437 * entries in the #dvlearn_map, we purge the oldest entry
9438 * using #lle_tail.
9439 *
9440 * @param cls NULL
9441 */
9442static void
9443start_dv_learn (void *cls)
9444{
9445 struct LearnLaunchEntry *lle;
9446 struct QueueQualityContext qqc;
9447 struct TransportDVLearnMessage dvl;
9448
9449 (void) cls;
9450 dvlearn_task = NULL;
9451 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
9452 return; /* lost all connectivity, cannot do learning */
9453 qqc.quality_count = 0;
9454 qqc.num_queues = 0;
9455 qqc.k = GNUNET_CONTAINER_multipeermap_size (neighbours);
9456 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9457 &check_connection_quality,
9458 &qqc);
9459 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
9460 {
9461 struct GNUNET_TIME_Relative delay;
9462 unsigned int factor;
9463
9464 /* scale our retries by how far we are above the threshold */
9465 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
9466 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
9467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9468 "At connection quality %u, will launch DV learn in %s\n",
9469 qqc.quality_count,
9470 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
9471 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
9472 return;
9473 }
9474 /* remove old entries in #dvlearn_map if it has grown too big */
9475 while (MAX_DV_LEARN_PENDING <=
9476 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
9477 {
9478 lle = lle_tail;
9479 GNUNET_assert (GNUNET_YES ==
9480 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
9481 &lle->challenge.value,
9482 lle));
9483 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
9484 GNUNET_free (lle);
9485 }
9486 /* setup data structure for learning */
9487 lle = GNUNET_new (struct LearnLaunchEntry);
9488 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9489 &lle->challenge,
9490 sizeof(lle->challenge));
9491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9492 "Starting launch DV learn with challenge %s\n",
9493 GNUNET_sh2s (&lle->challenge.value));
9494 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
9495 GNUNET_break (GNUNET_YES ==
9496 GNUNET_CONTAINER_multishortmap_put (
9497 dvlearn_map,
9498 &lle->challenge.value,
9499 lle,
9500 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9501 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
9502 dvl.header.size = htons (sizeof(dvl));
9503 dvl.num_hops = htons (0);
9504 dvl.bidirectional = htons (0);
9505 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
9506 dvl.monotonic_time =
9507 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
9508 {
9509 struct DvInitPS dvip = {
9510 .purpose.purpose = htonl (
9511 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
9512 .purpose.size = htonl (sizeof(dvip)),
9513 .monotonic_time = dvl.monotonic_time,
9514 .challenge = lle->challenge
9515 };
9516
9517 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
9518 &dvip,
9519 &dvl.init_sig);
9520 }
9521 dvl.initiator = GST_my_identity;
9522 dvl.challenge = lle->challenge;
9523
9524 qqc.quality_count = 0;
9525 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
9526 qqc.num_queues = 0;
9527 qqc.q = NULL;
9528 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
9529 &check_connection_quality,
9530 &qqc);
9531 GNUNET_assert (NULL != qqc.q);
9532
9533 /* Do this as close to transmission time as possible! */
9534 lle->launch_time = GNUNET_TIME_absolute_get ();
9535
9536 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
9537 /* reschedule this job, randomizing the time it runs (but no
9538 actual backoff!) */
9539 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
9540 DV_LEARN_BASE_FREQUENCY),
9541 &start_dv_learn,
9542 NULL);
9543}
9544
9545
9546/**
9547 * A new queue has been created, check if any address validation
9548 * requests have been waiting for it.
9549 *
9550 * @param cls a `struct Queue`
9551 * @param pid peer concerned (unused)
9552 * @param value a `struct ValidationState`
9553 * @return #GNUNET_NO if a match was found and we can stop looking
9554 */
9555static int
9556check_validation_request_pending (void *cls,
9557 const struct GNUNET_PeerIdentity *pid,
9558 void *value)
9559{
9560 struct Queue *q = cls;
9561 struct ValidationState *vs = value;
9562
9563 (void) pid;
9564 if ((GNUNET_YES == vs->awaiting_queue) &&
9565 (0 == strcmp (vs->address, q->address)))
9566 {
9567 vs->awaiting_queue = GNUNET_NO;
9568 validation_transmit_on_queue (q, vs);
9569 return GNUNET_NO;
9570 }
9571 return GNUNET_OK;
9572}
9573
9574
9575/**
9576 * Function called with the monotonic time of a DV initiator
9577 * by PEERSTORE. Updates the time.
9578 *
9579 * @param cls a `struct Neighbour`
9580 * @param record the information found, NULL for the last call
9581 * @param emsg error message
9582 */
9583static void
9584neighbour_dv_monotime_cb (void *cls,
9585 const struct GNUNET_PEERSTORE_Record *record,
9586 const char *emsg)
9587{
9588 struct Neighbour *n = cls;
9589 struct GNUNET_TIME_AbsoluteNBO *mtbe;
9590
9591 (void) emsg;
9592 if (NULL == record)
9593 {
9594 /* we're done with #neighbour_dv_monotime_cb() invocations,
9595 continue normal processing */
9596 n->get = NULL;
9597 n->dv_monotime_available = GNUNET_YES;
9598 return;
9599 }
9600 if (sizeof(*mtbe) != record->value_size)
9601 {
9602 GNUNET_break (0);
9603 return;
9604 }
9605 mtbe = record->value;
9606 n->last_dv_learn_monotime =
9607 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
9608 GNUNET_TIME_absolute_ntoh (*mtbe));
9609}
9610
9611
9612/**
9613 * New queue became available. Process the request.
9614 *
9615 * @param cls the client
9616 * @param aqm the send message that was sent
9617 */
9618static void
9619handle_add_queue_message (void *cls,
9620 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
9621{
9622 struct TransportClient *tc = cls;
9623 struct Queue *queue;
9624 struct Neighbour *neighbour;
9625 const char *addr;
9626 uint16_t addr_len;
9627
9628 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
9629 {
9630 /* MTU so small as to be useless for transmissions,
9631 required for #fragment_message()! */
9632 GNUNET_break_op (0);
9633 GNUNET_SERVICE_client_drop (tc->client);
9634 return;
9635 }
9636 /* This may simply be a queue update */
9637 for (queue = tc->details.communicator.queue_head;
9638 NULL != queue;
9639 queue = queue->next_client)
9640 {
9641 if (queue->qid != aqm->qid)
9642 continue;
9643 break;
9644 }
9645
9646 if (NULL != queue)
9647 {
9648 neighbour = queue->neighbour;
9649 }
9650 else
9651 {
9652 neighbour = lookup_neighbour (&aqm->receiver);
9653 if (NULL == neighbour)
9654 {
9655 neighbour = GNUNET_new (struct Neighbour);
9656 neighbour->pid = aqm->receiver;
9657 GNUNET_assert (GNUNET_OK ==
9658 GNUNET_CONTAINER_multipeermap_put (
9659 neighbours,
9660 &neighbour->pid,
9661 neighbour,
9662 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9663 neighbour->get =
9664 GNUNET_PEERSTORE_iterate (peerstore,
9665 "transport",
9666 &neighbour->pid,
9667 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
9668 &neighbour_dv_monotime_cb,
9669 neighbour);
9670 }
9671 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
9672 addr = (const char *) &aqm[1];
9673 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9674 "New queue %s to %s available with QID %llu\n",
9675 addr,
9676 GNUNET_i2s (&aqm->receiver),
9677 (unsigned long long) aqm->qid);
9678 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
9679 queue->tc = tc;
9680 queue->address = (const char *) &queue[1];
9681 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
9682 queue->qid = aqm->qid;
9683 queue->neighbour = neighbour;
9684 memcpy (&queue[1], addr, addr_len);
9685 /* notify monitors about new queue */
9686 {
9687 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
9688
9689 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
9690 }
9691 GNUNET_CONTAINER_MDLL_insert (neighbour,
9692 neighbour->queue_head,
9693 neighbour->queue_tail,
9694 queue);
9695 GNUNET_CONTAINER_MDLL_insert (client,
9696 tc->details.communicator.queue_head,
9697 tc->details.communicator.queue_tail,
9698 queue);
9699
9700 }
9701 queue->mtu = ntohl (aqm->mtu);
9702 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
9703 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
9704 queue->idle = GNUNET_YES;
9705 /* check if valdiations are waiting for the queue */
9706 (void)
9707 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
9708 &aqm->receiver,
9709 &check_validation_request_pending,
9710 queue);
9711 /* look for traffic for this queue */
9712 schedule_transmit_on_queue (queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9713 /* might be our first queue, try launching DV learning */
9714 if (NULL == dvlearn_task)
9715 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
9716 GNUNET_SERVICE_client_continue (tc->client);
9717}
9718
9719
9720/**
9721 * @brief Handle updates to queues.
9722 *
9723 * @param cls the transport client.
9724 * @param msg Message struct.
9725 */
9726static void
9727handle_update_queue_message (void *cls,
9728 const struct
9729 GNUNET_TRANSPORT_UpdateQueueMessage *msg)
9730{
9731 struct TransportClient *tc = cls;
9732 struct Queue *target_queue = NULL;
9733
9734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9735 "Received queue update message for %u with q_len %llu\n",
9736 msg->qid, (unsigned long long) GNUNET_ntohll (msg->q_len));
9737 for (target_queue = tc->details.communicator.queue_head;
9738 NULL != target_queue;
9739 target_queue = target_queue->next_client)
9740 {
9741 if (msg->qid == target_queue->qid)
9742 break;
9743 }
9744 if (NULL == target_queue)
9745 {
9746 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9747 "Queue to update no longer exists! Discarding update.\n");
9748 return;
9749 }
9750
9751 target_queue->nt = msg->nt;
9752 target_queue->mtu = ntohl (msg->mtu);
9753 target_queue->cs = msg->cs;
9754 target_queue->priority = ntohl (msg->priority);
9755 /* The update message indicates how many _additional_
9756 * messages the queue should be able to handle
9757 */
9758 target_queue->queue_length += GNUNET_ntohll (msg->q_len);
9759 GNUNET_SERVICE_client_continue (tc->client);
9760}
9761
9762
9763/**
9764 * Communicator tells us that our request to create a queue "worked", that
9765 * is setting up the queue is now in process.
9766 *
9767 * @param cls the `struct TransportClient`
9768 * @param cqr confirmation message
9769 */
9770static void
9771handle_queue_create_ok (void *cls,
9772 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9773{
9774 struct TransportClient *tc = cls;
9775
9776 if (CT_COMMUNICATOR != tc->type)
9777 {
9778 GNUNET_break (0);
9779 GNUNET_SERVICE_client_drop (tc->client);
9780 return;
9781 }
9782 GNUNET_STATISTICS_update (GST_stats,
9783 "# Suggestions succeeded at communicator",
9784 1,
9785 GNUNET_NO);
9786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9787 "Request #%u for communicator to create queue succeeded\n",
9788 (unsigned int) ntohs (cqr->request_id));
9789 GNUNET_SERVICE_client_continue (tc->client);
9790}
9791
9792
9793/**
9794 * Communicator tells us that our request to create a queue failed. This
9795 * usually indicates that the provided address is simply invalid or that the
9796 * communicator's resources are exhausted.
9797 *
9798 * @param cls the `struct TransportClient`
9799 * @param cqr failure message
9800 */
9801static void
9802handle_queue_create_fail (
9803 void *cls,
9804 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
9805{
9806 struct TransportClient *tc = cls;
9807
9808 if (CT_COMMUNICATOR != tc->type)
9809 {
9810 GNUNET_break (0);
9811 GNUNET_SERVICE_client_drop (tc->client);
9812 return;
9813 }
9814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9815 "Request #%u for communicator to create queue failed\n",
9816 (unsigned int) ntohs (cqr->request_id));
9817 GNUNET_STATISTICS_update (GST_stats,
9818 "# Suggestions failed in queue creation at communicator",
9819 1,
9820 GNUNET_NO);
9821 GNUNET_SERVICE_client_continue (tc->client);
9822}
9823
9824
9825/**
9826 * We have received a `struct ExpressPreferenceMessage` from an application
9827 * client.
9828 *
9829 * @param cls handle to the client
9830 * @param msg the start message
9831 */
9832static void
9833handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
9834{
9835 struct TransportClient *tc = cls;
9836 struct PeerRequest *pr;
9837
9838 if (CT_APPLICATION != tc->type)
9839 {
9840 GNUNET_break (0);
9841 GNUNET_SERVICE_client_drop (tc->client);
9842 return;
9843 }
9844 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
9845 &msg->peer);
9846 if (NULL == pr)
9847 {
9848 GNUNET_break (0);
9849 GNUNET_SERVICE_client_drop (tc->client);
9850 return;
9851 }
9852 (void) stop_peer_request (tc, &pr->pid, pr);
9853 GNUNET_SERVICE_client_continue (tc->client);
9854}
9855
9856
9857/**
9858 * Function called by PEERSTORE for each matching record.
9859 *
9860 * @param cls closure, a `struct PeerRequest`
9861 * @param record peerstore record information
9862 * @param emsg error message, or NULL if no errors
9863 */
9864static void
9865handle_hello_for_client (void *cls,
9866 const struct GNUNET_PEERSTORE_Record *record,
9867 const char *emsg)
9868{
9869 struct PeerRequest *pr = cls;
9870 const char *val;
9871
9872 if (NULL != emsg)
9873 {
9874 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9875 "Got failure from PEERSTORE: %s\n",
9876 emsg);
9877 return;
9878 }
9879 val = record->value;
9880 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
9881 {
9882 GNUNET_break (0);
9883 return;
9884 }
9885 start_address_validation (&pr->pid, (const char *) record->value);
9886}
9887
9888
9889/**
9890 * We have received a `struct ExpressPreferenceMessage` from an application
9891 * client.
9892 *
9893 * @param cls handle to the client
9894 * @param msg the start message
9895 */
9896static void
9897handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
9898{
9899 struct TransportClient *tc = cls;
9900 struct PeerRequest *pr;
9901
9902 if (CT_NONE == tc->type)
9903 {
9904 tc->type = CT_APPLICATION;
9905 tc->details.application.requests =
9906 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
9907 }
9908 if (CT_APPLICATION != tc->type)
9909 {
9910 GNUNET_break (0);
9911 GNUNET_SERVICE_client_drop (tc->client);
9912 return;
9913 }
9914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9915 "Client suggested we talk to %s with preference %d at rate %u\n",
9916 GNUNET_i2s (&msg->peer),
9917 (int) ntohl (msg->pk),
9918 (int) ntohl (msg->bw.value__));
9919 pr = GNUNET_new (struct PeerRequest);
9920 pr->tc = tc;
9921 pr->pid = msg->peer;
9922 pr->bw = msg->bw;
9923 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
9924 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
9925 tc->details.application.requests,
9926 &pr->pid,
9927 pr,
9928 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
9929 {
9930 GNUNET_break (0);
9931 GNUNET_free (pr);
9932 GNUNET_SERVICE_client_drop (tc->client);
9933 return;
9934 }
9935 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
9936 "transport",
9937 &pr->pid,
9938 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
9939 &handle_hello_for_client,
9940 pr);
9941 GNUNET_SERVICE_client_continue (tc->client);
9942}
9943
9944
9945/**
9946 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
9947 * messages.
9948 *
9949 * @param cls a `struct TransportClient *`
9950 * @param m message to verify
9951 * @return #GNUNET_OK on success
9952 */
9953static int
9954check_request_hello_validation (void *cls,
9955 const struct RequestHelloValidationMessage *m)
9956{
9957 (void) cls;
9958 GNUNET_MQ_check_zero_termination (m);
9959 return GNUNET_OK;
9960}
9961
9962
9963/**
9964 * A client encountered an address of another peer. Consider validating it,
9965 * and if validation succeeds, persist it to PEERSTORE.
9966 *
9967 * @param cls a `struct TransportClient *`
9968 * @param m message to verify
9969 */
9970static void
9971handle_request_hello_validation (void *cls,
9972 const struct RequestHelloValidationMessage *m)
9973{
9974 struct TransportClient *tc = cls;
9975
9976 start_address_validation (&m->peer, (const char *) &m[1]);
9977 GNUNET_SERVICE_client_continue (tc->client);
9978}
9979
9980
9981/**
9982 * Free neighbour entry.
9983 *
9984 * @param cls NULL
9985 * @param pid unused
9986 * @param value a `struct Neighbour`
9987 * @return #GNUNET_OK (always)
9988 */
9989static int
9990free_neighbour_cb (void *cls,
9991 const struct GNUNET_PeerIdentity *pid,
9992 void *value)
9993{
9994 struct Neighbour *neighbour = value;
9995
9996 (void) cls;
9997 (void) pid;
9998 GNUNET_break (0); // should this ever happen?
9999 free_neighbour (neighbour);
10000
10001 return GNUNET_OK;
10002}
10003
10004
10005/**
10006 * Free DV route entry.
10007 *
10008 * @param cls NULL
10009 * @param pid unused
10010 * @param value a `struct DistanceVector`
10011 * @return #GNUNET_OK (always)
10012 */
10013static int
10014free_dv_routes_cb (void *cls,
10015 const struct GNUNET_PeerIdentity *pid,
10016 void *value)
10017{
10018 struct DistanceVector *dv = value;
10019
10020 (void) cls;
10021 (void) pid;
10022 free_dv_route (dv);
10023
10024 return GNUNET_OK;
10025}
10026
10027
10028/**
10029 * Free validation state.
10030 *
10031 * @param cls NULL
10032 * @param pid unused
10033 * @param value a `struct ValidationState`
10034 * @return #GNUNET_OK (always)
10035 */
10036static int
10037free_validation_state_cb (void *cls,
10038 const struct GNUNET_PeerIdentity *pid,
10039 void *value)
10040{
10041 struct ValidationState *vs = value;
10042
10043 (void) cls;
10044 (void) pid;
10045 free_validation_state (vs);
10046 return GNUNET_OK;
10047}
10048
10049
10050/**
10051 * Free pending acknowledgement.
10052 *
10053 * @param cls NULL
10054 * @param key unused
10055 * @param value a `struct PendingAcknowledgement`
10056 * @return #GNUNET_OK (always)
10057 */
10058static int
10059free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
10060{
10061 struct PendingAcknowledgement *pa = value;
10062
10063 (void) cls;
10064 (void) key;
10065 free_pending_acknowledgement (pa);
10066 return GNUNET_OK;
10067}
10068
10069
10070/**
10071 * Free acknowledgement cummulator.
10072 *
10073 * @param cls NULL
10074 * @param pid unused
10075 * @param value a `struct AcknowledgementCummulator`
10076 * @return #GNUNET_OK (always)
10077 */
10078static int
10079free_ack_cummulator_cb (void *cls,
10080 const struct GNUNET_PeerIdentity *pid,
10081 void *value)
10082{
10083 struct AcknowledgementCummulator *ac = value;
10084
10085 (void) cls;
10086 (void) pid;
10087 GNUNET_free (ac);
10088 return GNUNET_OK;
10089}
10090
10091
10092/**
10093 * Function called when the service shuts down. Unloads our plugins
10094 * and cancels pending validations.
10095 *
10096 * @param cls closure, unused
10097 */
10098static void
10099do_shutdown (void *cls)
10100{
10101 struct LearnLaunchEntry *lle;
10102
10103 (void) cls;
10104 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10105 &free_neighbour_cb, NULL);
10106 if (NULL != validation_task)
10107 {
10108 GNUNET_SCHEDULER_cancel (validation_task);
10109 validation_task = NULL;
10110 }
10111 if (NULL != dvlearn_task)
10112 {
10113 GNUNET_SCHEDULER_cancel (dvlearn_task);
10114 dvlearn_task = NULL;
10115 }
10116 if (NULL != GST_stats)
10117 {
10118 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
10119 GST_stats = NULL;
10120 }
10121 if (NULL != GST_my_private_key)
10122 {
10123 GNUNET_free (GST_my_private_key);
10124 GST_my_private_key = NULL;
10125 }
10126 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
10127 &free_ack_cummulator_cb,
10128 NULL);
10129 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
10130 ack_cummulators = NULL;
10131 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
10132 &free_pending_ack_cb,
10133 NULL);
10134 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
10135 pending_acks = NULL;
10136 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
10137 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
10138 neighbours = NULL;
10139 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
10140 GNUNET_CONTAINER_multipeermap_destroy (links);
10141 links = NULL;
10142 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
10143 &free_backtalker_cb,
10144 NULL);
10145 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
10146 backtalkers = NULL;
10147 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
10148 &free_validation_state_cb,
10149 NULL);
10150 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
10151 validation_map = NULL;
10152 while (NULL != ir_head)
10153 free_incoming_request (ir_head);
10154 GNUNET_assert (0 == ir_total);
10155 while (NULL != (lle = lle_head))
10156 {
10157 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
10158 GNUNET_free (lle);
10159 }
10160 if (NULL != peerstore)
10161 {
10162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10163 "Disconnecting from PEERSTORE service\n");
10164 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
10165 peerstore = NULL;
10166 }
10167 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
10168 dvlearn_map = NULL;
10169 GNUNET_CONTAINER_heap_destroy (validation_heap);
10170 validation_heap = NULL;
10171 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
10172 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
10173 dv_routes = NULL;
10174 GNUNET_SCHEDULER_shutdown ();
10175}
10176
10177
10178static void
10179shutdown_task (void *cls)
10180{
10181 in_shutdown = GNUNET_YES;
10182 if (NULL == clients_head)
10183 do_shutdown (cls);
10184}
10185
10186
10187/**
10188 * Initiate transport service.
10189 *
10190 * @param cls closure
10191 * @param c configuration to use
10192 * @param service the initialized service
10193 */
10194static void
10195run (void *cls,
10196 const struct GNUNET_CONFIGURATION_Handle *c,
10197 struct GNUNET_SERVICE_Handle *service)
10198{
10199 (void) cls;
10200 (void) service;
10201 /* setup globals */
10202 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
10203 in_shutdown = GNUNET_NO;
10204 GST_cfg = c;
10205 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
10206 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
10207 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
10208 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10209 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
10210 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10211 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
10212 GNUNET_YES);
10213 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
10214 validation_heap =
10215 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
10216 GST_my_private_key =
10217 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
10218 if (NULL == GST_my_private_key)
10219 {
10220 GNUNET_log (
10221 GNUNET_ERROR_TYPE_ERROR,
10222 _ (
10223 "Transport service is lacking key configuration settings. Exiting.\n"));
10224 GNUNET_SCHEDULER_shutdown ();
10225 return;
10226 }
10227 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
10228 &GST_my_identity.public_key);
10229 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10230 "My identity is `%s'\n",
10231 GNUNET_i2s_full (&GST_my_identity));
10232 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
10233 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
10234 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
10235 if (NULL == peerstore)
10236 {
10237 GNUNET_break (0);
10238 GNUNET_SCHEDULER_shutdown ();
10239 return;
10240 }
10241}
10242
10243
10244/**
10245 * Define "main" method using service macro.
10246 */
10247GNUNET_SERVICE_MAIN (
10248 "transport",
10249 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
10250 &run,
10251 &client_connect_cb,
10252 &client_disconnect_cb,
10253 NULL,
10254 /* communication with applications */
10255 GNUNET_MQ_hd_fixed_size (suggest,
10256 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
10257 struct ExpressPreferenceMessage,
10258 NULL),
10259 GNUNET_MQ_hd_fixed_size (suggest_cancel,
10260 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
10261 struct ExpressPreferenceMessage,
10262 NULL),
10263 GNUNET_MQ_hd_var_size (request_hello_validation,
10264 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
10265 struct RequestHelloValidationMessage,
10266 NULL),
10267 /* communication with core */
10268 GNUNET_MQ_hd_fixed_size (client_start,
10269 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
10270 struct StartMessage,
10271 NULL),
10272 GNUNET_MQ_hd_var_size (client_send,
10273 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
10274 struct OutboundMessage,
10275 NULL),
10276 GNUNET_MQ_hd_fixed_size (client_recv_ok,
10277 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
10278 struct RecvOkMessage,
10279 NULL),
10280 /* communication with communicators */
10281 GNUNET_MQ_hd_var_size (communicator_available,
10282 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
10283 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
10284 NULL),
10285 GNUNET_MQ_hd_var_size (communicator_backchannel,
10286 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
10287 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
10288 NULL),
10289 GNUNET_MQ_hd_var_size (add_address,
10290 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
10291 struct GNUNET_TRANSPORT_AddAddressMessage,
10292 NULL),
10293 GNUNET_MQ_hd_fixed_size (del_address,
10294 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
10295 struct GNUNET_TRANSPORT_DelAddressMessage,
10296 NULL),
10297 GNUNET_MQ_hd_var_size (incoming_msg,
10298 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
10299 struct GNUNET_TRANSPORT_IncomingMessage,
10300 NULL),
10301 GNUNET_MQ_hd_fixed_size (queue_create_ok,
10302 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
10303 struct GNUNET_TRANSPORT_CreateQueueResponse,
10304 NULL),
10305 GNUNET_MQ_hd_fixed_size (queue_create_fail,
10306 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
10307 struct GNUNET_TRANSPORT_CreateQueueResponse,
10308 NULL),
10309 GNUNET_MQ_hd_var_size (add_queue_message,
10310 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
10311 struct GNUNET_TRANSPORT_AddQueueMessage,
10312 NULL),
10313 GNUNET_MQ_hd_fixed_size (update_queue_message,
10314 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE,
10315 struct GNUNET_TRANSPORT_UpdateQueueMessage,
10316 NULL),
10317 GNUNET_MQ_hd_fixed_size (del_queue_message,
10318 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
10319 struct GNUNET_TRANSPORT_DelQueueMessage,
10320 NULL),
10321 GNUNET_MQ_hd_fixed_size (send_message_ack,
10322 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
10323 struct GNUNET_TRANSPORT_SendMessageToAck,
10324 NULL),
10325 /* communication with monitors */
10326 GNUNET_MQ_hd_fixed_size (monitor_start,
10327 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
10328 struct GNUNET_TRANSPORT_MonitorStart,
10329 NULL),
10330 GNUNET_MQ_handler_end ());
10331
10332
10333/* 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 24cc6464a..000000000
--- a/src/transport/gnunet-service-transport.c
+++ /dev/null
@@ -1,2788 +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 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_LEGACY:
1632 /* Legacy 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
2192/**
2193 * Perform next action in the blacklist check.
2194 *
2195 * @param cls the `struct GST_BlacklistCheck *`
2196 */
2197static void
2198do_blacklist_check (void *cls)
2199{
2200 struct GST_BlacklistCheck *bc = cls;
2201 struct TransportClient *tc;
2202 struct GNUNET_MQ_Envelope *env;
2203 struct BlacklistMessage *bm;
2204
2205 bc->task = NULL;
2206 while (NULL != (tc = bc->bl_pos))
2207 {
2208 if (CT_BLACKLIST == tc->type)
2209 break;
2210 bc->bl_pos = tc->next;
2211 }
2212 if (NULL == tc)
2213 {
2214 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2215 "No other blacklist clients active, will allow neighbour `%s'\n",
2216 GNUNET_i2s (&bc->peer));
2217
2218 bc->cont (bc->cont_cls, &bc->peer, bc->address, bc->session, GNUNET_OK);
2219 GST_blacklist_test_cancel (bc);
2220 return;
2221 }
2222 if ((NULL != tc->details.blacklist.bc) ||
2223 (GNUNET_NO != tc->details.blacklist.waiting_for_reply))
2224 return; /* someone else busy with this client */
2225 tc->details.blacklist.bc = bc;
2226 env = GNUNET_MQ_msg (bm, GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
2227 bm->is_allowed = htonl (0);
2228 bm->peer = bc->peer;
2229 GNUNET_MQ_send (tc->mq, env);
2230 if (GNUNET_YES == tc->details.blacklist.call_receive_done)
2231 {
2232 tc->details.blacklist.call_receive_done = GNUNET_NO;
2233 GNUNET_SERVICE_client_continue (tc->client);
2234 }
2235 tc->details.blacklist.waiting_for_reply = GNUNET_YES;
2236}
2237
2238
2239/**
2240 * A blacklisting client has sent us reply. Process it.
2241 *
2242 * @param cls the client
2243 * @param msg the blacklist-reply message that was sent
2244 */
2245static void
2246handle_client_blacklist_reply (void *cls, const struct BlacklistMessage *msg)
2247{
2248 struct TransportClient *tc = cls;
2249 struct GST_BlacklistCheck *bc;
2250
2251 if (CT_BLACKLIST != tc->type)
2252 {
2253 GNUNET_break (0);
2254 GNUNET_SERVICE_client_drop (tc->client);
2255 return;
2256 }
2257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2258 "Blacklist client %p sent reply for `%s'\n",
2259 tc,
2260 GNUNET_i2s (&msg->peer));
2261 bc = tc->details.blacklist.bc;
2262 tc->details.blacklist.bc = NULL;
2263 tc->details.blacklist.waiting_for_reply = GNUNET_NO;
2264 tc->details.blacklist.call_receive_done = GNUNET_YES;
2265 if (NULL != bc)
2266 {
2267 /* only run this if the blacklist check has not been
2268 * cancelled in the meantime... */
2269 GNUNET_assert (bc->bl_pos == tc);
2270 if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
2271 {
2272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2273 "Blacklist check failed, peer not allowed\n");
2274 /* For the duration of the continuation, make the ongoing
2275 check invisible (to avoid double-cancellation); then
2276 add it back again so we can re-use GST_blacklist_test_cancel() */
2277 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
2278 bc->cont (bc->cont_cls, &bc->peer, bc->address, bc->session, GNUNET_NO);
2279 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
2280 GST_blacklist_test_cancel (bc);
2281 tc->details.blacklist.call_receive_done = GNUNET_NO;
2282 GNUNET_SERVICE_client_continue (tc->client);
2283 return;
2284 }
2285 else
2286 {
2287 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2288 "Blacklist check succeeded, continuing with checks\n");
2289 tc->details.blacklist.call_receive_done = GNUNET_NO;
2290 GNUNET_SERVICE_client_continue (tc->client);
2291 bc->bl_pos = tc->next;
2292 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
2293 }
2294 }
2295 /* check if any other blacklist checks are waiting for this blacklister */
2296 for (bc = bc_head; bc != NULL; bc = bc->next)
2297 if ((bc->bl_pos == tc) && (NULL == bc->task))
2298 {
2299 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
2300 break;
2301 }
2302}
2303
2304
2305/**
2306 * Add the given peer to the blacklist (for the given transport).
2307 *
2308 * @param peer peer to blacklist
2309 * @param transport_name transport to blacklist for this peer, NULL for all
2310 */
2311void
2312GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
2313 const char *transport_name)
2314{
2315 char *transport = NULL;
2316
2317 if (NULL != transport_name)
2318 {
2319 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2320 "Adding peer `%s' with plugin `%s' to blacklist\n",
2321 GNUNET_i2s (peer),
2322 transport_name);
2323 transport = GNUNET_strdup (transport_name);
2324 }
2325 else
2326 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2327 "Adding peer `%s' with all plugins to blacklist\n",
2328 GNUNET_i2s (peer));
2329 if (NULL == blacklist)
2330 blacklist =
2331 GNUNET_CONTAINER_multipeermap_create (TRANSPORT_BLACKLIST_HT_SIZE,
2332 GNUNET_NO);
2333
2334 GNUNET_CONTAINER_multipeermap_put (blacklist,
2335 peer,
2336 transport,
2337 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2338}
2339
2340
2341/**
2342 * Abort blacklist if @a address and @a session match.
2343 *
2344 * @param address address used to abort matching checks
2345 * @param session session used to abort matching checks
2346 */
2347void
2348GST_blacklist_abort_matching (const struct GNUNET_HELLO_Address *address,
2349 struct GNUNET_ATS_Session *session)
2350{
2351 struct GST_BlacklistCheck *bc;
2352 struct GST_BlacklistCheck *n;
2353
2354 n = bc_head;
2355 while (NULL != (bc = n))
2356 {
2357 n = bc->next;
2358 if ((bc->session == session) &&
2359 (0 == GNUNET_HELLO_address_cmp (bc->address, address)))
2360 {
2361 bc->cont (bc->cont_cls,
2362 &bc->peer,
2363 bc->address,
2364 bc->session,
2365 GNUNET_SYSERR);
2366 GST_blacklist_test_cancel (bc);
2367 }
2368 }
2369}
2370
2371
2372/**
2373 * Test if the given blacklist entry matches. If so,
2374 * abort the iteration.
2375 *
2376 * @param cls the transport name to match (const char*)
2377 * @param key the key (unused)
2378 * @param value the 'char *' (name of a blacklisted transport)
2379 * @return #GNUNET_OK if the entry does not match, #GNUNET_NO if it matches
2380 */
2381static int
2382test_blacklisted (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
2383{
2384 const char *transport_name = cls;
2385 char *be = value;
2386
2387 /* Blacklist entry be:
2388 * (NULL == be): peer is blacklisted with all plugins
2389 * (NULL != be): peer is blacklisted for a specific plugin
2390 *
2391 * If (NULL != transport_name) we look for a transport specific entry:
2392 * if (transport_name == be) forbidden
2393 *
2394 */GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2395 "Comparing BL request for peer `%4s':`%s' with BL entry: `%s'\n",
2396 GNUNET_i2s (key),
2397 (NULL == transport_name) ? "unspecified" : transport_name,
2398 (NULL == be) ? "all plugins" : be);
2399 /* all plugins for this peer were blacklisted: disallow */
2400 if (NULL == value)
2401 return GNUNET_NO;
2402
2403 /* blacklist check for specific transport */
2404 if ((NULL != transport_name) && (NULL != value))
2405 {
2406 if (0 == strcmp (transport_name, be))
2407 return GNUNET_NO; /* plugin is blacklisted! */
2408 }
2409 return GNUNET_OK;
2410}
2411
2412
2413/**
2414 * Test if a peer/transport combination is blacklisted.
2415 *
2416 * @param peer the identity of the peer to test
2417 * @param transport_name name of the transport to test, never NULL
2418 * @param cont function to call with result
2419 * @param cont_cls closure for @a cont
2420 * @param address address to pass back to @a cont, can be NULL
2421 * @param session session to pass back to @a cont, can be NULL
2422 * @return handle to the blacklist check, NULL if the decision
2423 * was made instantly and @a cont was already called
2424 */
2425struct GST_BlacklistCheck *
2426GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
2427 const char *transport_name,
2428 GST_BlacklistTestContinuation cont,
2429 void *cont_cls,
2430 const struct GNUNET_HELLO_Address *address,
2431 struct GNUNET_ATS_Session *session)
2432{
2433 struct GST_BlacklistCheck *bc;
2434 struct TransportClient *tc;
2435
2436 GNUNET_assert (NULL != peer);
2437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2438 "Blacklist check for peer `%s':%s\n",
2439 GNUNET_i2s (peer),
2440 (NULL != transport_name) ? transport_name : "unspecified");
2441
2442 /* Check local blacklist by iterating over hashmap
2443 * If iteration is aborted, we found a matching blacklist entry */
2444 if ((NULL != blacklist) &&
2445 (GNUNET_SYSERR ==
2446 GNUNET_CONTAINER_multipeermap_get_multiple (blacklist,
2447 peer,
2448 &test_blacklisted,
2449 (void *) transport_name)))
2450 {
2451 /* Disallowed by config, disapprove instantly */
2452 GNUNET_STATISTICS_update (GST_stats,
2453 gettext_noop ("# disconnects due to blacklist"),
2454 1,
2455 GNUNET_NO);
2456 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2457 _ ("Disallowing connection to peer `%s' on transport %s\n"),
2458 GNUNET_i2s (peer),
2459 (NULL != transport_name) ? transport_name : "unspecified");
2460 if (NULL != cont)
2461 cont (cont_cls, peer, address, session, GNUNET_NO);
2462 return NULL;
2463 }
2464
2465 for (tc = clients_head; NULL != tc; tc = tc->next)
2466 if (CT_BLACKLIST == tc->type)
2467 break;
2468 if (NULL == tc)
2469 {
2470 /* no blacklist clients, approve instantly */
2471 if (NULL != cont)
2472 cont (cont_cls, peer, address, session, GNUNET_OK);
2473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2474 "Allowing connection to peer `%s' %s\n",
2475 GNUNET_i2s (peer),
2476 (NULL != transport_name) ? transport_name : "");
2477 return NULL;
2478 }
2479
2480 /* need to query blacklist clients */
2481 bc = GNUNET_new (struct GST_BlacklistCheck);
2482 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
2483 bc->peer = *peer;
2484 bc->address = GNUNET_HELLO_address_copy (address);
2485 bc->session = session;
2486 bc->cont = cont;
2487 bc->cont_cls = cont_cls;
2488 bc->bl_pos = tc;
2489 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
2490 return bc;
2491}
2492
2493
2494/**
2495 * Cancel a blacklist check.
2496 *
2497 * @param bc check to cancel
2498 */
2499void
2500GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
2501{
2502 GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
2503 if (NULL != bc->bl_pos)
2504 {
2505 if ((CT_BLACKLIST == bc->bl_pos->type) &&
2506 (bc->bl_pos->details.blacklist.bc == bc))
2507 {
2508 /* we're at the head of the queue, remove us! */
2509 bc->bl_pos->details.blacklist.bc = NULL;
2510 }
2511 }
2512 if (NULL != bc->task)
2513 {
2514 GNUNET_SCHEDULER_cancel (bc->task);
2515 bc->task = NULL;
2516 }
2517 GNUNET_free (bc->address);
2518 GNUNET_free (bc);
2519}
2520
2521
2522/**
2523 * Function to iterate over options in the blacklisting section for a peer.
2524 *
2525 * @param cls closure
2526 * @param section name of the section
2527 * @param option name of the option
2528 * @param value value of the option
2529 */
2530static void
2531blacklist_cfg_iter (void *cls,
2532 const char *section,
2533 const char *option,
2534 const char *value)
2535{
2536 unsigned int *res = cls;
2537 struct GNUNET_PeerIdentity peer;
2538 char *plugs;
2539 char *pos;
2540
2541 if (GNUNET_OK !=
2542 GNUNET_CRYPTO_eddsa_public_key_from_string (option,
2543 strlen (option),
2544 &peer.public_key))
2545 return;
2546
2547 if ((NULL == value) || (0 == strcmp (value, "")))
2548 {
2549 /* Blacklist whole peer */
2550 GST_blacklist_add_peer (&peer, NULL);
2551 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2552 _ ("Adding blacklisting entry for peer `%s'\n"),
2553 GNUNET_i2s (&peer));
2554 }
2555 else
2556 {
2557 plugs = GNUNET_strdup (value);
2558 for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
2559 {
2560 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2561 _ ("Adding blacklisting entry for peer `%s':`%s'\n"),
2562 GNUNET_i2s (&peer),
2563 pos);
2564 GST_blacklist_add_peer (&peer, pos);
2565 }
2566 GNUNET_free (plugs);
2567 }
2568 (*res)++;
2569}
2570
2571
2572/**
2573 * Read blacklist configuration
2574 *
2575 * @param cfg the configuration handle
2576 * @param my_id my peer identity
2577 */
2578static void
2579read_blacklist_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg,
2580 const struct GNUNET_PeerIdentity *my_id)
2581{
2582 char cfg_sect[512];
2583 unsigned int res = 0;
2584
2585 GNUNET_snprintf (cfg_sect,
2586 sizeof(cfg_sect),
2587 "transport-blacklist-%s",
2588 GNUNET_i2s_full (my_id));
2589 GNUNET_CONFIGURATION_iterate_section_values (cfg,
2590 cfg_sect,
2591 &blacklist_cfg_iter,
2592 &res);
2593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2594 "Loaded %u blacklisting entries from configuration\n",
2595 res);
2596}
2597
2598
2599/**
2600 * Initiate transport service.
2601 *
2602 * @param cls closure
2603 * @param c configuration to use
2604 * @param service the initialized service
2605 */
2606static void
2607run (void *cls,
2608 const struct GNUNET_CONFIGURATION_Handle *c,
2609 struct GNUNET_SERVICE_Handle *service)
2610{
2611 char *keyfile;
2612 long long unsigned int max_fd_cfg;
2613 int max_fd_rlimit;
2614 int max_fd;
2615 int friend_only;
2616
2617 /* setup globals */
2618 GST_cfg = c;
2619 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (c,
2620 "PEER",
2621 "PRIVATE_KEY",
2622 &keyfile))
2623 {
2624 GNUNET_log (
2625 GNUNET_ERROR_TYPE_ERROR,
2626 _ (
2627 "Transport service is lacking key configuration settings. Exiting.\n"));
2628 GNUNET_SCHEDULER_shutdown ();
2629 return;
2630 }
2631 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (c,
2632 "transport",
2633 "HELLO_EXPIRATION",
2634 &hello_expiration))
2635 {
2636 hello_expiration = GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION;
2637 }
2638 if (GNUNET_SYSERR ==
2639 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
2640 GNUNET_YES,
2641 &GST_my_private_key))
2642 {
2643 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2644 "Failed to setup peer's private key\n");
2645 GNUNET_SCHEDULER_shutdown ();
2646 GNUNET_free (keyfile);
2647 return;
2648 }
2649 GNUNET_free (keyfile);
2650 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
2651 GST_peerinfo = GNUNET_PEERINFO_connect (GST_cfg);
2652 GNUNET_CRYPTO_eddsa_key_get_public (&GST_my_private_key,
2653 &GST_my_identity.public_key);
2654 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2655 "My identity is `%s'\n",
2656 GNUNET_i2s_full (&GST_my_identity));
2657
2658 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
2659 if (NULL == GST_peerinfo)
2660 {
2661 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2662 _ ("Could not access PEERINFO service. Exiting.\n"));
2663 GNUNET_SCHEDULER_shutdown ();
2664 return;
2665 }
2666
2667 max_fd_rlimit = 0;
2668#if HAVE_GETRLIMIT
2669 {
2670 struct rlimit r_file;
2671
2672 if (0 == getrlimit (RLIMIT_NOFILE, &r_file))
2673 {
2674 max_fd_rlimit = r_file.rlim_cur;
2675 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2676 "Maximum number of open files was: %u/%u\n",
2677 (unsigned int) r_file.rlim_cur,
2678 (unsigned int) r_file.rlim_max);
2679 }
2680 max_fd_rlimit =
2681 (9 * max_fd_rlimit) / 10; /* Keep 10% for rest of transport */
2682 }
2683#endif
2684 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (GST_cfg,
2685 "transport",
2686 "MAX_FD",
2687 &max_fd_cfg))
2688 max_fd_cfg = max_fd_rlimit;
2689
2690 if (max_fd_cfg > max_fd_rlimit)
2691 max_fd = max_fd_cfg;
2692 else
2693 max_fd = max_fd_rlimit;
2694 if (max_fd < DEFAULT_MAX_FDS)
2695 max_fd = DEFAULT_MAX_FDS;
2696
2697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2698 "Limiting number of sockets to %u: validation %u, neighbors: %u\n",
2699 max_fd,
2700 (max_fd / 3),
2701 (max_fd / 3) * 2);
2702
2703 friend_only =
2704 GNUNET_CONFIGURATION_get_value_yesno (GST_cfg, "topology", "FRIENDS-ONLY");
2705 if (GNUNET_SYSERR == friend_only)
2706 friend_only = GNUNET_NO; /* According to topology defaults */
2707 /* start subsystems */
2708 /* Disable DSTJ peer */
2709 {
2710 struct GNUNET_PeerIdentity dstj;
2711 const char *ds = "DSTJBRRKZ8TBW3FGK6B0M5QXWT9WYNZ45H5MCV4HY7ST64Q8T9F0";
2712
2713 GNUNET_assert (
2714 GNUNET_OK ==
2715 GNUNET_CRYPTO_eddsa_public_key_from_string (ds,
2716 strlen (ds),
2717 &dstj.public_key));
2718 GST_blacklist_add_peer (&dstj, NULL);
2719 }
2720 read_blacklist_configuration (GST_cfg, &GST_my_identity);
2721 GST_is = GNUNET_NT_scanner_init ();
2722 GST_ats_connect = GNUNET_ATS_connectivity_init (GST_cfg);
2723 GST_ats =
2724 GNUNET_ATS_scheduling_init (GST_cfg, &ats_request_address_change, NULL);
2725 GST_ats_init ();
2726 GST_manipulation_init ();
2727 GST_plugins_load (&GST_manipulation_recv,
2728 &plugin_env_address_change_notification,
2729 &plugin_env_session_start,
2730 &plugin_env_session_end);
2731 GST_hello_start (friend_only, &process_hello_update, NULL);
2732 GST_neighbours_start ((max_fd / 3) * 2);
2733 active_stccs = GNUNET_CONTAINER_multipeermap_create (128, GNUNET_YES);
2734 plugin_nc = GNUNET_notification_context_create (0);
2735 GST_validation_start ((max_fd / 3));
2736}
2737
2738
2739/**
2740 * Define "main" method using service macro.
2741 */
2742GNUNET_SERVICE_MAIN (
2743 "transport",
2744 GNUNET_SERVICE_OPTION_NONE,
2745 &run,
2746 &client_connect_cb,
2747 &client_disconnect_cb,
2748 NULL,
2749 GNUNET_MQ_hd_fixed_size (client_start,
2750 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
2751 struct StartMessage,
2752 NULL),
2753 GNUNET_MQ_hd_var_size (client_hello,
2754 GNUNET_MESSAGE_TYPE_HELLO,
2755 struct GNUNET_MessageHeader,
2756 NULL),
2757 GNUNET_MQ_hd_var_size (client_send,
2758 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
2759 struct OutboundMessage,
2760 NULL),
2761 GNUNET_MQ_hd_var_size (client_address_to_string,
2762 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING,
2763 struct AddressLookupMessage,
2764 NULL),
2765 GNUNET_MQ_hd_fixed_size (client_monitor_peers,
2766 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST,
2767 struct PeerMonitorMessage,
2768 NULL),
2769 GNUNET_MQ_hd_fixed_size (client_blacklist_init,
2770 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
2771 struct GNUNET_MessageHeader,
2772 NULL),
2773 GNUNET_MQ_hd_fixed_size (client_blacklist_reply,
2774 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
2775 struct BlacklistMessage,
2776 NULL),
2777 GNUNET_MQ_hd_fixed_size (client_set_metric,
2778 GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC,
2779 struct TrafficMetricMessage,
2780 NULL),
2781 GNUNET_MQ_hd_fixed_size (client_monitor_plugins,
2782 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START,
2783 struct GNUNET_MessageHeader,
2784 NULL),
2785 GNUNET_MQ_handler_end ());
2786
2787
2788/* 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 8348dd1b7..000000000
--- a/src/transport/gnunet-transport-certificate-creation.in
+++ /dev/null
@@ -1,147 +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
45setdefaults()
46{
47 verbosity=0
48 runcmd=
49}
50
51statusmsg()
52{
53 ${runcmd} echo " $@"
54}
55
56infomsg()
57{
58 if [ x$verbosity = x1 ]; then
59 statusmsg "INFO: $@"
60 fi
61}
62
63warningmsg()
64{
65 statusmsg "WARNING: $@"
66}
67
68errormsg()
69{
70 statusmsg "ERROR: $@"
71}
72
73linemsg()
74{
75 statusmsg "========================================="
76}
77
78
79usage()
80{
81 if [ -n "$*" ]; then
82 echo ""
83 echo "${progname}: $*"
84 fi
85 cat <<_usage_
86
87Usage: ${progname} [-hv] [-c FILE] [...]
88
89Options:
90 -c FILE Use the configuration file FILE.
91 -h Print this help message.
92 -v Print the version and exit.
93 -V be verbose
94
95_usage_
96 exit 1
97}
98
99
100generate_cert_key()
101{
102 echo ""
103 infomsg "Generating Cert and Key"
104
105 CERTTOOL=""
106 GNUTLS_CA_TEMPLATE=@PKGDATADIRECTORY@/gnunet-gns-proxy-ca.template
107 OPENSSL=0
108 if test -z "`gnutls-certtool --version`" > /dev/null
109 then
110 if test -z "`openssl version`" > /dev/null
111 then
112 warningmsg "Install either gnutls certtool or openssl for certificate generation!"
113 exit 1
114 else
115 OPENSSL=1
116 fi
117 CERTTOOL="openssl"
118 else
119 CERTTOOL="gnutls-certtool"
120 fi
121 mkdir -p `dirname $KEYFILE`
122
123 if test 1 -eq $OPENSSL
124 then
125 $CERTTOOL genrsa -out $KEYFILE 1024
126 $CERTTOOL req -batch -days 365 -out $CERTFILE -new -x509 -key $KEYFILE
127 else
128 $CERTTOOL --generate-privkey --outfile $KEYFILE 2>/dev/null
129 $CERTTOOL --template $GNUTLS_CA_TEMPLATE --generate-self-signed --load-privkey $KEYFILE --outfile $CERTFILE 2>/dev/null
130 fi
131 }
132
133print_version()
134{
135 GNUNET_ARM_VERSION=`gnunet-arm -v`
136 echo $GNUNET_ARM_VERSION
137}
138
139main()
140{
141 KEYFILE=$1
142 CERTFILE=$2
143 setdefaults
144 generate_cert_key
145}
146
147main "$@"
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 18bfcc054..000000000
--- a/src/transport/plugin_transport_http_client.c
+++ /dev/null
@@ -1,2535 +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
1695/**
1696 * Connect a HTTP put request
1697 *
1698 * @param s the session to connect
1699 * @return #GNUNET_SYSERR for hard failure, #GNUNET_OK for ok
1700 */
1701static int
1702client_connect_put (struct GNUNET_ATS_Session *s)
1703{
1704 CURLMcode mret;
1705 struct HttpAddress *ha;
1706 uint32_t options;
1707
1708 ha = (struct HttpAddress *) s->address->address;
1709 options = ntohl (ha->options);
1710 /* create put request */
1711 LOG (GNUNET_ERROR_TYPE_DEBUG,
1712 "Session %p: Init PUT handle\n",
1713 s);
1714 s->put.easyhandle = curl_easy_init ();
1715 s->put.s = s;
1716#if VERBOSE_CURL
1717 curl_easy_setopt (s->put.easyhandle,
1718 CURLOPT_VERBOSE,
1719 1L);
1720 curl_easy_setopt (s->put.easyhandle,
1721 CURLOPT_DEBUGFUNCTION,
1722 &client_log);
1723 curl_easy_setopt (s->put.easyhandle,
1724 CURLOPT_DEBUGDATA,
1725 &s->put);
1726#endif
1727 if (0 != (options & HTTP_OPTIONS_TCP_STEALTH))
1728 {
1729#ifdef TCP_STEALTH
1730 curl_easy_setopt (s->put.easyhandle,
1731 CURLOPT_OPENSOCKETFUNCTION,
1732 &open_tcp_stealth_socket_cb);
1733 curl_easy_setopt (s->put.easyhandle,
1734 CURLOPT_OPENSOCKETDATA,
1735 s);
1736#else
1737 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1738 "Cannot connect, TCP STEALTH needed and not supported by kernel.\n");
1739 curl_easy_cleanup (s->put.easyhandle);
1740 s->put.easyhandle = NULL;
1741 s->put.s = NULL;
1742 s->put.state = H_DISCONNECTED;
1743 return GNUNET_SYSERR;
1744#endif
1745 }
1746#if BUILD_HTTPS
1747 curl_easy_setopt (s->put.easyhandle,
1748 CURLOPT_SSLVERSION,
1749 CURL_SSLVERSION_TLSv1);
1750 {
1751 struct HttpAddress *ha;
1752 ha = (struct HttpAddress *) s->address->address;
1753
1754 if (HTTP_OPTIONS_VERIFY_CERTIFICATE ==
1755 (ntohl (ha->options) & HTTP_OPTIONS_VERIFY_CERTIFICATE))
1756 {
1757 curl_easy_setopt (s->put.easyhandle,
1758 CURLOPT_SSL_VERIFYPEER,
1759 1L);
1760 curl_easy_setopt (s->put.easyhandle,
1761 CURLOPT_SSL_VERIFYHOST,
1762 2L);
1763 }
1764 else
1765 {
1766 curl_easy_setopt (s->put.easyhandle,
1767 CURLOPT_SSL_VERIFYPEER,
1768 0L);
1769 curl_easy_setopt (s->put.easyhandle,
1770 CURLOPT_SSL_VERIFYHOST,
1771 0L);
1772 }
1773 }
1774 curl_easy_setopt (s->put.easyhandle,
1775 CURLOPT_PROTOCOLS,
1776 CURLPROTO_HTTPS);
1777 curl_easy_setopt (s->put.easyhandle,
1778 CURLOPT_REDIR_PROTOCOLS,
1779 CURLPROTO_HTTPS);
1780#else
1781 curl_easy_setopt (s->put.easyhandle,
1782 CURLOPT_PROTOCOLS,
1783 CURLPROTO_HTTP);
1784 curl_easy_setopt (s->put.easyhandle,
1785 CURLOPT_REDIR_PROTOCOLS,
1786 CURLPROTO_HTTP);
1787#endif
1788 if (NULL != s->plugin->proxy_hostname)
1789 {
1790 curl_easy_setopt (s->put.easyhandle,
1791 CURLOPT_PROXY,
1792 s->plugin->proxy_hostname);
1793 curl_easy_setopt (s->put.easyhandle,
1794 CURLOPT_PROXYTYPE,
1795 s->plugin->proxytype);
1796 if (NULL != s->plugin->proxy_username)
1797 curl_easy_setopt (s->put.easyhandle,
1798 CURLOPT_PROXYUSERNAME,
1799 s->plugin->proxy_username);
1800 if (NULL != s->plugin->proxy_password)
1801 curl_easy_setopt (s->put.easyhandle,
1802 CURLOPT_PROXYPASSWORD,
1803 s->plugin->proxy_password);
1804 if (GNUNET_YES == s->plugin->proxy_use_httpproxytunnel)
1805 curl_easy_setopt (s->put.easyhandle,
1806 CURLOPT_HTTPPROXYTUNNEL,
1807 s->plugin->proxy_use_httpproxytunnel);
1808 }
1809
1810 curl_easy_setopt (s->put.easyhandle,
1811 CURLOPT_URL,
1812 s->url);
1813 curl_easy_setopt (s->put.easyhandle,
1814 CURLOPT_UPLOAD,
1815 1L);
1816 curl_easy_setopt (s->put.easyhandle,
1817 CURLOPT_READFUNCTION,
1818 &client_send_cb);
1819 curl_easy_setopt (s->put.easyhandle,
1820 CURLOPT_READDATA,
1821 s);
1822 curl_easy_setopt (s->put.easyhandle,
1823 CURLOPT_WRITEFUNCTION,
1824 &client_receive_put);
1825 curl_easy_setopt (s->put.easyhandle,
1826 CURLOPT_WRITEDATA,
1827 s);
1828 /* No timeout by default, timeout done with session timeout */
1829 curl_easy_setopt (s->put.easyhandle,
1830 CURLOPT_TIMEOUT,
1831 0L);
1832 curl_easy_setopt (s->put.easyhandle,
1833 CURLOPT_PRIVATE,
1834 s);
1835 curl_easy_setopt (s->put.easyhandle,
1836 CURLOPT_CONNECTTIMEOUT_MS,
1837 (long) (HTTP_CLIENT_NOT_VALIDATED_TIMEOUT.rel_value_us
1838 / 1000LL));
1839 curl_easy_setopt (s->put.easyhandle, CURLOPT_BUFFERSIZE,
1840 2 * GNUNET_MAX_MESSAGE_SIZE);
1841#if CURL_TCP_NODELAY
1842 curl_easy_setopt (s->put.easyhandle, CURLOPT_TCP_NODELAY, 1);
1843#endif
1844 mret = curl_multi_add_handle (s->plugin->curl_multi_handle,
1845 s->put.easyhandle);
1846 if (CURLM_OK != mret)
1847 {
1848 LOG (GNUNET_ERROR_TYPE_ERROR,
1849 "Session %p : Failed to add PUT handle to multihandle: `%s'\n",
1850 s, curl_multi_strerror (mret));
1851 curl_easy_cleanup (s->put.easyhandle);
1852 s->put.easyhandle = NULL;
1853 s->put.s = NULL;
1854 s->put.state = H_DISCONNECTED;
1855 return GNUNET_SYSERR;
1856 }
1857 s->put.state = H_CONNECTED;
1858 s->plugin->cur_requests++;
1859
1860 LOG (GNUNET_ERROR_TYPE_INFO,
1861 "PUT request `%s' established, number of requests increased to %u\n",
1862 s->url, s->plugin->cur_requests);
1863
1864 return GNUNET_OK;
1865}
1866
1867
1868/**
1869 * Connect both PUT and GET request for a session
1870 *
1871 * @param s the session to connect
1872 * @return #GNUNET_OK on success, #GNUNET_SYSERR otherwise
1873 */
1874static int
1875client_connect (struct GNUNET_ATS_Session *s)
1876{
1877 struct HTTP_Client_Plugin *plugin = s->plugin;
1878 int res = GNUNET_OK;
1879
1880 /* create url */
1881 if (NULL ==
1882 http_common_plugin_address_to_string (plugin->protocol,
1883 s->address->address,
1884 s->address->address_length))
1885 {
1886 LOG (GNUNET_ERROR_TYPE_DEBUG,
1887 "Invalid address peer `%s'\n",
1888 GNUNET_i2s (&s->address->peer));
1889 return GNUNET_SYSERR;
1890 }
1891
1892 GNUNET_asprintf (&s->url,
1893 "%s/%s;%u",
1894 http_common_plugin_address_to_url (NULL,
1895 s->address->address,
1896 s->address->address_length),
1897 GNUNET_i2s_full (plugin->env->my_identity),
1898 plugin->last_tag);
1899
1900 plugin->last_tag++;
1901 LOG (GNUNET_ERROR_TYPE_DEBUG,
1902 "Initiating outbound session peer `%s' using address `%s'\n",
1903 GNUNET_i2s (&s->address->peer), s->url);
1904
1905 if (GNUNET_SYSERR == client_connect_get (s))
1906 return GNUNET_SYSERR;
1907 /* If we are emulating an XHR client then delay sending a PUT request until
1908 * there is something to send.
1909 */
1910 if (GNUNET_YES == plugin->emulate_xhr)
1911 {
1912 s->put.state = H_TMP_DISCONNECTED;
1913 }
1914 else if (GNUNET_SYSERR == client_connect_put (s))
1915 return GNUNET_SYSERR;
1916
1917 LOG (GNUNET_ERROR_TYPE_DEBUG,
1918 "Session %p: connected with GET %p and PUT %p\n",
1919 s, s->get.easyhandle,
1920 s->put.easyhandle);
1921 /* Perform connect */
1922 GNUNET_STATISTICS_set (plugin->env->stats,
1923 HTTP_STAT_STR_CONNECTIONS,
1924 plugin->cur_requests,
1925 GNUNET_NO);
1926 /* Re-schedule since handles have changed */
1927 if (NULL != plugin->client_perform_task)
1928 {
1929 GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
1930 plugin->client_perform_task = NULL;
1931 }
1932
1933 /* Schedule task to run immediately */
1934 plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run,
1935 plugin);
1936 return res;
1937}
1938
1939
1940/**
1941 * Function obtain the network type for a session
1942 *
1943 * @param cls closure (`struct Plugin*`)
1944 * @param session the session
1945 * @return the network type
1946 */
1947static enum GNUNET_NetworkType
1948http_client_plugin_get_network (void *cls,
1949 struct GNUNET_ATS_Session *session)
1950{
1951 return session->scope;
1952}
1953
1954
1955/**
1956 * Function obtain the network type for an address.
1957 *
1958 * @param cls closure (`struct Plugin *`)
1959 * @param address the address
1960 * @return the network type
1961 */
1962static enum GNUNET_NetworkType
1963http_client_plugin_get_network_for_address (void *cls,
1964 const struct
1965 GNUNET_HELLO_Address *address)
1966{
1967 struct HTTP_Client_Plugin *plugin = cls;
1968
1969 return http_common_get_network_for_address (plugin->env,
1970 address);
1971}
1972
1973
1974/**
1975 * Session was idle, so disconnect it
1976 *
1977 * @param cls the `struct GNUNET_ATS_Session` of the idle session
1978 */
1979static void
1980client_session_timeout (void *cls)
1981{
1982 struct GNUNET_ATS_Session *s = cls;
1983 struct GNUNET_TIME_Relative left;
1984
1985 s->timeout_task = NULL;
1986 left = GNUNET_TIME_absolute_get_remaining (s->timeout);
1987 if (0 != left.rel_value_us)
1988 {
1989 /* not actually our turn yet, but let's at least update
1990 the monitor, it may think we're about to die ... */
1991 notify_session_monitor (s->plugin,
1992 s,
1993 GNUNET_TRANSPORT_SS_UPDATE);
1994 s->timeout_task = GNUNET_SCHEDULER_add_delayed (left,
1995 &client_session_timeout,
1996 s);
1997 return;
1998 }
1999 LOG (TIMEOUT_LOG,
2000 "Session %p was idle for %s, disconnecting\n",
2001 s,
2002 GNUNET_STRINGS_relative_time_to_string (HTTP_CLIENT_SESSION_TIMEOUT,
2003 GNUNET_YES));
2004 GNUNET_assert (GNUNET_OK ==
2005 http_client_plugin_session_disconnect (s->plugin,
2006 s));
2007}
2008
2009
2010/**
2011 * Creates a new outbound session the transport service will use to
2012 * send data to the peer
2013 *
2014 * @param cls the plugin
2015 * @param address the address
2016 * @return the session or NULL of max connections exceeded
2017 */
2018static struct GNUNET_ATS_Session *
2019http_client_plugin_get_session (void *cls,
2020 const struct GNUNET_HELLO_Address *address)
2021{
2022 struct HTTP_Client_Plugin *plugin = cls;
2023 struct GNUNET_ATS_Session *s;
2024 struct sockaddr *sa;
2025 enum GNUNET_NetworkType net_type;
2026 size_t salen = 0;
2027 int res;
2028
2029 GNUNET_assert (NULL != address->address);
2030
2031 /* find existing session */
2032 s = client_lookup_session (plugin, address);
2033 if (NULL != s)
2034 return s;
2035
2036 /* create a new session */
2037 if (plugin->max_requests <= plugin->cur_requests)
2038 {
2039 LOG (GNUNET_ERROR_TYPE_WARNING,
2040 "Maximum number of requests (%u) reached: "
2041 "cannot connect to peer `%s'\n",
2042 plugin->max_requests,
2043 GNUNET_i2s (&address->peer));
2044 return NULL;
2045 }
2046
2047 /* Determine network location */
2048 net_type = GNUNET_NT_UNSPECIFIED;
2049 sa = http_common_socket_from_address (address->address,
2050 address->address_length,
2051 &res);
2052 if (GNUNET_SYSERR == res)
2053 return NULL;
2054 if (GNUNET_YES == res)
2055 {
2056 GNUNET_assert (NULL != sa);
2057 if (AF_INET == sa->sa_family)
2058 {
2059 salen = sizeof(struct sockaddr_in);
2060 }
2061 else if (AF_INET6 == sa->sa_family)
2062 {
2063 salen = sizeof(struct sockaddr_in6);
2064 }
2065 net_type = plugin->env->get_address_type (plugin->env->cls, sa, salen);
2066 GNUNET_free (sa);
2067 }
2068 else if (GNUNET_NO == res)
2069 {
2070 /* Cannot convert to sockaddr -> is external hostname */
2071 net_type = GNUNET_NT_WAN;
2072 }
2073 if (GNUNET_NT_UNSPECIFIED == net_type)
2074 {
2075 GNUNET_break (0);
2076 return NULL;
2077 }
2078
2079 s = GNUNET_new (struct GNUNET_ATS_Session);
2080 s->plugin = plugin;
2081 s->address = GNUNET_HELLO_address_copy (address);
2082 s->scope = net_type;
2083
2084 s->put.state = H_NOT_CONNECTED;
2085 s->timeout = GNUNET_TIME_relative_to_absolute (HTTP_CLIENT_SESSION_TIMEOUT);
2086 s->timeout_task = GNUNET_SCHEDULER_add_delayed (HTTP_CLIENT_SESSION_TIMEOUT,
2087 &client_session_timeout,
2088 s);
2089 LOG (GNUNET_ERROR_TYPE_DEBUG,
2090 "Created new session %p for `%s' address `%s''\n",
2091 s,
2092 http_common_plugin_address_to_string (plugin->protocol,
2093 s->address->address,
2094 s->address->address_length),
2095 GNUNET_i2s (&s->address->peer));
2096
2097 /* add new session */
2098 (void) GNUNET_CONTAINER_multipeermap_put (plugin->sessions,
2099 &s->address->peer,
2100 s,
2101 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2102 /* initiate new connection */
2103 if (GNUNET_SYSERR == client_connect (s))
2104 {
2105 LOG (GNUNET_ERROR_TYPE_ERROR,
2106 "Cannot connect to peer `%s' address `%s''\n",
2107 http_common_plugin_address_to_string (plugin->protocol,
2108 s->address->address,
2109 s->address->address_length),
2110 GNUNET_i2s (&s->address->peer));
2111 client_delete_session (s);
2112 return NULL;
2113 }
2114 notify_session_monitor (plugin,
2115 s,
2116 GNUNET_TRANSPORT_SS_INIT);
2117 notify_session_monitor (plugin,
2118 s,
2119 GNUNET_TRANSPORT_SS_UP); /* or handshake? */
2120 return s;
2121}
2122
2123
2124/**
2125 * Setup http_client plugin
2126 *
2127 * @param plugin the plugin handle
2128 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
2129 */
2130static int
2131client_start (struct HTTP_Client_Plugin *plugin)
2132{
2133 curl_global_init (CURL_GLOBAL_ALL);
2134 plugin->curl_multi_handle = curl_multi_init ();
2135
2136 if (NULL == plugin->curl_multi_handle)
2137 {
2138 LOG (GNUNET_ERROR_TYPE_ERROR,
2139 _ (
2140 "Could not initialize curl multi handle, failed to start %s plugin!\n"),
2141 plugin->name);
2142 return GNUNET_SYSERR;
2143 }
2144 return GNUNET_OK;
2145}
2146
2147
2148/**
2149 * Another peer has suggested an address for this
2150 * peer and transport plugin. Check that this could be a valid
2151 * address. If so, consider adding it to the list
2152 * of addresses.
2153 *
2154 * @param cls closure with the `struct Plugin`
2155 * @param addr pointer to the address
2156 * @param addrlen length of @a addr
2157 * @return #GNUNET_OK if this is a plausible address for this peer
2158 * and transport; always returns #GNUNET_NO (this is the client!)
2159 */
2160static int
2161http_client_plugin_address_suggested (void *cls,
2162 const void *addr,
2163 size_t addrlen)
2164{
2165 /* A HTTP/S client does not have any valid address so:*/
2166 return GNUNET_NO;
2167}
2168
2169
2170/**
2171 * Exit point from the plugin.
2172 *
2173 * @param cls api as closure
2174 * @return NULL
2175 */
2176void *
2177LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
2178{
2179 struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
2180 struct HTTP_Client_Plugin *plugin = api->cls;
2181
2182 if (NULL == api->cls)
2183 {
2184 /* Stub shutdown */
2185 GNUNET_free (api);
2186 return NULL;
2187 }
2188 LOG (GNUNET_ERROR_TYPE_DEBUG,
2189 _ ("Shutting down plugin `%s'\n"),
2190 plugin->name);
2191 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
2192 &destroy_session_cb,
2193 plugin);
2194 if (NULL != plugin->client_perform_task)
2195 {
2196 GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
2197 plugin->client_perform_task = NULL;
2198 }
2199 if (NULL != plugin->curl_multi_handle)
2200 {
2201 curl_multi_cleanup (plugin->curl_multi_handle);
2202 plugin->curl_multi_handle = NULL;
2203 }
2204 curl_global_cleanup ();
2205 LOG (GNUNET_ERROR_TYPE_DEBUG,
2206 _ ("Shutdown for plugin `%s' complete\n"),
2207 plugin->name);
2208 GNUNET_CONTAINER_multipeermap_destroy (plugin->sessions);
2209 GNUNET_free (plugin->proxy_hostname);
2210 GNUNET_free (plugin->proxy_username);
2211 GNUNET_free (plugin->proxy_password);
2212 GNUNET_free (plugin);
2213 GNUNET_free (api);
2214 return NULL;
2215}
2216
2217
2218/**
2219 * Configure plugin
2220 *
2221 * @param plugin the plugin handle
2222 * @return #GNUNET_OK on success, #GNUNET_SYSERR on failure
2223 */
2224static int
2225client_configure_plugin (struct HTTP_Client_Plugin *plugin)
2226{
2227 unsigned long long max_requests;
2228 char *proxy_type;
2229
2230 /* Optional parameters */
2231 if (GNUNET_OK !=
2232 GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg,
2233 plugin->name,
2234 "MAX_CONNECTIONS",
2235 &max_requests))
2236 max_requests = 128;
2237 plugin->max_requests = max_requests;
2238
2239 LOG (GNUNET_ERROR_TYPE_DEBUG,
2240 _ ("Maximum number of requests is %u\n"),
2241 plugin->max_requests);
2242
2243 /* Read proxy configuration */
2244 if (GNUNET_OK ==
2245 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2246 plugin->name,
2247 "PROXY",
2248 &plugin->proxy_hostname))
2249 {
2250 LOG (GNUNET_ERROR_TYPE_DEBUG,
2251 "Found proxy host: `%s'\n",
2252 plugin->proxy_hostname);
2253 /* proxy username */
2254 if (GNUNET_OK ==
2255 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2256 plugin->name,
2257 "PROXY_USERNAME",
2258 &plugin->proxy_username))
2259 {
2260 LOG (GNUNET_ERROR_TYPE_DEBUG,
2261 "Found proxy username name: `%s'\n",
2262 plugin->proxy_username);
2263 }
2264
2265 /* proxy password */
2266 if (GNUNET_OK ==
2267 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2268 plugin->name,
2269 "PROXY_PASSWORD",
2270 &plugin->proxy_password))
2271 {
2272 LOG (GNUNET_ERROR_TYPE_DEBUG,
2273 "Found proxy password name: `%s'\n",
2274 plugin->proxy_password);
2275 }
2276
2277 /* proxy type */
2278 if (GNUNET_OK ==
2279 GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
2280 plugin->name,
2281 "PROXY_TYPE",
2282 &proxy_type))
2283 {
2284 GNUNET_STRINGS_utf8_toupper (proxy_type, proxy_type);
2285
2286 if (0 == strcmp (proxy_type, "HTTP"))
2287 plugin->proxytype = CURLPROXY_HTTP;
2288 else if (0 == strcmp (proxy_type, "SOCKS4"))
2289 plugin->proxytype = CURLPROXY_SOCKS4;
2290 else if (0 == strcmp (proxy_type, "SOCKS5"))
2291 plugin->proxytype = CURLPROXY_SOCKS5;
2292 else if (0 == strcmp (proxy_type, "SOCKS4A"))
2293 plugin->proxytype = CURLPROXY_SOCKS4A;
2294 else if (0 == strcmp (proxy_type, "SOCKS5_HOSTNAME "))
2295 plugin->proxytype = CURLPROXY_SOCKS5_HOSTNAME;
2296 else
2297 {
2298 LOG (GNUNET_ERROR_TYPE_ERROR,
2299 _ (
2300 "Invalid proxy type: `%s', disabling proxy! Check configuration!\n"),
2301 proxy_type);
2302
2303 GNUNET_free (proxy_type);
2304 GNUNET_free (plugin->proxy_hostname);
2305 plugin->proxy_hostname = NULL;
2306 GNUNET_free (plugin->proxy_username);
2307 plugin->proxy_username = NULL;
2308 GNUNET_free (plugin->proxy_password);
2309 plugin->proxy_password = NULL;
2310
2311 return GNUNET_SYSERR;
2312 }
2313
2314 LOG (GNUNET_ERROR_TYPE_DEBUG,
2315 "Found proxy type: `%s'\n",
2316 proxy_type);
2317 }
2318
2319 /* proxy http tunneling */
2320 plugin->proxy_use_httpproxytunnel
2321 = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2322 plugin->name,
2323 "PROXY_HTTP_TUNNELING");
2324 if (GNUNET_SYSERR == plugin->proxy_use_httpproxytunnel)
2325 plugin->proxy_use_httpproxytunnel = GNUNET_NO;
2326
2327 GNUNET_free (proxy_type);
2328 }
2329
2330 /* Should we emulate an XHR client for testing? */
2331 plugin->emulate_xhr
2332 = GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg,
2333 plugin->name,
2334 "EMULATE_XHR");
2335 return GNUNET_OK;
2336}
2337
2338
2339/**
2340 * Function to convert an address to a human-readable string.
2341 *
2342 * @param cls closure
2343 * @param addr address to convert
2344 * @param addrlen address length
2345 * @return res string if conversion was successful, NULL otherwise
2346 */
2347static const char *
2348http_client_plugin_address_to_string (void *cls,
2349 const void *addr,
2350 size_t addrlen)
2351{
2352 return http_common_plugin_address_to_string (PLUGIN_NAME,
2353 addr,
2354 addrlen);
2355}
2356
2357
2358/**
2359 * Function that will be called whenever the transport service wants to
2360 * notify the plugin that a session is still active and in use and
2361 * therefore the session timeout for this session has to be updated
2362 *
2363 * @param cls closure
2364 * @param peer which peer was the session for
2365 * @param session which session is being updated
2366 */
2367static void
2368http_client_plugin_update_session_timeout (void *cls,
2369 const struct
2370 GNUNET_PeerIdentity *peer,
2371 struct GNUNET_ATS_Session *session)
2372{
2373 client_reschedule_session_timeout (session);
2374}
2375
2376
2377/**
2378 * Function that will be called whenever the transport service wants to
2379 * notify the plugin that the inbound quota changed and that the plugin
2380 * should update it's delay for the next receive value
2381 *
2382 * @param cls closure
2383 * @param peer which peer was the session for
2384 * @param s which session is being updated
2385 * @param delay new delay to use for receiving
2386 */
2387static void
2388http_client_plugin_update_inbound_delay (void *cls,
2389 const struct GNUNET_PeerIdentity *peer,
2390 struct GNUNET_ATS_Session *s,
2391 struct GNUNET_TIME_Relative delay)
2392{
2393 s->next_receive = GNUNET_TIME_relative_to_absolute (delay);
2394 LOG (GNUNET_ERROR_TYPE_DEBUG,
2395 "New inbound delay %s\n",
2396 GNUNET_STRINGS_relative_time_to_string (delay,
2397 GNUNET_NO));
2398 if (s->recv_wakeup_task != NULL)
2399 {
2400 GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
2401 s->recv_wakeup_task
2402 = GNUNET_SCHEDULER_add_delayed (delay,
2403 &client_wake_up,
2404 s);
2405 }
2406}
2407
2408
2409/**
2410 * Return information about the given session to the
2411 * monitor callback.
2412 *
2413 * @param cls the `struct Plugin` with the monitor callback (`sic`)
2414 * @param peer peer we send information about
2415 * @param value our `struct GNUNET_ATS_Session` to send information about
2416 * @return #GNUNET_OK (continue to iterate)
2417 */
2418static int
2419send_session_info_iter (void *cls,
2420 const struct GNUNET_PeerIdentity *peer,
2421 void *value)
2422{
2423 struct HTTP_Client_Plugin *plugin = cls;
2424 struct GNUNET_ATS_Session *session = value;
2425
2426 notify_session_monitor (plugin,
2427 session,
2428 GNUNET_TRANSPORT_SS_INIT);
2429 notify_session_monitor (plugin,
2430 session,
2431 GNUNET_TRANSPORT_SS_UP); /* FIXME: or handshake? */
2432 return GNUNET_OK;
2433}
2434
2435
2436/**
2437 * Begin monitoring sessions of a plugin. There can only
2438 * be one active monitor per plugin (i.e. if there are
2439 * multiple monitors, the transport service needs to
2440 * multiplex the generated events over all of them).
2441 *
2442 * @param cls closure of the plugin
2443 * @param sic callback to invoke, NULL to disable monitor;
2444 * plugin will being by iterating over all active
2445 * sessions immediately and then enter monitor mode
2446 * @param sic_cls closure for @a sic
2447 */
2448static void
2449http_client_plugin_setup_monitor (void *cls,
2450 GNUNET_TRANSPORT_SessionInfoCallback sic,
2451 void *sic_cls)
2452{
2453 struct HTTP_Client_Plugin *plugin = cls;
2454
2455 plugin->sic = sic;
2456 plugin->sic_cls = sic_cls;
2457 if (NULL != sic)
2458 {
2459 GNUNET_CONTAINER_multipeermap_iterate (plugin->sessions,
2460 &send_session_info_iter,
2461 plugin);
2462 /* signal end of first iteration */
2463 sic (sic_cls, NULL, NULL);
2464 }
2465}
2466
2467
2468/**
2469 * Entry point for the plugin.
2470 */
2471void *
2472LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
2473{
2474 struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
2475 struct GNUNET_TRANSPORT_PluginFunctions *api;
2476 struct HTTP_Client_Plugin *plugin;
2477
2478 if (NULL == env->receive)
2479 {
2480 /* run in 'stub' mode (i.e. as part of gnunet-peerinfo), don't fully
2481 initialize the plugin or the API */
2482 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2483 api->cls = NULL;
2484 api->address_to_string = &http_client_plugin_address_to_string;
2485 api->string_to_address = &http_common_plugin_string_to_address;
2486 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
2487 return api;
2488 }
2489
2490 plugin = GNUNET_new (struct HTTP_Client_Plugin);
2491 plugin->env = env;
2492 plugin->sessions = GNUNET_CONTAINER_multipeermap_create (128,
2493 GNUNET_YES);
2494 api = GNUNET_new (struct GNUNET_TRANSPORT_PluginFunctions);
2495 api->cls = plugin;
2496 api->send = &http_client_plugin_send;
2497 api->disconnect_session = &http_client_plugin_session_disconnect;
2498 api->query_keepalive_factor = &http_client_query_keepalive_factor;
2499 api->disconnect_peer = &http_client_plugin_peer_disconnect;
2500 api->check_address = &http_client_plugin_address_suggested;
2501 api->get_session = &http_client_plugin_get_session;
2502 api->address_to_string = &http_client_plugin_address_to_string;
2503 api->string_to_address = &http_common_plugin_string_to_address;
2504 api->address_pretty_printer = &http_common_plugin_address_pretty_printer;
2505 api->get_network = &http_client_plugin_get_network;
2506 api->get_network_for_address = &http_client_plugin_get_network_for_address;
2507 api->update_session_timeout = &http_client_plugin_update_session_timeout;
2508 api->update_inbound_delay = &http_client_plugin_update_inbound_delay;
2509 api->setup_monitor = &http_client_plugin_setup_monitor;
2510#if BUILD_HTTPS
2511 plugin->name = "transport-https_client";
2512 plugin->protocol = "https";
2513#else
2514 plugin->name = "transport-http_client";
2515 plugin->protocol = "http";
2516#endif
2517 plugin->last_tag = 1;
2518
2519 if (GNUNET_SYSERR == client_configure_plugin (plugin))
2520 {
2521 LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
2522 return NULL;
2523 }
2524
2525 /* Start client */
2526 if (GNUNET_SYSERR == client_start (plugin))
2527 {
2528 LIBGNUNET_PLUGIN_TRANSPORT_DONE (api);
2529 return NULL;
2530 }
2531 return api;
2532}
2533
2534
2535/* 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 8606b353b..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_MALLINFO
33#include <malloc.h>
34#include "gauger.h"
35#endif
36
37
38/* ******************* access control ******************** */
39
40/**
41 * Check if the given IP address is in the list of IP addresses.
42 *
43 * @param list a list of networks
44 * @param add the IP to check (in network byte order)
45 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
46 */
47static int
48check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
49 const struct in_addr *add)
50{
51 unsigned int i;
52
53 if (NULL == list)
54 return GNUNET_NO;
55 i = 0;
56 while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
57 {
58 if ((add->s_addr & list[i].netmask.s_addr) ==
59 (list[i].network.s_addr & list[i].netmask.s_addr))
60 return GNUNET_YES;
61 i++;
62 }
63 return GNUNET_NO;
64}
65
66
67/**
68 * Check if the given IP address is in the list of IP addresses.
69 *
70 * @param list a list of networks
71 * @param ip the IP to check (in network byte order)
72 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
73 */
74static int
75check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
76 const struct in6_addr *ip)
77{
78 unsigned int i;
79 unsigned int j;
80 struct in6_addr zero;
81
82 if (NULL == list)
83 return GNUNET_NO;
84 memset (&zero, 0, sizeof(struct in6_addr));
85 i = 0;
86NEXT:
87 while (0 != memcmp (&zero, &list[i].network, sizeof(struct in6_addr)))
88 {
89 for (j = 0; j < sizeof(struct in6_addr) / sizeof(int); j++)
90 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
91 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
92 {
93 i++;
94 goto NEXT;
95 }
96 return GNUNET_YES;
97 }
98 return GNUNET_NO;
99}
100
101
102/* ****************** service struct ****************** */
103
104
105/**
106 * Context for "service_task".
107 */
108struct LEGACY_SERVICE_Context
109{
110 /**
111 * Our configuration.
112 */
113 const struct GNUNET_CONFIGURATION_Handle *cfg;
114
115 /**
116 * Handle for the server.
117 */
118 struct GNUNET_SERVER_Handle *server;
119
120 /**
121 * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
122 * listen sockets.
123 */
124 struct sockaddr **addrs;
125
126 /**
127 * Name of our service.
128 */
129 const char *service_name;
130
131 /**
132 * Main service-specific task to run.
133 */
134 LEGACY_SERVICE_Main task;
135
136 /**
137 * Closure for @e task.
138 */
139 void *task_cls;
140
141 /**
142 * IPv4 addresses that are not allowed to connect.
143 */
144 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
145
146 /**
147 * IPv6 addresses that are not allowed to connect.
148 */
149 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
150
151 /**
152 * IPv4 addresses that are allowed to connect (if not
153 * set, all are allowed).
154 */
155 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
156
157 /**
158 * IPv6 addresses that are allowed to connect (if not
159 * set, all are allowed).
160 */
161 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
162
163 /**
164 * My (default) message handlers. Adjusted copy
165 * of "defhandlers".
166 */
167 struct GNUNET_SERVER_MessageHandler *my_handlers;
168
169 /**
170 * Array of the lengths of the entries in addrs.
171 */
172 socklen_t *addrlens;
173
174 /**
175 * NULL-terminated array of listen sockets we should take over.
176 */
177 struct GNUNET_NETWORK_Handle **lsocks;
178
179 /**
180 * Task ID of the shutdown task.
181 */
182 struct GNUNET_SCHEDULER_Task *shutdown_task;
183
184 /**
185 * Idle timeout for server.
186 */
187 struct GNUNET_TIME_Relative timeout;
188
189 /**
190 * Overall success/failure of the service start.
191 */
192 int ret;
193
194 /**
195 * If we are daemonizing, this FD is set to the
196 * pipe to the parent. Send '.' if we started
197 * ok, '!' if not. -1 if we are not daemonizing.
198 */
199 int ready_confirm_fd;
200
201 /**
202 * Do we close connections if we receive messages
203 * for which we have no handler?
204 */
205 int require_found;
206
207 /**
208 * Do we require a matching UID for UNIX domain socket connections?
209 * #GNUNET_NO means that the UID does not have to match (however,
210 * @e match_gid may still impose other access control checks).
211 */
212 int match_uid;
213
214 /**
215 * Do we require a matching GID for UNIX domain socket connections?
216 * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
217 * checking that the client's UID is in our group OR that the
218 * client's GID is our GID. If both "match_gid" and @e match_uid are
219 * #GNUNET_NO, all users on the local system have access.
220 */
221 int match_gid;
222
223 /**
224 * Our options.
225 */
226 enum LEGACY_SERVICE_Options options;
227};
228
229
230/* ****************** 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_MALLINFO
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 mallinfo mi;
1466
1467 mi = mallinfo ();
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_MALLINFO
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 mallinfo mi;
1615
1616 mi = mallinfo ();
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 11306fd6a..000000000
--- a/src/transport/test_transport_api2_tcp_node1.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]
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 = 192.168.15.1: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[communicator-udp]
20BINARY = gnunet-communicator-udp
21BINDTO = 192.168.15.1:60002
22DISABLE_V6 = YES
23IMMEDIATE_START = YES
24UNIXPATH = $GNUNET_RUNTIME_DIR/udp-comm-p1.sock
25
26[peerstore]
27IMMEDIATE_START = YES
28
29#[transport]
30#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_plugin_cmd_simple_send.c b/src/transport/test_transport_plugin_cmd_simple_send.c
deleted file mode 100644
index 07255a1a5..000000000
--- a/src/transport/test_transport_plugin_cmd_simple_send.c
+++ /dev/null
@@ -1,229 +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_util_lib.h"
29#include "gnunet_transport_application_service.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#define BASE_DIR "testdir"
39
40/**
41 * The name for a specific test environment directory.
42 *
43 */
44char *testdir;
45
46/**
47 * The name for the configuration file of the specific node.
48 *
49 */
50char *cfgname;
51
52/**
53 * Flag indicating if all peers have been started.
54 *
55 */
56unsigned int are_all_peers_started;
57
58/**
59 * Flag indicating a received message.
60 */
61unsigned int message_received;
62
63
64/**
65 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
66 * received.
67 *
68 */
69static int
70check_test (void *cls,
71 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
72{
73 return GNUNET_OK;
74}
75
76
77/**
78 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
79 * being received.
80 *
81 */
82static void
83handle_test (void *cls,
84 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
85{
86 message_received = GNUNET_YES;
87}
88
89
90/**
91 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
92 *
93 */
94static void
95all_peers_started ()
96{
97 are_all_peers_started = GNUNET_YES;
98}
99
100
101/**
102 * Function to start a local test case.
103 *
104 * @param write_message Callback to send a message to the master loop.
105 * @param router_ip Global address of the network namespace.
106 * @param node_ip Local address of a node i a network namespace.
107 * @param m The number of the node in a network namespace.
108 * @param n The number of the network namespace.
109 * @param local_m The number of nodes in a network namespace.
110 */
111static void
112start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
113 char *node_ip,
114 char *m,
115 char *n,
116 char *local_m)
117{
118
119 GNUNET_asprintf (&cfgname,
120 "test_transport_api2_tcp_node%s.conf",
121 "1");
122
123 LOG (GNUNET_ERROR_TYPE_ERROR,
124 "plugin cfgname: %s\n",
125 cfgname);
126
127 LOG (GNUNET_ERROR_TYPE_ERROR,
128 "node ip: %s\n",
129 node_ip);
130
131 LOG (GNUNET_ERROR_TYPE_ERROR,
132 "m: %s n: %s\n",
133 m,
134 n);
135
136 GNUNET_asprintf (&testdir,
137 "%s%s%s",
138 BASE_DIR,
139 m,
140 n);
141
142 struct GNUNET_MQ_MessageHandler handlers[] = {
143 GNUNET_MQ_hd_var_size (test,
144 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
145 struct GNUNET_TRANSPORT_TESTING_TestMessage,
146 NULL),
147 GNUNET_MQ_handler_end ()
148 };
149
150 struct GNUNET_TESTING_Command commands[] = {
151 GNUNET_TESTING_cmd_system_create ("system-create",
152 testdir),
153 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
154 "system-create",
155 m,
156 n,
157 local_m,
158 node_ip,
159 handlers,
160 cfgname),
161 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
162 write_message),
163 GNUNET_TESTING_cmd_block_until_all_peers_started ("block",
164 &are_all_peers_started),
165 GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
166 "start-peer",
167 "system-create",
168 (atoi (n) - 1) * atoi (local_m) + atoi (
169 m)),
170 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
171 m,
172 n,
173 (atoi (n) - 1) * atoi (local_m) + atoi (
174 m),
175 "start-peer"),
176 GNUNET_TESTING_cmd_block_until_external_trigger ("block-receive",
177 &message_received),
178 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
179 "start-peer"),
180 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
181 "system-create"),
182 GNUNET_TESTING_cmd_local_test_finished ("local-test-finished",
183 write_message)
184 };
185
186 GNUNET_TESTING_run (NULL,
187 commands,
188 GNUNET_TIME_UNIT_FOREVER_REL);
189
190}
191
192
193/**
194 * Entry point for the plugin.
195 *
196 * @param cls NULL
197 * @return the exported block API
198 */
199void *
200libgnunet_test_transport_plugin_cmd_simple_send_init (void *cls)
201{
202 struct GNUNET_TESTING_PluginFunctions *api;
203
204 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
205 api->start_testcase = &start_testcase;
206 api->all_peers_started = &all_peers_started;
207 return api;
208}
209
210
211/**
212 * Exit point from the plugin.
213 *
214 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
215 * @return NULL
216 */
217void *
218libgnunet_test_transport_plugin_cmd_simple_send_done (void *cls)
219{
220 struct GNUNET_TESTING_PluginFunctions *api = cls;
221
222 GNUNET_free (api);
223 GNUNET_free (testdir);
224 GNUNET_free (cfgname);
225 return NULL;
226}
227
228
229/* end of plugin_cmd_simple_send.c */
diff --git a/src/transport/test_transport_plugin_cmd_simple_send_v2.c b/src/transport/test_transport_plugin_cmd_simple_send_v2.c
deleted file mode 100644
index c79b5c7e2..000000000
--- a/src/transport/test_transport_plugin_cmd_simple_send_v2.c
+++ /dev/null
@@ -1,234 +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_util_lib.h"
29#include "gnunet_transport_application_service.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#define BASE_DIR "testdir"
39
40#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
41
42/**
43 * The name for a specific test environment directory.
44 *
45 */
46char *testdir;
47
48/**
49 * The name for the configuration file of the specific node.
50 *
51 */
52char *cfgname;
53
54/**
55 * Flag indicating if all peers have been started.
56 *
57 */
58unsigned int are_all_peers_started;
59
60/**
61 * Flag indicating a received message.
62 */
63unsigned int message_received;
64
65
66/**
67 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
68 * received.
69 *
70 */
71static int
72check_test (void *cls,
73 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
74{
75 return GNUNET_OK;
76}
77
78
79/**
80 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
81 * being received.
82 *
83 */
84static void
85handle_test (void *cls,
86 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
87{
88 message_received = GNUNET_YES;
89}
90
91
92/**
93 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
94 *
95 */
96static void
97all_peers_started ()
98{
99 are_all_peers_started = GNUNET_YES;
100}
101
102
103/**
104 * Function to start a local test case.
105 *
106 * @param write_message Callback to send a message to the master loop.
107 * @param router_ip Global address of the network namespace.
108 * @param node_ip Local address of a node i a network namespace.
109 * @param m The number of the node in a network namespace.
110 * @param n The number of the network namespace.
111 * @param local_m The number of nodes in a network namespace.
112 */
113static void
114start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
115 char *node_ip,
116 char *m,
117 char *n,
118 char *local_m)
119{
120
121 unsigned int n_int, m_int, local_m_int, num;
122
123 struct GNUNET_TESTING_NetjailTopology *topology =
124 GNUNET_TESTING_get_topo_from_file (TOPOLOGY_CONFIG);
125
126 sscanf (m, "%u", &m_int);
127 sscanf (n, "%u", &n_int);
128 sscanf (local_m, "%u", &local_m_int);
129
130
131 if (0 == m_int)
132 num = n_int;
133 else
134 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
135
136 GNUNET_asprintf (&cfgname,
137 "test_transport_api2_tcp_node1.conf");
138
139 LOG (GNUNET_ERROR_TYPE_ERROR,
140 "plugin cfgname: %s\n",
141 cfgname);
142
143 LOG (GNUNET_ERROR_TYPE_ERROR,
144 "node ip: %s\n",
145 node_ip);
146
147 GNUNET_asprintf (&testdir,
148 "%s%s%s",
149 BASE_DIR,
150 m,
151 n);
152
153 struct GNUNET_MQ_MessageHandler handlers[] = {
154 GNUNET_MQ_hd_var_size (test,
155 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
156 struct GNUNET_TRANSPORT_TESTING_TestMessage,
157 NULL),
158 GNUNET_MQ_handler_end ()
159 };
160
161 struct GNUNET_TESTING_Command commands[] = {
162 GNUNET_TESTING_cmd_system_create ("system-create",
163 testdir),
164 GNUNET_TRANSPORT_cmd_start_peer_v2 ("start-peer",
165 "system-create",
166 num,
167 node_ip,
168 handlers,
169 cfgname),
170 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
171 write_message),
172 GNUNET_TESTING_cmd_block_until_all_peers_started ("block",
173 &are_all_peers_started),
174 GNUNET_TRANSPORT_cmd_connect_peers_v2 ("connect-peers",
175 "start-peer",
176 "system-create",
177 num),
178 GNUNET_TRANSPORT_cmd_send_simple_v2 ("send-simple",
179 "start-peer",
180 num),
181 GNUNET_TESTING_cmd_block_until_external_trigger ("block-receive",
182 &message_received),
183 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
184 "start-peer"),
185 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
186 "system-create"),
187 GNUNET_TESTING_cmd_local_test_finished ("local-test-finished",
188 write_message)
189 };
190
191 GNUNET_TESTING_run (NULL,
192 commands,
193 GNUNET_TIME_UNIT_FOREVER_REL);
194
195}
196
197
198/**
199 * Entry point for the plugin.
200 *
201 * @param cls NULL
202 * @return the exported block API
203 */
204void *
205libgnunet_test_transport_plugin_cmd_simple_send_init (void *cls)
206{
207 struct GNUNET_TESTING_PluginFunctions *api;
208
209 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
210 api->start_testcase = &start_testcase;
211 api->all_peers_started = &all_peers_started;
212 return api;
213}
214
215
216/**
217 * Exit point from the plugin.
218 *
219 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
220 * @return NULL
221 */
222void *
223libgnunet_test_transport_plugin_cmd_simple_send_done (void *cls)
224{
225 struct GNUNET_TESTING_PluginFunctions *api = cls;
226
227 GNUNET_free (api);
228 GNUNET_free (testdir);
229 GNUNET_free (cfgname);
230 return NULL;
231}
232
233
234/* end of plugin_cmd_simple_send.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 90e474aea..000000000
--- a/src/transport/test_transport_plugin_cmd_udp_backchannel.c
+++ /dev/null
@@ -1,242 +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_util_lib.h"
29#include "gnunet_transport_application_service.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#define BASE_DIR "testdir"
39
40#define TOPOLOGY_CONFIG "test_transport_udp_backchannel_topo.conf"
41
42/**
43 * The name for a specific test environment directory.
44 *
45 */
46char *testdir;
47
48/**
49 * The name for the configuration file of the specific node.
50 *
51 */
52char *cfgname;
53
54/**
55 * Flag indicating if all peers have been started.
56 *
57 */
58unsigned int are_all_peers_started;
59
60/**
61 * Flag indicating a received message.
62 */
63unsigned int message_received;
64
65
66/**
67 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
68 * received.
69 *
70 */
71static int
72check_test (void *cls,
73 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
74{
75 return GNUNET_OK;
76}
77
78
79/**
80 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
81 * being received.
82 *
83 */
84static void
85handle_test (void *cls,
86 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
87{
88 message_received = GNUNET_YES;
89}
90
91
92/**
93 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
94 *
95 */
96static void
97all_peers_started ()
98{
99 are_all_peers_started = GNUNET_YES;
100 LOG (GNUNET_ERROR_TYPE_ERROR,
101 "setting are_all_peers_started: %d\n",
102 are_all_peers_started);
103}
104
105
106/**
107 * Function to start a local test case.
108 *
109 * @param write_message Callback to send a message to the master loop.
110 * @param router_ip Global address of the network namespace.
111 * @param node_ip Local address of a node i a network namespace.
112 * @param m The number of the node in a network namespace.
113 * @param n The number of the network namespace.
114 * @param local_m The number of nodes in a network namespace.
115 */
116static void
117start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
118 char *node_ip,
119 char *m,
120 char *n,
121 char *local_m)
122{
123
124 unsigned int n_int, m_int, local_m_int, num;
125
126 struct GNUNET_TESTING_NetjailTopology *topology =
127 GNUNET_TESTING_get_topo_from_file (TOPOLOGY_CONFIG);
128
129 sscanf (m, "%u", &m_int);
130 sscanf (n, "%u", &n_int);
131 sscanf (local_m, "%u", &local_m_int);
132
133
134 if (0 == n_int)
135 num = m_int;
136 else
137 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
138
139 GNUNET_asprintf (&cfgname,
140 "test_transport_api2_tcp_node1.conf");
141
142 LOG (GNUNET_ERROR_TYPE_ERROR,
143 "plugin cfgname: %s\n",
144 cfgname);
145
146 LOG (GNUNET_ERROR_TYPE_ERROR,
147 "node ip: %s\n",
148 node_ip);
149
150 GNUNET_asprintf (&testdir,
151 "%s%s%s",
152 BASE_DIR,
153 m,
154 n);
155
156 struct GNUNET_MQ_MessageHandler handlers[] = {
157 GNUNET_MQ_hd_var_size (test,
158 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
159 struct GNUNET_TRANSPORT_TESTING_TestMessage,
160 NULL),
161 GNUNET_MQ_handler_end ()
162 };
163
164 struct GNUNET_TESTING_Command commands[] = {
165 GNUNET_TESTING_cmd_system_create ("system-create",
166 testdir),
167 GNUNET_TRANSPORT_cmd_start_peer_v3 ("start-peer",
168 "system-create",
169 num,
170 node_ip,
171 handlers,
172 cfgname),
173 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
174 write_message),
175 GNUNET_TESTING_cmd_block_until_all_peers_started ("block",
176 &are_all_peers_started),
177 GNUNET_TRANSPORT_cmd_connect_peers_v3 ("connect-peers",
178 "start-peer",
179 "system-create",
180 num,
181 topology),
182 GNUNET_TRANSPORT_cmd_send_simple_v2 ("send-simple",
183 "start-peer",
184 num),
185 GNUNET_TESTING_cmd_block_until_external_trigger ("block-receive",
186 &message_received),
187 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
188 "start-peer"),
189 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
190 "system-create"),
191 GNUNET_TESTING_cmd_local_test_finished ("local-test-finished",
192 write_message)
193 };
194
195 GNUNET_TESTING_run (NULL,
196 commands,
197 GNUNET_TIME_UNIT_FOREVER_REL);
198
199}
200
201
202/**
203 * Entry point for the plugin.
204 *
205 * @param cls NULL
206 * @return the exported block API
207 */
208void *
209libgnunet_test_transport_plugin_cmd_udp_backchannel_init (void *cls)
210{
211 struct GNUNET_TESTING_PluginFunctions *api;
212
213 GNUNET_log_setup ("udp-backchannel",
214 "DEBUG",
215 NULL);
216
217 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
218 api->start_testcase = &start_testcase;
219 api->all_peers_started = &all_peers_started;
220 return api;
221}
222
223
224/**
225 * Exit point from the plugin.
226 *
227 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
228 * @return NULL
229 */
230void *
231libgnunet_test_transport_plugin_cmd_udp_backchannel_done (void *cls)
232{
233 struct GNUNET_TESTING_PluginFunctions *api = cls;
234
235 GNUNET_free (api);
236 GNUNET_free (testdir);
237 GNUNET_free (cfgname);
238 return NULL;
239}
240
241
242/* end of plugin_cmd_simple_send.c */
diff --git a/src/transport/test_transport_port_forward.c b/src/transport/test_transport_port_forward.c
deleted file mode 100644
index d3233c2da..000000000
--- a/src/transport/test_transport_port_forward.c
+++ /dev/null
@@ -1,85 +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_port_forward.c
23 * @brief Test case executing a script which sends a test UDP message from a nated peer
24 * to a global known peer. There is a tcp port forwarding in place towards the
25 * natted peer to test the backchannel functionality of the TNG service.
26 * @author t3sserakt
27 */
28#include "platform.h"
29#include "gnunet_testing_ng_lib.h"
30#include "gnunet_util_lib.h"
31
32#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
33
34/**
35 * Return value of the test.
36 *
37 */
38static unsigned int rv = 0;
39
40
41/**
42 * Main function to run the test cases.
43 *
44 * @param cls not used.
45 *
46 */
47static void
48run (void *cls)
49{
50 const char *topology_config = "test_topology_port_forward.conf";
51
52 struct GNUNET_TESTING_Command commands[] = {
53 GNUNET_TESTING_cmd_netjail_start_v2 ("netjail-start",
54 topology_config),
55 GNUNET_TESTING_cmd_netjail_start_testing_system_v2 ("netjail-start-testbed",
56 topology_config,
57 &rv),
58 GNUNET_TESTING_cmd_stop_testing_system_v2 ("stop-testbed",
59 "netjail-start-testbed",
60 topology_config),
61 GNUNET_TESTING_cmd_netjail_stop_v2 ("netjail-stop",
62 topology_config),
63 GNUNET_TESTING_cmd_end ()
64 };
65
66 GNUNET_TESTING_run (NULL,
67 commands,
68 TIMEOUT);
69}
70
71
72int
73main (int argc,
74 char *const *argv)
75{
76 GNUNET_log_setup ("test-netjail",
77 "DEBUG",
78 NULL);
79 GNUNET_SCHEDULER_run (&run,
80 NULL);
81
82 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
83 "Test finished!\n");
84 return rv;
85}
diff --git a/src/transport/test_transport_simple_send.c b/src/transport/test_transport_simple_send.c
deleted file mode 100644
index 924990d0a..000000000
--- a/src/transport/test_transport_simple_send.c
+++ /dev/null
@@ -1,86 +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_api_cmd_simple_send.c
23 * @brief Test case executing a script which sends a test message between two peers.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_util_lib.h"
29
30#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
31
32/**
33 * Return value of the test.
34 *
35 */
36static unsigned int rv = 0;
37
38
39/**
40 * Main function to run the test cases.
41 *
42 * @param cls not used.
43 *
44 */
45static void
46run (void *cls)
47{
48 struct GNUNET_TESTING_Command commands[] = {
49 GNUNET_TESTING_cmd_netjail_start ("netjail-start",
50 "2",
51 "1"),
52 GNUNET_TESTING_cmd_netjail_start_testing_system ("netjail-start-testbed",
53 "2",
54 "1",
55 "libgnunet_test_transport_plugin_cmd_simple_send",
56 &rv),
57 GNUNET_TESTING_cmd_stop_testing_system ("stop-testbed",
58 "netjail-start-testbed",
59 "2",
60 "1"),
61 GNUNET_TESTING_cmd_netjail_stop ("netjail-stop",
62 "2",
63 "1"),
64 GNUNET_TESTING_cmd_end ()
65 };
66
67 GNUNET_TESTING_run (NULL,
68 commands,
69 TIMEOUT);
70}
71
72
73int
74main (int argc,
75 char *const *argv)
76{
77 GNUNET_log_setup ("test-netjail",
78 "DEBUG",
79 NULL);
80 GNUNET_SCHEDULER_run (&run,
81 NULL);
82
83 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
84 "Test finished!\n");
85 return rv;
86}
diff --git a/src/transport/test_transport_simple_send.sh b/src/transport/test_transport_simple_send.sh
deleted file mode 100755
index 25d5b6797..000000000
--- a/src/transport/test_transport_simple_send.sh
+++ /dev/null
@@ -1,2 +0,0 @@
1#!/bin/bash
2exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_simple_send"
diff --git a/src/transport/test_transport_simple_send_v2.c b/src/transport/test_transport_simple_send_v2.c
deleted file mode 100644
index aeac1bfb6..000000000
--- a/src/transport/test_transport_simple_send_v2.c
+++ /dev/null
@@ -1,83 +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_api_cmd_simple_send.c
23 * @brief Test case executing a script which sends a test message between two peers.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_util_lib.h"
29
30#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
31
32#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
33
34/**
35 * Return value of the test.
36 *
37 */
38static unsigned int rv = 0;
39
40
41/**
42 * Main function to run the test cases.
43 *
44 * @param cls not used.
45 *
46 */
47static void
48run (void *cls)
49{
50 struct GNUNET_TESTING_Command commands[] = {
51 GNUNET_TESTING_cmd_netjail_start_v2 ("netjail-start",
52 TOPOLOGY_CONFIG),
53 GNUNET_TESTING_cmd_netjail_start_testing_system_v2 ("netjail-start-testbed",
54 TOPOLOGY_CONFIG,
55 &rv),
56 GNUNET_TESTING_cmd_stop_testing_system_v2 ("stop-testbed",
57 "netjail-start-testbed",
58 TOPOLOGY_CONFIG),
59 GNUNET_TESTING_cmd_netjail_stop_v2 ("netjail-stop",
60 TOPOLOGY_CONFIG),
61 GNUNET_TESTING_cmd_end ()
62 };
63
64 GNUNET_TESTING_run (NULL,
65 commands,
66 TIMEOUT);
67}
68
69
70int
71main (int argc,
72 char *const *argv)
73{
74 GNUNET_log_setup ("test-netjail",
75 "DEBUG",
76 NULL);
77 GNUNET_SCHEDULER_run (&run,
78 NULL);
79
80 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
81 "Test finished!\n");
82 return rv;
83}
diff --git a/src/transport/test_transport_simple_send_v2.sh b/src/transport/test_transport_simple_send_v2.sh
deleted file mode 100755
index 8462d1849..000000000
--- a/src/transport/test_transport_simple_send_v2.sh
+++ /dev/null
@@ -1,2 +0,0 @@
1#!/bin/bash
2exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_simple_send_v2"
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 795c157d7..000000000
--- a/src/transport/test_transport_start_with_config.c
+++ /dev/null
@@ -1,85 +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 Test case executing a script which sends a test message between two peers.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_util_lib.h"
29
30#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
31
32/**
33 * Return value of the test.
34 *
35 */
36static unsigned int rv = 0;
37
38static char *topology_config;
39
40/**
41 * Main function to run the test cases.
42 *
43 * @param cls not used.
44 *
45 */
46static void
47run (void *cls)
48{
49 struct GNUNET_TESTING_Command commands[] = {
50 GNUNET_TESTING_cmd_netjail_start_v2 ("netjail-start",
51 topology_config),
52 GNUNET_TESTING_cmd_netjail_start_testing_system_v2 ("netjail-start-testbed",
53 topology_config,
54 &rv),
55 GNUNET_TESTING_cmd_stop_testing_system_v2 ("stop-testbed",
56 "netjail-start-testbed",
57 topology_config),
58 GNUNET_TESTING_cmd_netjail_stop_v2 ("netjail-stop",
59 topology_config),
60 GNUNET_TESTING_cmd_end ()
61 };
62
63 GNUNET_TESTING_run (NULL,
64 commands,
65 TIMEOUT);
66}
67
68
69int
70main (int argc,
71 char *const *argv)
72{
73 GNUNET_log_setup ("test-netjail",
74 "DEBUG",
75 NULL);
76
77 topology_config = argv[1];
78
79 GNUNET_SCHEDULER_run (&run,
80 NULL);
81
82 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
83 "Test finished!\n");
84 return rv;
85}
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/transport-testing-cmds.h b/src/transport/transport-testing-cmds.h
deleted file mode 100644
index ecdabd35f..000000000
--- a/src/transport/transport-testing-cmds.h
+++ /dev/null
@@ -1,345 +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
32struct StartPeerState_v2
33{
34 /**
35 * The ip of a node.
36 */
37 char *node_ip;
38
39 /**
40 * Receive callback
41 */
42 struct GNUNET_MQ_MessageHandler *handlers;
43
44 const char *cfgname;
45
46 /**
47 * Peer's configuration
48 */
49 struct GNUNET_CONFIGURATION_Handle *cfg;
50
51 struct GNUNET_TESTING_Peer *peer;
52
53 /**
54 * Peer identity
55 */
56 struct GNUNET_PeerIdentity id;
57
58 /**
59 * Peer's transport service handle
60 */
61 struct GNUNET_TRANSPORT_CoreHandle *th;
62
63 /**
64 * Application handle
65 */
66 struct GNUNET_TRANSPORT_ApplicationHandle *ah;
67
68 /**
69 * Peer's PEERSTORE Handle
70 */
71 struct GNUNET_PEERSTORE_Handle *ph;
72
73 /**
74 * Hello get task
75 */
76 struct GNUNET_SCHEDULER_Task *rh_task;
77
78 /**
79 * Peer's transport get hello handle to retrieve peer's HELLO message
80 */
81 struct GNUNET_PEERSTORE_IterateContext *pic;
82
83 /**
84 * Hello
85 */
86 char *hello;
87
88 /**
89 * Hello size
90 */
91 size_t hello_size;
92
93 char *m;
94
95 char *n;
96
97 char *local_m;
98
99 unsigned int finished;
100
101 const char *system_label;
102
103 /**
104 * An unique number to identify the peer
105 */
106 unsigned int no;
107
108 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
109
110 struct GNUNET_TESTING_System *tl_system;
111
112};
113
114
115struct StartPeerState
116{
117 /**
118 * The ip of a node.
119 */
120 char *node_ip;
121
122 /**
123 * Receive callback
124 */
125 struct GNUNET_MQ_MessageHandler *handlers;
126
127 const char *cfgname;
128
129 /**
130 * Peer's configuration
131 */
132 struct GNUNET_CONFIGURATION_Handle *cfg;
133
134 struct GNUNET_TESTING_Peer *peer;
135
136 /**
137 * Peer identity
138 */
139 struct GNUNET_PeerIdentity id;
140
141 /**
142 * Peer's transport service handle
143 */
144 struct GNUNET_TRANSPORT_CoreHandle *th;
145
146 /**
147 * Application handle
148 */
149 struct GNUNET_TRANSPORT_ApplicationHandle *ah;
150
151 /**
152 * Peer's PEERSTORE Handle
153 */
154 struct GNUNET_PEERSTORE_Handle *ph;
155
156 /**
157 * Hello get task
158 */
159 struct GNUNET_SCHEDULER_Task *rh_task;
160
161 /**
162 * Peer's transport get hello handle to retrieve peer's HELLO message
163 */
164 struct GNUNET_PEERSTORE_IterateContext *pic;
165
166 /**
167 * Hello
168 */
169 char *hello;
170
171 /**
172 * Hello size
173 */
174 size_t hello_size;
175
176 char *m;
177
178 char *n;
179
180 char *local_m;
181
182 unsigned int finished;
183
184 const char *system_label;
185
186 /**
187 * An unique number to identify the peer
188 */
189 unsigned int no;
190
191 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
192
193 struct GNUNET_TESTING_System *tl_system;
194
195};
196
197
198int
199GNUNET_TRANSPORT_get_trait_state (const struct
200 GNUNET_TESTING_Command
201 *cmd,
202 struct StartPeerState **sps);
203
204
205struct GNUNET_TESTING_Command
206GNUNET_TRANSPORT_cmd_start_peer_v2 (const char *label,
207 const char *system_label,
208 uint32_t no,
209 char *node_ip,
210 struct GNUNET_MQ_MessageHandler *handlers,
211 const char *cfgname);
212
213struct GNUNET_TESTING_Command
214GNUNET_TRANSPORT_cmd_start_peer_v3 (const char *label,
215 const char *system_label,
216 uint32_t no,
217 char *node_ip,
218 struct GNUNET_MQ_MessageHandler *handlers,
219 const char *cfgname);
220
221struct GNUNET_TESTING_Command
222GNUNET_TRANSPORT_cmd_start_peer (const char *label,
223 const char *system_label,
224 char *m,
225 char *n,
226 char *local_m,
227 char *node_ip,
228 struct GNUNET_MQ_MessageHandler *handlers,
229 const char *cfgname);
230
231struct GNUNET_TESTING_Command
232GNUNET_TRANSPORT_cmd_stop_peer (const char *label,
233 const char *start_label);
234
235struct GNUNET_TESTING_Command
236GNUNET_TRANSPORT_cmd_connect_peers (const char *label,
237 const char *start_peer_label,
238 const char *create_label,
239 uint32_t num);
240
241struct GNUNET_TESTING_Command
242GNUNET_TRANSPORT_cmd_connect_peers_v2 (const char *label,
243 const char *start_peer_label,
244 const char *create_label,
245 uint32_t num);
246
247struct GNUNET_TESTING_Command
248GNUNET_TRANSPORT_cmd_connect_peers_v3 (const char *label,
249 const char *start_peer_label,
250 const char *create_label,
251 uint32_t num,
252 struct GNUNET_TESTING_NetjailTopology *
253 topology);
254
255struct GNUNET_TESTING_Command
256GNUNET_TRANSPORT_cmd_send_simple (const char *label,
257 char *m,
258 char *n,
259 uint32_t num,
260 const char *start_peer_label);
261
262/**
263 * Create command.
264 *
265 * @param label name for command.
266 * @param m The number of the local node of the actual network namespace.
267 * @param n The number of the actual namespace.
268 * @param num Number globally identifying the node.
269 * @param start_peer_label Label of the cmd to start a peer.
270 * @return command.
271 */
272struct GNUNET_TESTING_Command
273GNUNET_TRANSPORT_cmd_send_simple_v2 (const char *label,
274 const char *start_peer_label,
275 uint32_t num);
276
277int
278GNUNET_TRANSPORT_get_trait_peer_id (const struct
279 GNUNET_TESTING_Command *cmd,
280 struct GNUNET_PeerIdentity **id);
281
282int
283GNUNET_TRANSPORT_get_trait_connected_peers_map (const struct
284 GNUNET_TESTING_Command
285 *cmd,
286 struct
287 GNUNET_CONTAINER_MultiShortmap *
288 *
289 connected_peers_map);
290
291int
292GNUNET_TRANSPORT_get_trait_connected_peers_map_v2 (const struct
293 GNUNET_TESTING_Command
294 *cmd,
295 struct
296 GNUNET_CONTAINER_MultiShortmap
297 *
298 *
299 connected_peers_map);
300
301int
302GNUNET_TRANSPORT_get_trait_connected_peers_map_v3 (const struct
303 GNUNET_TESTING_Command
304 *cmd,
305 struct
306 GNUNET_CONTAINER_MultiShortmap
307 *
308 *
309 connected_peers_map);
310int
311GNUNET_TRANSPORT_get_trait_hello_size (const struct
312 GNUNET_TESTING_Command
313 *cmd,
314 size_t **hello_size);
315
316int
317GNUNET_TRANSPORT_get_trait_hello (const struct
318 GNUNET_TESTING_Command
319 *cmd,
320 char **hello);
321
322
323int
324GNUNET_TRANSPORT_get_trait_application_handle (const struct
325 GNUNET_TESTING_Command *cmd,
326 struct
327 GNUNET_TRANSPORT_ApplicationHandle
328 **ah);
329
330int
331GNUNET_TRANSPORT_get_trait_application_handle_v2 (const struct
332 GNUNET_TESTING_Command *cmd,
333 struct
334 GNUNET_TRANSPORT_ApplicationHandle
335 **ah);
336
337int
338GNUNET_TRANSPORT_get_trait_application_handle_v3 (const struct
339 GNUNET_TESTING_Command *cmd,
340 struct
341 GNUNET_TRANSPORT_ApplicationHandle
342 **ah);
343
344#endif
345/* 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 446add6f6..000000000
--- a/src/transport/transport_api2_communication.c
+++ /dev/null
@@ -1,1158 +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 if (NULL == ch->mq)
908 return GNUNET_SYSERR;
909 if ((NULL == cb) && (GNUNET_MQ_get_length (ch->mq) >= ch->max_queue_length))
910 {
911 GNUNET_log (
912 GNUNET_ERROR_TYPE_WARNING,
913 "Dropping message: transport is too slow, queue length %llu exceeded\n",
914 ch->max_queue_length);
915 return GNUNET_NO;
916 }
917
918 msize = ntohs (msg->size);
919 env =
920 GNUNET_MQ_msg_extra (im, msize, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG);
921 if (NULL == env)
922 {
923 GNUNET_break (0);
924 return GNUNET_SYSERR;
925 }
926 im->expected_address_validity =
927 GNUNET_TIME_relative_hton (expected_addr_validity);
928 im->sender = *sender;
929 // FIXME: this is expensive, would be better if we would
930 // re-design the API to allow us to create the envelope first,
931 // and then have the application fill in the body so we do
932 // not have to memcpy()
933 memcpy (&im[1], msg, msize);
934 im->fc_on = htonl (GNUNET_NO);
935 if (NULL != cb)
936 {
937 struct FlowControl *fc;
938
939 im->fc_on = htonl (GNUNET_YES);
940 im->fc_id = ch->fc_gen++;
941 fc = GNUNET_new (struct FlowControl);
942 fc->sender = *sender;
943 fc->id = im->fc_id;
944 fc->cb = cb;
945 fc->cb_cls = cb_cls;
946 GNUNET_CONTAINER_DLL_insert (ch->fc_head, ch->fc_tail, fc);
947 }
948 GNUNET_MQ_send (ch->mq, env);
949 return GNUNET_OK;
950}
951
952
953/* ************************* Discovery *************************** */
954
955
956/**
957 * Notify transport service that an MQ became available due to an
958 * "inbound" connection or because the communicator discovered the
959 * presence of another peer.
960 *
961 * @param ch connection to transport service
962 * @param peer peer with which we can now communicate
963 * @param address address in human-readable format, 0-terminated, UTF-8
964 * @param mtu maximum message size supported by queue, 0 if
965 * sending is not supported, SIZE_MAX for no MTU
966 * @param q_len number of messages that can be send through this queue
967 * @param priority queue priority. Queues with highest priority should be
968 * used
969 * @param nt which network type does the @a address belong to?
970 * @param cc what characteristics does the communicator have?
971 * @param cs what is the connection status of the queue?
972 * @param mq message queue of the @a peer
973 * @return API handle identifying the new MQ
974 */
975struct GNUNET_TRANSPORT_QueueHandle *
976GNUNET_TRANSPORT_communicator_mq_add (
977 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
978 const struct GNUNET_PeerIdentity *peer,
979 const char *address,
980 uint32_t mtu,
981 uint64_t q_len,
982 uint32_t priority,
983 enum GNUNET_NetworkType nt,
984 enum GNUNET_TRANSPORT_ConnectionStatus cs,
985 struct GNUNET_MQ_Handle *mq)
986{
987 struct GNUNET_TRANSPORT_QueueHandle *qh;
988
989 qh = GNUNET_new (struct GNUNET_TRANSPORT_QueueHandle);
990 qh->ch = ch;
991 qh->peer = *peer;
992 qh->address = GNUNET_strdup (address);
993 qh->nt = nt;
994 qh->mtu = mtu;
995 qh->q_len = q_len;
996 qh->priority = priority;
997 qh->cs = cs;
998 qh->mq = mq;
999 qh->queue_id = ch->queue_gen++;
1000 GNUNET_CONTAINER_DLL_insert (ch->queue_head, ch->queue_tail, qh);
1001 send_add_queue (qh);
1002 return qh;
1003}
1004
1005
1006/**
1007 * Notify transport service that an MQ was updated
1008 *
1009 * @param ch connection to transport service
1010 * @param qh the queue to update
1011 * @param q_len number of messages that can be send through this queue
1012 * @param priority queue priority. Queues with highest priority should be
1013 * used
1014 */
1015void
1016GNUNET_TRANSPORT_communicator_mq_update (
1017 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1018 const struct GNUNET_TRANSPORT_QueueHandle *u_qh,
1019 uint64_t q_len,
1020 uint32_t priority)
1021{
1022 struct GNUNET_TRANSPORT_QueueHandle *qh;
1023
1024 for (qh = ch->queue_head; NULL != qh; qh = qh->next)
1025 {
1026 if (u_qh == qh)
1027 break;
1028 }
1029 GNUNET_assert (NULL != qh);
1030 qh->q_len = q_len;
1031 qh->priority = priority;
1032 send_update_queue (qh);
1033}
1034
1035
1036/**
1037 * Notify transport service that an MQ became unavailable due to a
1038 * disconnect or timeout.
1039 *
1040 * @param qh handle for the queue that must be invalidated
1041 */
1042void
1043GNUNET_TRANSPORT_communicator_mq_del (struct GNUNET_TRANSPORT_QueueHandle *qh)
1044{
1045 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = qh->ch;
1046
1047 send_del_queue (qh);
1048 GNUNET_CONTAINER_DLL_remove (ch->queue_head, ch->queue_tail, qh);
1049 GNUNET_MQ_destroy (qh->mq);
1050 GNUNET_free (qh->address);
1051 GNUNET_free (qh);
1052}
1053
1054
1055/**
1056 * Notify transport service about an address that this communicator
1057 * provides for this peer.
1058 *
1059 * @param ch connection to transport service
1060 * @param address our address in human-readable format, 0-terminated, UTF-8
1061 * @param nt which network type does the address belong to?
1062 * @param expiration when does the communicator forsee this address expiring?
1063 */
1064struct GNUNET_TRANSPORT_AddressIdentifier *
1065GNUNET_TRANSPORT_communicator_address_add (
1066 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1067 const char *address,
1068 enum GNUNET_NetworkType nt,
1069 struct GNUNET_TIME_Relative expiration)
1070{
1071 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
1072
1073 ai = GNUNET_new (struct GNUNET_TRANSPORT_AddressIdentifier);
1074 ai->ch = ch;
1075 ai->address = GNUNET_strdup (address);
1076 ai->nt = nt;
1077 ai->expiration = expiration;
1078 ai->aid = ch->aid_gen++;
1079 GNUNET_CONTAINER_DLL_insert (ch->ai_head, ch->ai_tail, ai);
1080 send_add_address (ai);
1081 return ai;
1082}
1083
1084/**
1085 * Notify transport service about an address that this communicator no
1086 * longer provides for this peer.
1087 *
1088 * @param ai address that is no longer provided
1089 */
1090void
1091GNUNET_TRANSPORT_communicator_address_remove (
1092 struct GNUNET_TRANSPORT_AddressIdentifier *ai)
1093{
1094 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = ai->ch;
1095
1096 send_del_address (ai);
1097 GNUNET_CONTAINER_DLL_remove (ch->ai_head, ch->ai_tail, ai);
1098 GNUNET_free (ai->address);
1099 GNUNET_free (ai);
1100}
1101
1102/**
1103 * Notify transport service that this communicator no longer provides all its addresses for this peer.
1104 *
1105 * @param ch The communicator handle.
1106 */
1107void
1108GNUNET_TRANSPORT_communicator_address_remove_all (
1109 struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
1110{
1111 for (struct GNUNET_TRANSPORT_AddressIdentifier *ai = ch->ai_head; NULL != ai;
1112 ai = ai->next)
1113 GNUNET_TRANSPORT_communicator_address_remove (ai);
1114}
1115
1116
1117/* ************************* Backchannel *************************** */
1118
1119
1120/**
1121 * The communicator asks the transport service to route a message via
1122 * a different path to another communicator service at another peer.
1123 * This must only be done for special control traffic (as there is no
1124 * flow control for this API), such as acknowledgements, and generally
1125 * only be done if the communicator is uni-directional (i.e. cannot
1126 * send the message back itself).
1127 *
1128 * @param ch handle of this communicator
1129 * @param pid peer to send the message to
1130 * @param comm name of the communicator to send the message to
1131 * @param header header of the message to transmit and pass via the
1132 * notify-API to @a pid's communicator @a comm
1133 */
1134void
1135GNUNET_TRANSPORT_communicator_notify (
1136 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1137 const struct GNUNET_PeerIdentity *pid,
1138 const char *comm,
1139 const struct GNUNET_MessageHeader *header)
1140{
1141 struct GNUNET_MQ_Envelope *env;
1142 struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb;
1143 size_t slen = strlen (comm) + 1;
1144 uint16_t mlen = ntohs (header->size);
1145
1146 GNUNET_assert (mlen + slen + sizeof(*cb) < UINT16_MAX);
1147 env =
1148 GNUNET_MQ_msg_extra (cb,
1149 slen + mlen,
1150 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL);
1151 cb->pid = *pid;
1152 memcpy (&cb[1], header, mlen);
1153 memcpy (((char *) &cb[1]) + mlen, comm, slen);
1154 GNUNET_MQ_send (ch->mq, env);
1155}
1156
1157
1158/* 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 002af81fc..000000000
--- a/src/transport/transport_api2_core.c
+++ /dev/null
@@ -1,801 +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 receiving from transport service, disconnecting temporarily.\n");
248 disconnect_and_schedule_reconnect (h);
249}
250
251
252/**
253 * A message from the handler's message queue to a neighbour was
254 * transmitted. Now trigger (possibly delayed) notification of the
255 * neighbour's message queue that we are done and thus ready for
256 * the next message. Note that the MQ being ready is independent
257 * of the send window, as we may queue many messages and simply
258 * not pass them to TRANSPORT if the send window is insufficient.
259 *
260 * @param cls the `struct Neighbour` where the message was sent
261 */
262static void
263notify_send_done (void *cls)
264{
265 struct Neighbour *n = cls;
266
267 n->awaiting_done = GNUNET_NO;
268 n->env = NULL;
269 GNUNET_MQ_impl_send_continue (n->mq);
270}
271
272
273/**
274 * We have an envelope waiting for transmission at @a n, and
275 * our transmission window is positive. Perform the transmission.
276 *
277 * @param n neighbour to perform transmission for
278 */
279static void
280do_send (struct Neighbour *n)
281{
282 GNUNET_assert (0 < n->ready_window);
283 GNUNET_assert (NULL != n->env);
284 n->ready_window--;
285 n->awaiting_done = GNUNET_YES;
286 GNUNET_MQ_notify_sent (n->env, &notify_send_done, n);
287 GNUNET_MQ_send (n->h->mq, n->env);
288 LOG (GNUNET_ERROR_TYPE_DEBUG,
289 "Passed message of type %u for neighbour `%s' to TRANSPORT.\n",
290 ntohs (GNUNET_MQ_env_get_msg (n->env)->type),
291 GNUNET_i2s (&n->id));
292}
293
294
295/**
296 * Implement sending functionality of a message queue.
297 * Called one message at a time. Should send the @a msg
298 * to the transport service and then notify the queue
299 * once we are ready for the next one.
300 *
301 * @param mq the message queue
302 * @param msg the message to send
303 * @param impl_state state of the implementation
304 */
305static void
306mq_send_impl (struct GNUNET_MQ_Handle *mq,
307 const struct GNUNET_MessageHeader *msg,
308 void *impl_state)
309{
310 struct Neighbour *n = impl_state;
311 struct OutboundMessage *obm;
312 uint16_t msize;
313
314 msize = ntohs (msg->size);
315 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(*obm))
316 {
317 GNUNET_break (0);
318 GNUNET_MQ_impl_send_continue (mq);
319 return;
320 }
321 LOG (GNUNET_ERROR_TYPE_DEBUG,
322 "CORE requested transmission of message of type %u to neighbour `%s'.\n",
323 ntohs (msg->type),
324 GNUNET_i2s (&n->id));
325
326 GNUNET_assert (NULL == n->env);
327 n->env =
328 GNUNET_MQ_msg_nested_mh (obm, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, msg);
329 n->env_size = ntohs (msg->size);
330 {
331 struct GNUNET_MQ_Envelope *env;
332
333 env = GNUNET_MQ_get_current_envelope (mq);
334 obm->priority = htonl ((uint32_t) GNUNET_MQ_env_get_options (env));
335 }
336 obm->peer = n->id;
337 if (0 == n->ready_window)
338 {
339 LOG (GNUNET_ERROR_TYPE_DEBUG,
340 "Flow control delays transmission to CORE until we see SEND_OK.\n");
341 return; /* can't send yet, need to wait for SEND_OK */
342 }
343 do_send (n);
344}
345
346
347/**
348 * Handle destruction of a message queue. Implementations must not
349 * free @a mq, but should take care of @a impl_state.
350 *
351 * @param mq the message queue to destroy
352 * @param impl_state state of the implementation
353 */
354static void
355mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
356{
357 struct Neighbour *n = impl_state;
358
359 GNUNET_assert (mq == n->mq);
360 n->mq = NULL;
361}
362
363
364/**
365 * Implementation function that cancels the currently sent message.
366 * Should basically undo whatever #mq_send_impl() did.
367 *
368 * @param mq message queue
369 * @param impl_state state specific to the implementation
370 */
371static void
372mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
373{
374 struct Neighbour *n = impl_state;
375
376 n->ready_window++;
377 if (GNUNET_YES == n->awaiting_done)
378 {
379 GNUNET_MQ_send_cancel (n->env);
380 n->env = NULL;
381 n->awaiting_done = GNUNET_NO;
382 }
383 else
384 {
385 GNUNET_assert (0 == n->ready_window);
386 n->env = NULL;
387 }
388}
389
390
391/**
392 * We had an error processing a message we forwarded from a peer to
393 * the CORE service. We should just complain about it but otherwise
394 * continue processing.
395 *
396 * @param cls closure
397 * @param error error code
398 */
399static void
400peer_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
401{
402 /* struct Neighbour *n = cls; */
403
404 GNUNET_break_op (0);
405}
406
407
408/**
409 * Function we use for handling incoming connect messages.
410 *
411 * @param cls closure, a `struct GNUNET_TRANSPORT_Handle *`
412 * @param cim message received
413 */
414static void
415handle_connect (void *cls, const struct ConnectInfoMessage *cim)
416{
417 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
418 struct Neighbour *n;
419
420 LOG (GNUNET_ERROR_TYPE_DEBUG,
421 "Receiving CONNECT message for `%s'\n",
422 GNUNET_i2s (&cim->id));
423 n = neighbour_find (h, &cim->id);
424 if (NULL != n)
425 {
426 GNUNET_break (0);
427 disconnect_and_schedule_reconnect (h);
428 return;
429 }
430 n = GNUNET_new (struct Neighbour);
431 n->id = cim->id;
432 n->h = h;
433 n->ready_window = SEND_WINDOW_SIZE;
434 GNUNET_assert (GNUNET_OK ==
435 GNUNET_CONTAINER_multipeermap_put (
436 h->neighbours,
437 &n->id,
438 n,
439 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
440
441 n->mq = GNUNET_MQ_queue_for_callbacks (&mq_send_impl,
442 &mq_destroy_impl,
443 &mq_cancel_impl,
444 n,
445 h->handlers,
446 &peer_mq_error_handler,
447 n);
448 if (NULL != h->nc_cb)
449 {
450 n->handlers_cls = h->nc_cb (h->cls, &n->id, n->mq);
451 GNUNET_MQ_set_handlers_closure (n->mq, n->handlers_cls);
452 }
453}
454
455
456/**
457 * Function we use for handling incoming disconnect messages.
458 *
459 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
460 * @param dim message received
461 */
462static void
463handle_disconnect (void *cls, const struct DisconnectInfoMessage *dim)
464{
465 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
466 struct Neighbour *n;
467
468 GNUNET_break (ntohl (dim->reserved) == 0);
469 LOG (GNUNET_ERROR_TYPE_DEBUG,
470 "Receiving DISCONNECT message for `%s'.\n",
471 GNUNET_i2s (&dim->peer));
472 n = neighbour_find (h, &dim->peer);
473 if (NULL == n)
474 {
475 GNUNET_break (0);
476 disconnect_and_schedule_reconnect (h);
477 return;
478 }
479 GNUNET_assert (GNUNET_YES == neighbour_delete (h, &dim->peer, n));
480}
481
482
483/**
484 * Function we use for handling incoming send-ok messages.
485 *
486 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
487 * @param okm message received
488 */
489static void
490handle_send_ok (void *cls, const struct SendOkMessage *okm)
491{
492 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
493 struct Neighbour *n;
494
495 LOG (GNUNET_ERROR_TYPE_DEBUG,
496 "Receiving SEND_OK message for transmission to %s\n",
497 GNUNET_i2s (&okm->peer));
498 n = neighbour_find (h, &okm->peer);
499 if (NULL == n)
500 {
501 /* We should never get a 'SEND_OK' for a peer that we are not
502 connected to */
503 GNUNET_break (0);
504 disconnect_and_schedule_reconnect (h);
505 return;
506 }
507 n->ready_window++;
508 if ((NULL != n->env) && (1 == n->ready_window))
509 do_send (n);
510}
511
512
513/**
514 * Function we use for checking incoming "inbound" messages.
515 *
516 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
517 * @param im message received
518 */
519static int
520check_recv (void *cls, const struct InboundMessage *im)
521{
522 const struct GNUNET_MessageHeader *imm;
523 uint16_t size;
524
525 size = ntohs (im->header.size) - sizeof(*im);
526 if (size < sizeof(struct GNUNET_MessageHeader))
527 {
528 GNUNET_break (0);
529 return GNUNET_SYSERR;
530 }
531 imm = (const struct GNUNET_MessageHeader *) &im[1];
532 if (ntohs (imm->size) != size)
533 {
534 GNUNET_break (0);
535 return GNUNET_SYSERR;
536 }
537 return GNUNET_OK;
538}
539
540
541/**
542 * Function we use for handling incoming messages.
543 *
544 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
545 * @param im message received
546 */
547static void
548handle_recv (void *cls, const struct InboundMessage *im)
549{
550 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
551 const struct GNUNET_MessageHeader *imm =
552 (const struct GNUNET_MessageHeader *) &im[1];
553 struct Neighbour *n;
554
555 LOG (GNUNET_ERROR_TYPE_DEBUG,
556 "Received message of type %u with %u bytes from `%s'.\n",
557 (unsigned int) ntohs (imm->type),
558 (unsigned int) ntohs (imm->size),
559 GNUNET_i2s (&im->peer));
560 n = neighbour_find (h, &im->peer);
561 if (NULL == n)
562 {
563 GNUNET_break (0);
564 disconnect_and_schedule_reconnect (h);
565 return;
566 }
567 GNUNET_MQ_inject_message (n->mq, imm);
568}
569
570
571/**
572 * Try again to connect to transport service.
573 *
574 * @param cls the handle to the transport service
575 */
576static void
577reconnect (void *cls)
578{
579 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
580 struct GNUNET_MQ_MessageHandler handlers[] =
581 { GNUNET_MQ_hd_fixed_size (connect,
582 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT,
583 struct ConnectInfoMessage,
584 h),
585 GNUNET_MQ_hd_fixed_size (disconnect,
586 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT,
587 struct DisconnectInfoMessage,
588 h),
589 GNUNET_MQ_hd_fixed_size (send_ok,
590 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK,
591 struct SendOkMessage,
592 h),
593 GNUNET_MQ_hd_var_size (recv,
594 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV,
595 struct InboundMessage,
596 h),
597 GNUNET_MQ_handler_end () };
598 struct GNUNET_MQ_Envelope *env;
599 struct StartMessage *s;
600 uint32_t options;
601
602 h->reconnect_task = NULL;
603 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n");
604 GNUNET_assert (NULL == h->mq);
605 h->mq =
606 GNUNET_CLIENT_connect (h->cfg, "transport", handlers, &mq_error_handler, h);
607 if (NULL == h->mq)
608 return;
609 env = GNUNET_MQ_msg (s, GNUNET_MESSAGE_TYPE_TRANSPORT_START);
610 options = 0;
611 if (h->check_self)
612 options |= 1;
613 if (NULL != h->handlers)
614 options |= 2;
615 s->options = htonl (options);
616 s->self = h->self;
617 GNUNET_MQ_send (h->mq, env);
618}
619
620
621/**
622 * Disconnect from the transport service.
623 *
624 * @param h transport service to reconnect
625 */
626static void
627disconnect (struct GNUNET_TRANSPORT_CoreHandle *h)
628{
629 GNUNET_CONTAINER_multipeermap_iterate (h->neighbours, &neighbour_delete, h);
630 if (NULL != h->mq)
631 {
632 GNUNET_MQ_destroy (h->mq);
633 h->mq = NULL;
634 }
635}
636
637
638/**
639 * Function that will schedule the job that will try
640 * to connect us again to the client.
641 *
642 * @param h transport service to reconnect
643 */
644static void
645disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h)
646{
647 GNUNET_assert (NULL == h->reconnect_task);
648 disconnect (h);
649 LOG (GNUNET_ERROR_TYPE_DEBUG,
650 "Scheduling task to reconnect to transport service in %s.\n",
651 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
652 h->reconnect_task =
653 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
654 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
655}
656
657
658/**
659 * Checks if a given peer is connected to us and get the message queue.
660 *
661 * @param handle connection to transport service
662 * @param peer the peer to check
663 * @return NULL if disconnected, otherwise message queue for @a peer
664 */
665struct GNUNET_MQ_Handle *
666GNUNET_TRANSPORT_core_get_mq (struct GNUNET_TRANSPORT_CoreHandle *handle,
667 const struct GNUNET_PeerIdentity *peer)
668{
669 struct Neighbour *n;
670
671 n = neighbour_find (handle, peer);
672 if (NULL == n)
673 return NULL;
674 return n->mq;
675}
676
677
678/**
679 * Notification from the CORE service to the TRANSPORT service
680 * that the CORE service has finished processing a message from
681 * TRANSPORT (via the @code{handlers} of #GNUNET_TRANSPORT_core_connect())
682 * and that it is thus now OK for TRANSPORT to send more messages
683 * for @a pid.
684 *
685 * Used to provide flow control, this is our equivalent to
686 * #GNUNET_SERVICE_client_continue() of an ordinary service.
687 *
688 * Note that due to the use of a window, TRANSPORT may send multiple
689 * messages destined for the same peer even without an intermediate
690 * call to this function. However, CORE must still call this function
691 * once per message received, as otherwise eventually the window will
692 * be full and TRANSPORT will stop providing messages to CORE for @a
693 * pid.
694 *
695 * @param ch core handle
696 * @param pid which peer was the message from that was fully processed by CORE
697 */
698void
699GNUNET_TRANSPORT_core_receive_continue (struct GNUNET_TRANSPORT_CoreHandle *ch,
700 const struct GNUNET_PeerIdentity *pid)
701{
702 struct GNUNET_MQ_Envelope *env;
703 struct RecvOkMessage *rok;
704
705 LOG (GNUNET_ERROR_TYPE_DEBUG,
706 "Message for %s finished CORE processing, sending RECV_OK.\n",
707 GNUNET_i2s (pid));
708 if (NULL == ch->mq)
709 return;
710 env = GNUNET_MQ_msg (rok, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK);
711 rok->increase_window_delta = htonl (1);
712 rok->peer = *pid;
713 GNUNET_MQ_send (ch->mq, env);
714}
715
716
717/**
718 * Connect to the transport service. Note that the connection may
719 * complete (or fail) asynchronously.
720 *
721 * @param cfg configuration to use
722 * @param self our own identity (API should check that it matches
723 * the identity found by transport), or NULL (no check)
724 * @param cls closure for the callbacks
725 * @param rec receive function to call
726 * @param nc function to call on connect events
727 * @param nd function to call on disconnect events
728 * @return NULL on error
729 */
730struct GNUNET_TRANSPORT_CoreHandle *
731GNUNET_TRANSPORT_core_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
732 const struct GNUNET_PeerIdentity *self,
733 const struct GNUNET_MQ_MessageHandler *handlers,
734 void *cls,
735 GNUNET_TRANSPORT_NotifyConnect nc,
736 GNUNET_TRANSPORT_NotifyDisconnect nd)
737{
738 struct GNUNET_TRANSPORT_CoreHandle *h;
739 unsigned int i;
740
741 h = GNUNET_new (struct GNUNET_TRANSPORT_CoreHandle);
742 if (NULL != self)
743 {
744 h->self = *self;
745 h->check_self = GNUNET_YES;
746 }
747 h->cfg = cfg;
748 h->cls = cls;
749 h->nc_cb = nc;
750 h->nd_cb = nd;
751 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
752 if (NULL != handlers)
753 {
754 for (i = 0; NULL != handlers[i].cb; i++)
755 ;
756 h->handlers = GNUNET_new_array (i + 1, struct GNUNET_MQ_MessageHandler);
757 GNUNET_memcpy (h->handlers,
758 handlers,
759 i * sizeof(struct GNUNET_MQ_MessageHandler));
760 }
761 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service\n");
762 reconnect (h);
763 if (NULL == h->mq)
764 {
765 GNUNET_free (h->handlers);
766 GNUNET_free (h);
767 return NULL;
768 }
769 h->neighbours =
770 GNUNET_CONTAINER_multipeermap_create (STARTING_NEIGHBOURS_SIZE, GNUNET_YES);
771 return h;
772}
773
774
775/**
776 * Disconnect from the transport service.
777 *
778 * @param handle handle to the service as returned from
779 * #GNUNET_TRANSPORT_core_connect()
780 */
781void
782GNUNET_TRANSPORT_core_disconnect (struct GNUNET_TRANSPORT_CoreHandle *handle)
783{
784 LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n");
785 /* this disconnects all neighbours... */
786 disconnect (handle);
787 /* and now we stop trying to connect again... */
788 if (NULL != handle->reconnect_task)
789 {
790 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
791 handle->reconnect_task = NULL;
792 }
793 GNUNET_CONTAINER_multipeermap_destroy (handle->neighbours);
794 handle->neighbours = NULL;
795 GNUNET_free (handle->handlers);
796 handle->handlers = NULL;
797 GNUNET_free (handle);
798}
799
800
801/* 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_connecting_peers.c b/src/transport/transport_api_cmd_connecting_peers.c
deleted file mode 100644
index 09ca9e54c..000000000
--- a/src/transport/transport_api_cmd_connecting_peers.c
+++ /dev/null
@@ -1,281 +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_transport_application_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_transport_service.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/**
40 * Struct to store information needed in callbacks.
41 *
42 */
43struct ConnectPeersState
44{
45 // Label of the cmd which started the test system.
46 const char *create_label;
47
48 /**
49 * Number globally identifying the node.
50 *
51 */
52 uint32_t num;
53
54 /**
55 * Label of the cmd to start a peer.
56 *
57 */
58 const char *start_peer_label;
59
60 /**
61 * The peer identity of this peer.
62 *
63 */
64 struct GNUNET_PeerIdentity *id;
65};
66
67
68/**
69 * The run method of this cmd will connect to peers.
70 *
71 */
72static void
73connect_peers_run (void *cls,
74 const struct GNUNET_TESTING_Command *cmd,
75 struct GNUNET_TESTING_Interpreter *is)
76{
77 struct ConnectPeersState *cps = cls;
78 const struct GNUNET_TESTING_Command *system_cmd;
79 struct GNUNET_TESTING_System *tl_system;
80 struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key = GNUNET_new (struct
81 GNUNET_CRYPTO_EddsaPrivateKey);
82 struct GNUNET_CRYPTO_EddsaPublicKey *pub_key = GNUNET_new (struct
83 GNUNET_CRYPTO_EddsaPublicKey);
84 ;
85 const struct GNUNET_TESTING_Command *peer1_cmd;
86 // const struct GNUNET_TESTING_Command *peer2_cmd;
87 struct GNUNET_TRANSPORT_ApplicationHandle *ah;
88 struct GNUNET_PeerIdentity *peer = GNUNET_new (struct GNUNET_PeerIdentity);
89 char *addr;
90 // struct GNUNET_TIME_Absolute t;
91 char *hello;
92 // size_t *hello_size;
93 enum GNUNET_NetworkType nt = 0;
94 char *peer_id;
95 struct GNUNET_PeerIdentity *id;
96 struct GNUNET_PeerIdentity *other = GNUNET_new (struct GNUNET_PeerIdentity);
97 uint32_t num;
98
99 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (cps->start_peer_label);
100 GNUNET_TRANSPORT_get_trait_application_handle (peer1_cmd,
101 &ah);
102
103 GNUNET_TRANSPORT_get_trait_hello (peer1_cmd,
104 &hello);
105
106 GNUNET_TRANSPORT_get_trait_peer_id (peer1_cmd,
107 &id);
108
109 system_cmd = GNUNET_TESTING_interpreter_lookup_command (cps->create_label);
110 GNUNET_TESTING_get_trait_test_system (system_cmd,
111 &tl_system);
112
113 if (2 == cps->num)
114 num = 1;
115 else
116 num = 2;
117
118
119
120
121 // if (strstr (hello, "60002") != NULL)
122 if (2 == num)
123 {
124 addr = "tcp-192.168.15.2:60002";
125 peer_id = "F2F3X9G1YNCTXKK7A4J6M4ZM4BBSKC9DEXZVHCWQ475M0C7PNWCG";
126 }
127 else
128 {
129 addr = "tcp-192.168.15.1:60002";
130 peer_id = "4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730";
131 }
132
133 priv_key = GNUNET_TESTING_hostkey_get (tl_system,
134 num,
135 other);
136
137 GNUNET_CRYPTO_eddsa_key_get_public (priv_key,
138 pub_key);
139
140 GNUNET_CRYPTO_eddsa_public_key_from_string (peer_id,
141 strlen (peer_id),
142 &peer->public_key);
143
144 peer->public_key = *pub_key;
145
146 LOG (GNUNET_ERROR_TYPE_ERROR,
147 "\nnum: %u\n peer_id: %s\n pub_key %s\n",
148 num,
149 peer_id,
150 GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key));
151
152 cps->id = peer;
153
154 // TODO This does not work, because the other peer is running in another local loop. We need to message between different local loops. For now we will create the hello manually with the known information about the other local peers.
155 // ---------------------------------------------
156 /*peer2_cmd = GNUNET_TESTING_interpreter_lookup_command (cps->peer2_label);
157 GNUNET_TRANSPORT_get_trait_peer_id (peer2_cmd,
158 &id);
159 GNUNET_TRANSPORT_get_trait_hello (peer2_cmd,
160 &hello);
161 GNUNET_TRANSPORT_get_trait_hello_size (peer2_cmd,
162 &hello_size);
163
164 addr = GNUNET_HELLO_extract_address (hello,
165 *hello_size,
166 id,
167 &nt,
168 &t);*/
169
170 // ----------------------------------------------
171
172
173 GNUNET_TRANSPORT_application_validate (ah,
174 peer,
175 nt,
176 addr);
177}
178
179
180/**
181 * The finish function of this cmd will check if the peer we are trying to connect to is in the connected peers map of the start peer cmd for this peer.
182 *
183 */
184static int
185connect_peers_finish (void *cls,
186 GNUNET_SCHEDULER_TaskCallback cont,
187 void *cont_cls)
188{
189 struct ConnectPeersState *cps = cls;
190 const struct GNUNET_TESTING_Command *peer1_cmd;
191 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
192 unsigned int ret;
193 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
194 struct GNUNET_HashCode hc;
195 int node_number;
196
197 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (cps->start_peer_label);
198 GNUNET_TRANSPORT_get_trait_connected_peers_map (peer1_cmd,
199 &connected_peers_map);
200
201 node_number = 1;
202 GNUNET_CRYPTO_hash (&node_number, sizeof(node_number), &hc);
203
204 // TODO we need to store with a key identifying the netns node in the future. For now we have only one connecting node.
205 memcpy (key,
206 &hc,
207 sizeof (*key));
208 ret = GNUNET_CONTAINER_multishortmap_contains (connected_peers_map,
209 key);
210
211 if (GNUNET_YES == ret)
212 {
213 cont (cont_cls);
214 }
215
216 GNUNET_free (key);
217 return ret;
218}
219
220
221/**
222 * Trait function of this cmd does nothing.
223 *
224 */
225static int
226connect_peers_traits (void *cls,
227 const void **ret,
228 const char *trait,
229 unsigned int index)
230{
231 return GNUNET_OK;
232}
233
234
235/**
236 * The cleanup function of this cmd frees resources the cmd allocated.
237 *
238 */
239static void
240connect_peers_cleanup (void *cls,
241 const struct GNUNET_TESTING_Command *cmd)
242{
243 struct ConnectPeersState *cps = cls;
244
245 GNUNET_free (cps->id);
246 GNUNET_free (cps);
247}
248
249
250/**
251 * Create command.
252 *
253 * @param label name for command.
254 * @param start_peer_label Label of the cmd to start a peer.
255 * @return command.
256 */
257struct GNUNET_TESTING_Command
258GNUNET_TRANSPORT_cmd_connect_peers (const char *label,
259 const char *start_peer_label,
260 const char *create_label,
261 uint32_t num)
262{
263 struct ConnectPeersState *cps;
264
265 cps = GNUNET_new (struct ConnectPeersState);
266 cps->start_peer_label = start_peer_label;
267 cps->num = num;
268 cps->create_label = create_label;
269
270
271 struct GNUNET_TESTING_Command cmd = {
272 .cls = cps,
273 .label = label,
274 .run = &connect_peers_run,
275 .finish = &connect_peers_finish,
276 .cleanup = &connect_peers_cleanup,
277 .traits = &connect_peers_traits
278 };
279
280 return cmd;
281}
diff --git a/src/transport/transport_api_cmd_connecting_peers_v2.c b/src/transport/transport_api_cmd_connecting_peers_v2.c
deleted file mode 100644
index 0d286b714..000000000
--- a/src/transport/transport_api_cmd_connecting_peers_v2.c
+++ /dev/null
@@ -1,242 +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_transport_application_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_transport_service.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 CONNECT_ADDRESS_TEMPLATE "tcp-192.168.15.%u:60002"
40
41/**
42 * Struct to store information needed in callbacks.
43 *
44 */
45struct ConnectPeersState
46{
47 // Label of the cmd which started the test system.
48 const char *create_label;
49
50 /**
51 * Number globally identifying the node.
52 *
53 */
54 uint32_t num;
55
56 /**
57 * Label of the cmd to start a peer.
58 *
59 */
60 const char *start_peer_label;
61
62 /**
63 * The peer identity of this peer.
64 *
65 */
66 struct GNUNET_PeerIdentity *id;
67};
68
69
70/**
71 * The run method of this cmd will connect to peers.
72 *
73 */
74static void
75connect_peers_run (void *cls,
76 const struct GNUNET_TESTING_Command *cmd,
77 struct GNUNET_TESTING_Interpreter *is)
78{
79 struct ConnectPeersState *cps = cls;
80 const struct GNUNET_TESTING_Command *system_cmd;
81 struct GNUNET_TESTING_System *tl_system;
82 struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key = GNUNET_new (struct
83 GNUNET_CRYPTO_EddsaPrivateKey);
84 struct GNUNET_CRYPTO_EddsaPublicKey *pub_key = GNUNET_new (struct
85 GNUNET_CRYPTO_EddsaPublicKey);
86 const struct GNUNET_TESTING_Command *peer1_cmd;
87 struct GNUNET_TRANSPORT_ApplicationHandle *ah;
88 struct GNUNET_PeerIdentity *peer = GNUNET_new (struct GNUNET_PeerIdentity);
89 char *addr;
90 enum GNUNET_NetworkType nt = 0;
91 struct GNUNET_PeerIdentity *other = GNUNET_new (struct GNUNET_PeerIdentity);
92 uint32_t num;
93
94 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (cps->start_peer_label);
95 GNUNET_TRANSPORT_get_trait_application_handle_v2 (peer1_cmd,
96 &ah);
97
98 system_cmd = GNUNET_TESTING_interpreter_lookup_command (cps->create_label);
99 GNUNET_TESTING_get_trait_test_system (system_cmd,
100 &tl_system);
101
102 if (1 == cps->num)
103 {
104 num = 2;
105 // addr = "tcp-192.168.15.2:60002";
106 }
107 else
108 {
109 num = 1;
110 // addr = "tcp-192.168.15.1:60002";
111 }
112
113 GNUNET_asprintf (&addr,
114 CONNECT_ADDRESS_TEMPLATE,
115 num);
116
117 priv_key = GNUNET_TESTING_hostkey_get (tl_system,
118 num,
119 other);
120
121 GNUNET_CRYPTO_eddsa_key_get_public (priv_key,
122 pub_key);
123
124
125 peer->public_key = *pub_key;
126
127 LOG (GNUNET_ERROR_TYPE_ERROR,
128 "num: %u pub_key %s\n",
129 num,
130 GNUNET_CRYPTO_eddsa_public_key_to_string (pub_key));
131
132 cps->id = peer;
133
134 GNUNET_TRANSPORT_application_validate (ah,
135 peer,
136 nt,
137 addr);
138}
139
140
141/**
142 * The finish function of this cmd will check if the peer we are trying to connect to is in the connected peers map of the start peer cmd for this peer.
143 *
144 */
145static int
146connect_peers_finish (void *cls,
147 GNUNET_SCHEDULER_TaskCallback cont,
148 void *cont_cls)
149{
150 struct ConnectPeersState *cps = cls;
151 const struct GNUNET_TESTING_Command *peer1_cmd;
152 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
153 unsigned int ret;
154 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
155 struct GNUNET_HashCode hc;
156 int node_number;
157
158 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (cps->start_peer_label);
159 GNUNET_TRANSPORT_get_trait_connected_peers_map_v2 (peer1_cmd,
160 &connected_peers_map);
161
162 node_number = 1;
163 GNUNET_CRYPTO_hash (&node_number, sizeof(node_number), &hc);
164
165 // TODO we need to store with a key identifying the netns node in the future. For now we have only one connecting node.
166 memcpy (key,
167 &hc,
168 sizeof (*key));
169 ret = GNUNET_CONTAINER_multishortmap_contains (connected_peers_map,
170 key);
171
172 if (GNUNET_YES == ret)
173 {
174 cont (cont_cls);
175 }
176
177 GNUNET_free (key);
178 return ret;
179}
180
181
182/**
183 * Trait function of this cmd does nothing.
184 *
185 */
186static int
187connect_peers_traits (void *cls,
188 const void **ret,
189 const char *trait,
190 unsigned int index)
191{
192 return GNUNET_OK;
193}
194
195
196/**
197 * The cleanup function of this cmd frees resources the cmd allocated.
198 *
199 */
200static void
201connect_peers_cleanup (void *cls,
202 const struct GNUNET_TESTING_Command *cmd)
203{
204 struct ConnectPeersState *cps = cls;
205
206 GNUNET_free (cps->id);
207 GNUNET_free (cps);
208}
209
210
211/**
212 * Create command.
213 *
214 * @param label name for command.
215 * @param start_peer_label Label of the cmd to start a peer.
216 * @return command.
217 */
218struct GNUNET_TESTING_Command
219GNUNET_TRANSPORT_cmd_connect_peers_v2 (const char *label,
220 const char *start_peer_label,
221 const char *create_label,
222 uint32_t num)
223{
224 struct ConnectPeersState *cps;
225
226 cps = GNUNET_new (struct ConnectPeersState);
227 cps->start_peer_label = start_peer_label;
228 cps->num = num;
229 cps->create_label = create_label;
230
231
232 struct GNUNET_TESTING_Command cmd = {
233 .cls = cps,
234 .label = label,
235 .run = &connect_peers_run,
236 .finish = &connect_peers_finish,
237 .cleanup = &connect_peers_cleanup,
238 .traits = &connect_peers_traits
239 };
240
241 return cmd;
242}
diff --git a/src/transport/transport_api_cmd_connecting_peers_v3.c b/src/transport/transport_api_cmd_connecting_peers_v3.c
deleted file mode 100644
index e90781637..000000000
--- a/src/transport/transport_api_cmd_connecting_peers_v3.c
+++ /dev/null
@@ -1,508 +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_transport_application_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_transport_service.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 CONNECT_ADDRESS_TEMPLATE_TCP "tcp-192.168.15.%u:60002"
40
41#define CONNECT_ADDRESS_TEMPLATE_UDP "udp-192.168.15.%u:60002"
42
43#define ROUTER_CONNECT_ADDRESS_TEMPLATE_TCP "tcp-92.68.150.%u:60002"
44
45#define ROUTER_CONNECT_ADDRESS_TEMPLATE_UDP "udp-92.68.150.%u:60002"
46
47#define GLOBAL_CONNECT_ADDRESS_TEMPLATE_TCP "tcp-92.68.151.%u:60002"
48
49#define GLOBAL_CONNECT_ADDRESS_TEMPLATE_UDP "udp-92.68.151.%u:60002"
50
51#define PREFIX_TCP "tcp"
52
53#define PREFIX_UDP "udp"
54
55/**
56 * Struct to store information needed in callbacks.
57 *
58 */
59struct ConnectPeersState
60{
61 /**
62 * The testing system of this node.
63 */
64 struct GNUNET_TESTING_System *tl_system;
65
66 // Label of the cmd which started the test system.
67 const char *create_label;
68
69 /**
70 * Number globally identifying the node.
71 *
72 */
73 uint32_t num;
74
75 /**
76 * Label of the cmd to start a peer.
77 *
78 */
79 const char *start_peer_label;
80
81 /**
82 * The peer identity of this peer.
83 *
84 */
85 struct GNUNET_PeerIdentity *id;
86
87 /**
88 * The topology of the test setup.
89 */
90 struct GNUNET_TESTING_NetjailTopology *topology;
91
92 /**
93 * Connections to other peers.
94 */
95 struct GNUNET_TESTING_NodeConnection *node_connections_head;
96
97 /**
98 * Number of connections.
99 */
100 unsigned int con_num;
101};
102
103
104static struct GNUNET_PeerIdentity *
105get_pub_key (unsigned int num, struct GNUNET_TESTING_System *tl_system)
106{
107 struct GNUNET_PeerIdentity *peer = GNUNET_new (struct GNUNET_PeerIdentity);
108 struct GNUNET_CRYPTO_EddsaPublicKey *pub_key = GNUNET_new (struct
109 GNUNET_CRYPTO_EddsaPublicKey);
110 struct GNUNET_CRYPTO_EddsaPrivateKey *priv_key = GNUNET_new (struct
111 GNUNET_CRYPTO_EddsaPrivateKey);
112
113 priv_key = GNUNET_TESTING_hostkey_get (tl_system,
114 num,
115 peer);
116
117 GNUNET_CRYPTO_eddsa_key_get_public (priv_key,
118 pub_key);
119 peer->public_key = *pub_key;
120 return peer;
121}
122
123
124static int
125log_nodes (void *cls, const struct GNUNET_ShortHashCode *id, void *value)
126{
127 struct GNUNET_TESTING_NetjailNode *node = value;
128 struct GNUNET_TESTING_NodeConnection *pos_connection;
129 struct GNUNET_TESTING_ADDRESS_PREFIX *pos_prefix;
130
131 LOG (GNUNET_ERROR_TYPE_ERROR,
132 "plugin: %s space: %u node: %u global: %u\n",
133 node->plugin,
134 node->namespace_n,
135 node->node_n,
136 node->is_global);
137
138 for (pos_connection = node->node_connections_head; NULL != pos_connection;
139 pos_connection = pos_connection->next)
140 {
141
142 LOG (GNUNET_ERROR_TYPE_ERROR,
143 "namespace_n: %u node_n: %u node_type: %u\n",
144 pos_connection->namespace_n,
145 pos_connection->node_n,
146 pos_connection->node_type);
147
148 for (pos_prefix = pos_connection->address_prefixes_head; NULL != pos_prefix;
149 pos_prefix =
150 pos_prefix->next)
151 {
152 LOG (GNUNET_ERROR_TYPE_ERROR,
153 "prefix: %s\n",
154 pos_prefix->address_prefix);
155 }
156 }
157 return GNUNET_YES;
158}
159
160
161static int
162log_namespaces (void *cls, const struct GNUNET_ShortHashCode *id, void *value)
163{
164 struct GNUNET_TESTING_NetjailNamespace *namespace = value;
165 struct GNUNET_TESTING_NetjailRouter *router = namespace->router;
166
167 LOG (GNUNET_ERROR_TYPE_ERROR,
168 "router_tcp: %u router_udp: %u spaces: %u\n",
169 router->tcp_port,
170 router->udp_port,
171 namespace->namespace_n);
172 GNUNET_CONTAINER_multishortmap_iterate (namespace->nodes, &log_nodes, NULL);
173 return GNUNET_YES;
174}
175
176
177static int
178log_topo (struct GNUNET_TESTING_NetjailTopology *topology)
179{
180 LOG (GNUNET_ERROR_TYPE_ERROR,
181 "plugin: %s spaces: %u nodes: %u known: %u\n",
182 topology->plugin,
183 topology->namespaces_n,
184 topology->nodes_m,
185 topology->nodes_x);
186
187 GNUNET_CONTAINER_multishortmap_iterate (topology->map_namespaces,
188 log_namespaces, NULL);
189 GNUNET_CONTAINER_multishortmap_iterate (topology->map_globals, &log_nodes,
190 NULL);
191 return GNUNET_YES;
192}
193
194
195static struct GNUNET_TESTING_NodeConnection *
196get_connections (unsigned int num, struct
197 GNUNET_TESTING_NetjailTopology *topology)
198{
199 struct GNUNET_TESTING_NetjailNode *node;
200 struct GNUNET_ShortHashCode *hkey;
201 struct GNUNET_HashCode hc;
202 struct GNUNET_TESTING_NetjailNamespace *namespace;
203 unsigned int namespace_n, node_m;
204
205 log_topo (topology);
206
207 hkey = GNUNET_new (struct GNUNET_ShortHashCode);
208 if (topology->nodes_x >= num)
209 {
210
211 GNUNET_CRYPTO_hash (&num, sizeof(num), &hc);
212 memcpy (hkey,
213 &hc,
214 sizeof (*hkey));
215 node = GNUNET_CONTAINER_multishortmap_get (topology->map_globals,
216 hkey);
217 }
218 else
219 {
220 namespace_n = (unsigned int) floor ((num - topology->nodes_x)
221 / topology->nodes_m);
222 LOG (GNUNET_ERROR_TYPE_ERROR,
223 "num: %u nodes_x: %u nodes_m: %u namespace_n: %u\n",
224 num,
225 topology->nodes_x,
226 topology->nodes_m,
227 namespace_n);
228 hkey = GNUNET_new (struct GNUNET_ShortHashCode);
229 GNUNET_CRYPTO_hash (&namespace_n, sizeof(namespace_n), &hc);
230 memcpy (hkey,
231 &hc,
232 sizeof (*hkey));
233 namespace = GNUNET_CONTAINER_multishortmap_get (topology->map_namespaces,
234 hkey);
235 node_m = num - topology->nodes_x - topology->nodes_m * (namespace_n - 1);
236 hkey = GNUNET_new (struct GNUNET_ShortHashCode);
237 GNUNET_CRYPTO_hash (&node_m, sizeof(node_m), &hc);
238 memcpy (hkey,
239 &hc,
240 sizeof (*hkey));
241 node = GNUNET_CONTAINER_multishortmap_get (namespace->nodes,
242 hkey);
243 }
244
245
246 return node->node_connections_head;
247}
248
249
250static unsigned int
251calculate_num (struct GNUNET_TESTING_NodeConnection *node_connection,
252 struct GNUNET_TESTING_NetjailTopology *topology)
253{
254 unsigned int n, m, num;
255
256 n = node_connection->namespace_n;
257 m = node_connection->node_n;
258
259 if (0 == n)
260 num = m;
261 else
262 num = (n - 1) * topology->nodes_m + m + topology->nodes_x;
263
264 return num;
265}
266
267static char *
268get_address (struct GNUNET_TESTING_NodeConnection *connection,
269 char *prefix)
270{
271 struct GNUNET_TESTING_NetjailNode *node;
272 char *addr;
273
274 node = connection->node;
275 if (connection->namespace_n == node->namespace_n)
276 {
277 if (0 == strcmp (PREFIX_TCP, prefix))
278 {
279
280 GNUNET_asprintf (&addr,
281 CONNECT_ADDRESS_TEMPLATE_TCP,
282 connection->node_n);
283 }
284 else if (0 == strcmp (PREFIX_UDP, prefix))
285 {
286 GNUNET_asprintf (&addr,
287 CONNECT_ADDRESS_TEMPLATE_UDP,
288 connection->node_n);
289 }
290 else
291 {
292 GNUNET_break (0);
293 }
294 }
295 else
296 {
297 if (0 == strcmp (PREFIX_TCP, prefix))
298 {
299
300 GNUNET_asprintf (&addr,
301 ROUTER_CONNECT_ADDRESS_TEMPLATE_TCP,
302 connection->namespace_n);
303 }
304 else if (0 == strcmp (PREFIX_UDP, prefix))
305 {
306 GNUNET_asprintf (&addr,
307 ROUTER_CONNECT_ADDRESS_TEMPLATE_UDP,
308 connection->namespace_n);
309 }
310 else
311 {
312 GNUNET_break (0);
313 }
314 }
315
316 return addr;
317}
318
319
320/**
321 * The run method of this cmd will connect to peers.
322 *
323 */
324static void
325connect_peers_run (void *cls,
326 const struct GNUNET_TESTING_Command *cmd,
327 struct GNUNET_TESTING_Interpreter *is)
328{
329 struct ConnectPeersState *cps = cls;
330 const struct GNUNET_TESTING_Command *system_cmd;
331 struct GNUNET_TESTING_System *tl_system;
332
333
334 const struct GNUNET_TESTING_Command *peer1_cmd;
335 struct GNUNET_TRANSPORT_ApplicationHandle *ah;
336 struct GNUNET_PeerIdentity *peer;
337 char *addr;
338 enum GNUNET_NetworkType nt = 0;
339 uint32_t num;
340 struct GNUNET_TESTING_NodeConnection *pos_connection;
341 struct GNUNET_TESTING_ADDRESS_PREFIX *pos_prefix;
342 unsigned int con_num = 0;
343
344 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (cps->start_peer_label);
345 GNUNET_TRANSPORT_get_trait_application_handle_v2 (peer1_cmd,
346 &ah);
347
348 system_cmd = GNUNET_TESTING_interpreter_lookup_command (cps->create_label);
349 GNUNET_TESTING_get_trait_test_system (system_cmd,
350 &tl_system);
351
352 cps->tl_system = tl_system;
353
354 cps->node_connections_head = get_connections (cps->num, cps->topology);
355
356 for (pos_connection = cps->node_connections_head; NULL != pos_connection;
357 pos_connection = pos_connection->next)
358 {
359 con_num++;
360 num = calculate_num (pos_connection, cps->topology);
361 for (pos_prefix = pos_connection->address_prefixes_head; NULL != pos_prefix;
362 pos_prefix =
363 pos_prefix->next)
364 {
365
366 LOG (GNUNET_ERROR_TYPE_ERROR,
367 "prefix: %s\n",
368 pos_prefix->address_prefix);
369
370 addr = get_address (pos_connection, pos_prefix->address_prefix);
371
372 peer = get_pub_key (num, tl_system);
373
374 LOG (GNUNET_ERROR_TYPE_ERROR,
375 "num: %u pub_key %s addr: %s\n",
376 num,
377 GNUNET_CRYPTO_eddsa_public_key_to_string (&(peer->public_key)),
378 addr);
379
380 cps->id = peer;
381
382 GNUNET_TRANSPORT_application_validate (ah,
383 peer,
384 nt,
385 addr);
386 }
387 }
388 cps->con_num = con_num;
389}
390
391
392/**
393 * The finish function of this cmd will check if the peers we are trying to
394 * connect to are in the connected peers map of the start peer cmd for this peer.
395 *
396 */
397static int
398connect_peers_finish (void *cls,
399 GNUNET_SCHEDULER_TaskCallback cont,
400 void *cont_cls)
401{
402 struct ConnectPeersState *cps = cls;
403 const struct GNUNET_TESTING_Command *peer1_cmd;
404 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
405 unsigned int ret;
406 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
407 struct GNUNET_HashCode hc;
408 struct GNUNET_PeerIdentity *peer;
409 unsigned int con_num = 0;
410 struct GNUNET_TESTING_NodeConnection *pos_connection;
411 unsigned int num;
412
413 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (cps->start_peer_label);
414 GNUNET_TRANSPORT_get_trait_connected_peers_map_v2 (peer1_cmd,
415 &connected_peers_map);
416
417 for (pos_connection = cps->node_connections_head; NULL != pos_connection;
418 pos_connection = pos_connection->next)
419 {
420 num = calculate_num (pos_connection, cps->topology);
421 peer = get_pub_key (num, cps->tl_system);
422 GNUNET_CRYPTO_hash (&(peer->public_key), sizeof(peer->public_key), &hc);
423 memcpy (key,
424 &hc,
425 sizeof (*key));
426 if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains (
427 connected_peers_map,
428 key))
429 con_num++;
430 }
431
432
433
434 if (cps->con_num == con_num)
435 {
436 cont (cont_cls);
437 ret = GNUNET_YES;
438 }
439
440 GNUNET_free (key);
441 return ret;
442}
443
444
445/**
446 * Trait function of this cmd does nothing.
447 *
448 */
449static int
450connect_peers_traits (void *cls,
451 const void **ret,
452 const char *trait,
453 unsigned int index)
454{
455 return GNUNET_OK;
456}
457
458
459/**
460 * The cleanup function of this cmd frees resources the cmd allocated.
461 *
462 */
463static void
464connect_peers_cleanup (void *cls,
465 const struct GNUNET_TESTING_Command *cmd)
466{
467 struct ConnectPeersState *cps = cls;
468
469 GNUNET_free (cps->id);
470 GNUNET_free (cps);
471}
472
473
474/**
475 * Create command.
476 *
477 * @param label name for command.
478 * @param start_peer_label Label of the cmd to start a peer.
479 * @return command.
480 */
481struct GNUNET_TESTING_Command
482GNUNET_TRANSPORT_cmd_connect_peers_v3 (const char *label,
483 const char *start_peer_label,
484 const char *create_label,
485 uint32_t num,
486 struct GNUNET_TESTING_NetjailTopology *
487 topology)
488{
489 struct ConnectPeersState *cps;
490
491 cps = GNUNET_new (struct ConnectPeersState);
492 cps->start_peer_label = start_peer_label;
493 cps->num = num;
494 cps->create_label = create_label;
495 cps->topology = topology;
496
497
498 struct GNUNET_TESTING_Command cmd = {
499 .cls = cps,
500 .label = label,
501 .run = &connect_peers_run,
502 .finish = &connect_peers_finish,
503 .cleanup = &connect_peers_cleanup,
504 .traits = &connect_peers_traits
505 };
506
507 return cmd;
508}
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 f9e515c0f..000000000
--- a/src/transport/transport_api_cmd_send_simple.c
+++ /dev/null
@@ -1,172 +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 "transport-testing2.h"
30#include "transport-testing-cmds.h"
31
32/**
33 * Struct to hold information for callbacks.
34 *
35 */
36struct SendSimpleState
37{
38 /**
39 * The number of the local node of the actual network namespace.
40 *
41 */
42 char *m;
43
44 /**
45 * The number of the actual namespace.
46 *
47 */
48 char *n;
49
50 /**
51 * Number globally identifying the node.
52 *
53 */
54 uint32_t num;
55
56 /**
57 * Label of the cmd to start a peer.
58 *
59 */
60 const char *start_peer_label;
61};
62
63
64/**
65 * Trait function of this cmd does nothing.
66 *
67 */
68static int
69send_simple_traits (void *cls,
70 const void **ret,
71 const char *trait,
72 unsigned int index)
73{
74 return GNUNET_OK;
75}
76
77
78/**
79 * The cleanup function of this cmd frees resources the cmd allocated.
80 *
81 */
82static void
83send_simple_cleanup (void *cls,
84 const struct GNUNET_TESTING_Command *cmd)
85{
86 struct SendSimpleState *sss = cls;
87
88 GNUNET_free (sss);
89}
90
91
92/**
93 * The run method of this cmd will send a simple message to the connected peer.
94 *
95 */
96static void
97send_simple_run (void *cls,
98 const struct GNUNET_TESTING_Command *cmd,
99 struct GNUNET_TESTING_Interpreter *is)
100{
101 struct SendSimpleState *sss = cls;
102 struct GNUNET_MQ_Envelope *env;
103 struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
104 struct GNUNET_MQ_Handle *mq;
105 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
106 const struct GNUNET_TESTING_Command *peer1_cmd;
107 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
108 struct GNUNET_HashCode hc;
109 int node_number;
110
111 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (sss->start_peer_label);
112 GNUNET_TRANSPORT_get_trait_connected_peers_map (peer1_cmd,
113 &connected_peers_map);
114
115 node_number = 1;
116 GNUNET_CRYPTO_hash (&node_number, sizeof(node_number), &hc);
117 memcpy (key,
118 &hc,
119 sizeof (*key));
120
121 mq = GNUNET_CONTAINER_multishortmap_get (connected_peers_map,
122 key);
123
124 env = GNUNET_MQ_msg_extra (test,
125 2600 - sizeof(*test),
126 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE);
127 test->num = htonl (sss->num);
128 memset (&test[1],
129 sss->num,
130 2600 - sizeof(*test));
131 GNUNET_MQ_send (mq,
132 env);
133 GNUNET_free (key);
134
135}
136
137
138/**
139 * Create command.
140 *
141 * @param label name for command.
142 * @param m The number of the local node of the actual network namespace.
143 * @param n The number of the actual namespace.
144 * @param num Number globally identifying the node.
145 * @param start_peer_label Label of the cmd to start a peer.
146 * @return command.
147 */
148struct GNUNET_TESTING_Command
149GNUNET_TRANSPORT_cmd_send_simple (const char *label,
150 char *m,
151 char *n,
152 uint32_t num,
153 const char *start_peer_label)
154{
155 struct SendSimpleState *sss;
156
157 sss = GNUNET_new (struct SendSimpleState);
158 sss->m = m;
159 sss->n = n;
160 sss->num = num;
161 sss->start_peer_label = start_peer_label;
162
163 struct GNUNET_TESTING_Command cmd = {
164 .cls = sss,
165 .label = label,
166 .run = &send_simple_run,
167 .cleanup = &send_simple_cleanup,
168 .traits = &send_simple_traits
169 };
170
171 return cmd;
172}
diff --git a/src/transport/transport_api_cmd_send_simple_v2.c b/src/transport/transport_api_cmd_send_simple_v2.c
deleted file mode 100644
index d43c0b425..000000000
--- a/src/transport/transport_api_cmd_send_simple_v2.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_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 "transport-testing2.h"
30#include "transport-testing-cmds.h"
31
32/**
33 * Struct to hold information for callbacks.
34 *
35 */
36struct SendSimpleState
37{
38 /**
39 * Number globally identifying the node.
40 *
41 */
42 uint32_t num;
43
44 /**
45 * Label of the cmd to start a peer.
46 *
47 */
48 const char *start_peer_label;
49};
50
51
52/**
53 * Trait function of this cmd does nothing.
54 *
55 */
56static int
57send_simple_traits (void *cls,
58 const void **ret,
59 const char *trait,
60 unsigned int index)
61{
62 return GNUNET_OK;
63}
64
65
66/**
67 * The cleanup function of this cmd frees resources the cmd allocated.
68 *
69 */
70static void
71send_simple_cleanup (void *cls,
72 const struct GNUNET_TESTING_Command *cmd)
73{
74 struct SendSimpleState *sss = cls;
75
76 GNUNET_free (sss);
77}
78
79
80/**
81 * The run method of this cmd will send a simple message to the connected peer.
82 *
83 */
84static void
85send_simple_run (void *cls,
86 const struct GNUNET_TESTING_Command *cmd,
87 struct GNUNET_TESTING_Interpreter *is)
88{
89 struct SendSimpleState *sss = cls;
90 struct GNUNET_MQ_Envelope *env;
91 struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
92 struct GNUNET_MQ_Handle *mq;
93 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
94 const struct GNUNET_TESTING_Command *peer1_cmd;
95 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
96 struct GNUNET_HashCode hc;
97 int node_number;
98
99 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (sss->start_peer_label);
100 GNUNET_TRANSPORT_get_trait_connected_peers_map (peer1_cmd,
101 &connected_peers_map);
102
103 node_number = 1;
104 GNUNET_CRYPTO_hash (&node_number, sizeof(node_number), &hc);
105 memcpy (key,
106 &hc,
107 sizeof (*key));
108
109 mq = GNUNET_CONTAINER_multishortmap_get (connected_peers_map,
110 key);
111
112 env = GNUNET_MQ_msg_extra (test,
113 2600 - sizeof(*test),
114 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE);
115 test->num = htonl (sss->num);
116 memset (&test[1],
117 sss->num,
118 2600 - sizeof(*test));
119 GNUNET_MQ_send (mq,
120 env);
121 GNUNET_free (key);
122
123}
124
125
126/**
127 * Create command.
128 *
129 * @param label name for command.
130 * @param m The number of the local node of the actual network namespace.
131 * @param n The number of the actual namespace.
132 * @param num Number globally identifying the node.
133 * @param start_peer_label Label of the cmd to start a peer.
134 * @return command.
135 */
136struct GNUNET_TESTING_Command
137GNUNET_TRANSPORT_cmd_send_simple_v2 (const char *label,
138 const char *start_peer_label,
139 uint32_t num)
140{
141 struct SendSimpleState *sss;
142
143 sss = GNUNET_new (struct SendSimpleState);
144 sss->num = num;
145 sss->start_peer_label = start_peer_label;
146
147 struct GNUNET_TESTING_Command cmd = {
148 .cls = sss,
149 .label = label,
150 .run = &send_simple_run,
151 .cleanup = &send_simple_cleanup,
152 .traits = &send_simple_traits
153 };
154
155 return cmd;
156}
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 f4e92944b..000000000
--- a/src/transport/transport_api_cmd_start_peer.c
+++ /dev/null
@@ -1,611 +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_peerstore_service.h"
30#include "gnunet_transport_core_service.h"
31#include "gnunet_transport_application_service.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
40static void
41retrieve_hello (void *cls);
42
43
44/**
45 * Callback delivering the hello of this peer from peerstore.
46 *
47 */
48static void
49hello_iter_cb (void *cb_cls,
50 const struct GNUNET_PEERSTORE_Record *record,
51 const char *emsg)
52{
53 struct StartPeerState *sps = cb_cls;
54 if (NULL == record)
55 {
56 sps->pic = NULL;
57 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
58 return;
59 }
60 // Check record type et al?
61 sps->hello_size = record->value_size;
62 sps->hello = GNUNET_malloc (sps->hello_size);
63 memcpy (sps->hello, record->value, sps->hello_size);
64 sps->hello[sps->hello_size - 1] = '\0';
65
66 GNUNET_PEERSTORE_iterate_cancel (sps->pic);
67 sps->pic = NULL;
68 sps->finished = GNUNET_YES;
69}
70
71
72/**
73 * Function to start the retrieval task to retrieve the hello of this peer
74 * from the peerstore.
75 *
76 */
77static void
78retrieve_hello (void *cls)
79{
80 struct StartPeerState *sps = cls;
81 sps->rh_task = NULL;
82 sps->pic = GNUNET_PEERSTORE_iterate (sps->ph,
83 "transport",
84 &sps->id,
85 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
86 hello_iter_cb,
87 sps);
88
89}
90
91
92/**
93 * This function checks StartPeerState#finished, which is set when the hello was retrieved.
94 *
95 */
96static int
97start_peer_finish (void *cls,
98 GNUNET_SCHEDULER_TaskCallback cont,
99 void *cont_cls)
100{
101 struct StartPeerState *sps = cls;
102
103 if (GNUNET_YES == sps->finished)
104 {
105 cont (cont_cls);
106 }
107
108 return sps->finished;
109}
110
111
112/**
113 * Disconnect callback for the connection to the core service.
114 *
115 */
116static void
117notify_disconnect (void *cls,
118 const struct GNUNET_PeerIdentity *peer,
119 void *handler_cls)
120{
121 struct StartPeerState *sps = cls;
122
123 LOG (GNUNET_ERROR_TYPE_DEBUG,
124 "Peer %s disconnected from peer %u (`%s')\n",
125 GNUNET_i2s (peer),
126 sps->no,
127 GNUNET_i2s (&sps->id));
128
129}
130
131
132/**
133 * Connect callback for the connection to the core service.
134 *
135 */
136static void *
137notify_connect (void *cls,
138 const struct GNUNET_PeerIdentity *peer,
139 struct GNUNET_MQ_Handle *mq)
140{
141 struct StartPeerState *sps = cls;
142 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
143 struct GNUNET_HashCode hc;
144 int node_number;
145
146 void *ret = NULL;
147
148
149 LOG (GNUNET_ERROR_TYPE_DEBUG,
150 "Peer %s connected to peer %u (`%s')\n",
151 GNUNET_i2s (peer),
152 sps->no,
153 GNUNET_i2s (&sps->id));
154
155 // TODO we need to store with a key identifying the netns node in the future. For now we have only one connecting node.
156 node_number = 1;
157 GNUNET_CRYPTO_hash (&node_number, sizeof(node_number), &hc);
158
159
160 memcpy (key,
161 &hc,
162 sizeof (*key));
163 GNUNET_CONTAINER_multishortmap_put (sps->connected_peers_map,
164 key,
165 mq,
166 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
167
168 GNUNET_free (key);
169 // TODO what does the handler function need?
170 return ret;
171}
172
173
174/**
175 * The run method of this cmd will start all services of a peer to test the transport service.
176 *
177 */
178static void
179start_peer_run (void *cls,
180 const struct GNUNET_TESTING_Command *cmd,
181 struct GNUNET_TESTING_Interpreter *is)
182{
183 struct StartPeerState *sps = cls;
184 char *emsg = NULL;
185 struct GNUNET_PeerIdentity dummy;
186 const struct GNUNET_TESTING_Command *system_cmd;
187 struct GNUNET_TESTING_System *tl_system;
188 char *home;
189 char *transport_unix_path;
190 char *communicator_unix_path;
191 char *bindto;
192
193 if (GNUNET_NO == GNUNET_DISK_file_test (sps->cfgname))
194 {
195 LOG (GNUNET_ERROR_TYPE_ERROR,
196 "File not found: `%s'\n",
197 sps->cfgname);
198 GNUNET_TESTING_interpreter_fail ();
199 return;
200 }
201
202
203 sps->cfg = GNUNET_CONFIGURATION_create ();
204 GNUNET_assert (GNUNET_OK ==
205 GNUNET_CONFIGURATION_load (sps->cfg, sps->cfgname));
206
207 GNUNET_asprintf (&home,
208 "$GNUNET_TMP/test-transport/api-tcp-p%u",
209 sps->no);
210
211 GNUNET_asprintf (&transport_unix_path,
212 "$GNUNET_RUNTIME_DIR/tng-p%u.sock",
213 sps->no);
214
215 GNUNET_asprintf (&communicator_unix_path,
216 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
217 sps->no);
218
219 GNUNET_asprintf (&bindto,
220 "%s:60002",
221 sps->node_ip);
222
223
224 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "PATHS", "GNUNET_TEST_HOME",
225 home);
226 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "transport", "UNIXPATH",
227 transport_unix_path);
228 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
229 "BINDTO",
230 bindto);
231 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
232 "UNIXPATH",
233 communicator_unix_path);
234
235 system_cmd = GNUNET_TESTING_interpreter_lookup_command (sps->system_label);
236 GNUNET_TESTING_get_trait_test_system (system_cmd,
237 &tl_system);
238
239 sps->tl_system = tl_system;
240
241 if (GNUNET_SYSERR ==
242 GNUNET_TESTING_configuration_create (tl_system,
243 sps->cfg))
244 {
245 LOG (GNUNET_ERROR_TYPE_ERROR,
246 "Testing library failed to create unique configuration based on `%s'\n",
247 sps->cfgname);
248 GNUNET_CONFIGURATION_destroy (sps->cfg);
249 GNUNET_TESTING_interpreter_fail ();
250 return;
251 }
252
253 sps->peer = GNUNET_TESTING_peer_configure (sps->tl_system,
254 sps->cfg,
255 sps->no,
256 NULL,
257 &emsg);
258 if (NULL == sps->peer)
259 {
260 LOG (GNUNET_ERROR_TYPE_ERROR,
261 "Testing library failed to create unique configuration based on `%s': `%s'\n",
262 sps->cfgname,
263 emsg);
264 GNUNET_free (emsg);
265 GNUNET_TESTING_interpreter_fail ();
266 return;
267 }
268
269 if (GNUNET_OK != GNUNET_TESTING_peer_start (sps->peer))
270 {
271 LOG (GNUNET_ERROR_TYPE_ERROR,
272 "Testing library failed to create unique configuration based on `%s'\n",
273 sps->cfgname);
274 GNUNET_free (emsg);
275 GNUNET_TESTING_interpreter_fail ();
276 return;
277 }
278
279 memset (&dummy,
280 '\0',
281 sizeof(dummy));
282
283 GNUNET_TESTING_peer_get_identity (sps->peer,
284 &sps->id);
285
286 if (0 == memcmp (&dummy,
287 &sps->id,
288 sizeof(struct GNUNET_PeerIdentity)))
289 {
290 LOG (GNUNET_ERROR_TYPE_ERROR,
291 "Testing library failed to obtain peer identity for peer %u\n",
292 sps->no);
293 GNUNET_free (emsg);
294 GNUNET_TESTING_interpreter_fail ();
295 return;
296 }
297 LOG (GNUNET_ERROR_TYPE_DEBUG,
298 "Peer %u configured with identity `%s'\n",
299 sps->no,
300 GNUNET_i2s_full (&sps->id));
301
302 sps->th = GNUNET_TRANSPORT_core_connect (sps->cfg,
303 NULL,
304 sps->handlers,
305 sps,
306 &notify_connect,
307 &notify_disconnect);
308 if (NULL == sps->th)
309 {
310 LOG (GNUNET_ERROR_TYPE_ERROR,
311 "Failed to connect to transport service for peer `%s': `%s'\n",
312 sps->cfgname,
313 emsg);
314 GNUNET_free (emsg);
315 GNUNET_TESTING_interpreter_fail ();
316 return;
317 }
318
319 sps->ph = GNUNET_PEERSTORE_connect (sps->cfg);
320 if (NULL == sps->th)
321 {
322 LOG (GNUNET_ERROR_TYPE_ERROR,
323 "Failed to connect to peerstore service for peer `%s': `%s'\n",
324 sps->cfgname,
325 emsg);
326 GNUNET_free (emsg);
327 GNUNET_TESTING_interpreter_fail ();
328 return;
329 }
330
331 sps->ah = GNUNET_TRANSPORT_application_init (sps->cfg);
332 if (NULL == sps->ah)
333 {
334 LOG (GNUNET_ERROR_TYPE_ERROR,
335 "Failed to initialize the TRANSPORT application suggestion client handle for peer `%s': `%s'\n",
336 sps->cfgname,
337 emsg);
338 GNUNET_free (emsg);
339 GNUNET_TESTING_interpreter_fail ();
340 return;
341 }
342 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
343}
344
345
346/**
347 * The cleanup function of this cmd frees resources the cmd allocated.
348 *
349 */
350static void
351start_peer_cleanup (void *cls,
352 const struct GNUNET_TESTING_Command *cmd)
353{
354 struct StartPeerState *sps = cls;
355
356 if (NULL != sps->handlers)
357 {
358 GNUNET_free (sps->handlers);
359 sps->handlers = NULL;
360 }
361 if (NULL != sps->cfg)
362 {
363 GNUNET_CONFIGURATION_destroy (sps->cfg);
364 sps->cfg = NULL;
365 }
366 GNUNET_free (sps->hello);
367 GNUNET_free (sps->connected_peers_map);
368 GNUNET_free (sps);
369}
370
371
372/**
373 * This function prepares an array with traits.
374 *
375 */
376static int
377start_peer_traits (void *cls,
378 const void **ret,
379 const char *trait,
380 unsigned int index)
381{
382 struct StartPeerState *sps = cls;
383 struct GNUNET_TRANSPORT_ApplicationHandle *ah = sps->ah;
384 struct GNUNET_PeerIdentity *id = &sps->id;
385 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
386 sps->connected_peers_map;
387 char *hello = sps->hello;
388 size_t hello_size = sps->hello_size;
389
390
391 struct GNUNET_TESTING_Trait traits[] = {
392 {
393 .index = 0,
394 .trait_name = "application_handle",
395 .ptr = (const void *) ah,
396 },
397 {
398 .index = 1,
399 .trait_name = "peer_id",
400 .ptr = (const void *) id,
401 },
402 {
403 .index = 2,
404 .trait_name = "connected_peers_map",
405 .ptr = (const void *) connected_peers_map,
406 },
407 {
408 .index = 3,
409 .trait_name = "hello",
410 .ptr = (const void *) hello,
411 },
412 {
413 .index = 4,
414 .trait_name = "hello_size",
415 .ptr = (const void *) hello_size,
416 },
417 {
418 .index = 5,
419 .trait_name = "state",
420 .ptr = (const void *) sps,
421 },
422 GNUNET_TESTING_trait_end ()
423 };
424
425 return GNUNET_TESTING_get_trait (traits,
426 ret,
427 trait,
428 index);
429}
430
431
432/**
433 * Function to get the trait with the struct StartPeerState.
434 *
435 * @param[out] sps struct StartPeerState.
436 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
437 *
438 */
439int
440GNUNET_TRANSPORT_get_trait_state (const struct
441 GNUNET_TESTING_Command
442 *cmd,
443 struct StartPeerState **sps)
444{
445 return cmd->traits (cmd->cls,
446 (const void **) sps,
447 "state",
448 (unsigned int) 5);
449}
450
451
452/**
453 * Function to get the trait with the size of the hello.
454 *
455 * @param[out] hello_size size of hello.
456 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
457 *
458 */
459int
460GNUNET_TRANSPORT_get_trait_hello_size (const struct
461 GNUNET_TESTING_Command
462 *cmd,
463 size_t **hello_size)
464{
465 return cmd->traits (cmd->cls,
466 (const void **) hello_size,
467 "hello_size",
468 (unsigned int) 4);
469}
470
471
472/**
473 * Function to get the trait with the hello.
474 *
475 * @param[out] hello The hello for the peer.
476 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
477 *
478 */
479int
480GNUNET_TRANSPORT_get_trait_hello (const struct
481 GNUNET_TESTING_Command
482 *cmd,
483 char **hello)
484{
485 return cmd->traits (cmd->cls,
486 (const void **) hello,
487 "hello",
488 (unsigned int) 3);
489}
490
491
492/**
493 * Function to get the trait with the map of connected peers.
494 *
495 * @param[out] connected_peers_map The map with connected peers.
496 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
497 *
498 */
499int
500GNUNET_TRANSPORT_get_trait_connected_peers_map (const struct
501 GNUNET_TESTING_Command
502 *cmd,
503 struct
504 GNUNET_CONTAINER_MultiShortmap *
505 *
506 connected_peers_map)
507{
508 return cmd->traits (cmd->cls,
509 (const void **) connected_peers_map,
510 "connected_peers_map",
511 (unsigned int) 2);
512}
513
514
515/**
516 * Function to get the trait with the transport application handle.
517 *
518 * @param[out] ah The application handle.
519 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
520 */
521int
522GNUNET_TRANSPORT_get_trait_application_handle (const struct
523 GNUNET_TESTING_Command *cmd,
524 struct
525 GNUNET_TRANSPORT_ApplicationHandle
526 **ah)
527{
528 return cmd->traits (cmd->cls,
529 (const void **) ah,
530 "application_handle",
531 (unsigned int) 0);
532}
533
534
535/**
536 * Function to get the trait with the peer id.
537 *
538 * @param[out] id The peer id.
539 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
540 */
541int
542GNUNET_TRANSPORT_get_trait_peer_id (const struct
543 GNUNET_TESTING_Command *cmd,
544 struct GNUNET_PeerIdentity **id)
545{
546 return cmd->traits (cmd->cls,
547 (const void **) id,
548 "peer_id",
549 (unsigned int) 1);
550}
551
552
553/**
554 * Create command.
555 *
556 * @param label name for command.
557 * @param system_label Label of the cmd to setup a test environment.
558 * @param m The number of the local node of the actual network namespace.
559 * @param n The number of the actual namespace.
560 * @param local_m Number of local nodes in each namespace.
561 * @param handlers Handler for messages received by this peer.
562 * @param cfgname Configuration file name for this peer.
563 * @return command.
564 */
565struct GNUNET_TESTING_Command
566GNUNET_TRANSPORT_cmd_start_peer (const char *label,
567 const char *system_label,
568 char *m,
569 char *n,
570 char *local_m,
571 char *node_ip,
572 struct GNUNET_MQ_MessageHandler *handlers,
573 const char *cfgname)
574{
575 struct StartPeerState *sps;
576 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
577 GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO);
578 unsigned int i;
579
580 sps = GNUNET_new (struct StartPeerState);
581 sps->m = m;
582 sps->n = n;
583 sps->local_m = local_m;
584 sps->no = (atoi (n) - 1) * atoi (sps->local_m) + atoi (m);
585 sps->system_label = system_label;
586 sps->connected_peers_map = connected_peers_map;
587 sps->cfgname = cfgname;
588 sps->node_ip = node_ip;
589
590 if (NULL != handlers)
591 {
592 for (i = 0; NULL != handlers[i].cb; i++)
593 ;
594 sps->handlers = GNUNET_new_array (i + 1,
595 struct GNUNET_MQ_MessageHandler);
596 GNUNET_memcpy (sps->handlers,
597 handlers,
598 i * sizeof(struct GNUNET_MQ_MessageHandler));
599 }
600
601 struct GNUNET_TESTING_Command cmd = {
602 .cls = sps,
603 .label = label,
604 .run = &start_peer_run,
605 .finish = &start_peer_finish,
606 .cleanup = &start_peer_cleanup,
607 .traits = &start_peer_traits
608 };
609
610 return cmd;
611}
diff --git a/src/transport/transport_api_cmd_start_peer_v2.c b/src/transport/transport_api_cmd_start_peer_v2.c
deleted file mode 100644
index 0e39bd915..000000000
--- a/src/transport/transport_api_cmd_start_peer_v2.c
+++ /dev/null
@@ -1,607 +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_peerstore_service.h"
30#include "gnunet_transport_core_service.h"
31#include "gnunet_transport_application_service.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
40static void
41retrieve_hello (void *cls);
42
43
44/**
45 * Callback delivering the hello of this peer from peerstore.
46 *
47 */
48static void
49hello_iter_cb (void *cb_cls,
50 const struct GNUNET_PEERSTORE_Record *record,
51 const char *emsg)
52{
53 struct StartPeerState_v2 *sps = cb_cls;
54 if (NULL == record)
55 {
56 sps->pic = NULL;
57 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
58 return;
59 }
60 // Check record type et al?
61 sps->hello_size = record->value_size;
62 sps->hello = GNUNET_malloc (sps->hello_size);
63 memcpy (sps->hello, record->value, sps->hello_size);
64 sps->hello[sps->hello_size - 1] = '\0';
65
66 GNUNET_PEERSTORE_iterate_cancel (sps->pic);
67 sps->pic = NULL;
68 sps->finished = GNUNET_YES;
69}
70
71
72/**
73 * Function to start the retrieval task to retrieve the hello of this peer
74 * from the peerstore.
75 *
76 */
77static void
78retrieve_hello (void *cls)
79{
80 struct StartPeerState_v2 *sps = cls;
81 sps->rh_task = NULL;
82 sps->pic = GNUNET_PEERSTORE_iterate (sps->ph,
83 "transport",
84 &sps->id,
85 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
86 hello_iter_cb,
87 sps);
88
89}
90
91
92/**
93 * This function checks StartPeerState_v2#finished, which is set when the hello was retrieved.
94 *
95 */
96static int
97start_peer_finish (void *cls,
98 GNUNET_SCHEDULER_TaskCallback cont,
99 void *cont_cls)
100{
101 struct StartPeerState_v2 *sps = cls;
102
103 if (GNUNET_YES == sps->finished)
104 {
105 cont (cont_cls);
106 }
107
108 return sps->finished;
109}
110
111
112/**
113 * Disconnect callback for the connection to the core service.
114 *
115 */
116static void
117notify_disconnect (void *cls,
118 const struct GNUNET_PeerIdentity *peer,
119 void *handler_cls)
120{
121 struct StartPeerState_v2 *sps = cls;
122
123 LOG (GNUNET_ERROR_TYPE_DEBUG,
124 "Peer %s disconnected from peer %u (`%s')\n",
125 GNUNET_i2s (peer),
126 sps->no,
127 GNUNET_i2s (&sps->id));
128
129}
130
131
132/**
133 * Connect callback for the connection to the core service.
134 *
135 */
136static void *
137notify_connect (void *cls,
138 const struct GNUNET_PeerIdentity *peer,
139 struct GNUNET_MQ_Handle *mq)
140{
141 struct StartPeerState_v2 *sps = cls;
142 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
143 struct GNUNET_HashCode hc;
144 int node_number;
145
146 void *ret = NULL;
147
148
149 LOG (GNUNET_ERROR_TYPE_DEBUG,
150 "Peer %s connected to peer %u (`%s')\n",
151 GNUNET_i2s (peer),
152 sps->no,
153 GNUNET_i2s (&sps->id));
154
155 // TODO we need to store with a key identifying the netns node in the future. For now we have only one connecting node.
156 node_number = 1;
157 GNUNET_CRYPTO_hash (&node_number, sizeof(node_number), &hc);
158
159
160 memcpy (key,
161 &hc,
162 sizeof (*key));
163 GNUNET_CONTAINER_multishortmap_put (sps->connected_peers_map,
164 key,
165 mq,
166 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
167
168 GNUNET_free (key);
169 // TODO what does the handler function need?
170 return ret;
171}
172
173
174/**
175 * The run method of this cmd will start all services of a peer to test the transport service.
176 *
177 */
178static void
179start_peer_run (void *cls,
180 const struct GNUNET_TESTING_Command *cmd,
181 struct GNUNET_TESTING_Interpreter *is)
182{
183 struct StartPeerState_v2 *sps = cls;
184 char *emsg = NULL;
185 struct GNUNET_PeerIdentity dummy;
186 const struct GNUNET_TESTING_Command *system_cmd;
187 struct GNUNET_TESTING_System *tl_system;
188 char *home;
189 char *transport_unix_path;
190 char *communicator_unix_path;
191 char *bindto;
192
193 if (GNUNET_NO == GNUNET_DISK_file_test (sps->cfgname))
194 {
195 LOG (GNUNET_ERROR_TYPE_ERROR,
196 "File not found: `%s'\n",
197 sps->cfgname);
198 GNUNET_TESTING_interpreter_fail ();
199 return;
200 }
201
202
203 sps->cfg = GNUNET_CONFIGURATION_create ();
204 GNUNET_assert (GNUNET_OK ==
205 GNUNET_CONFIGURATION_load (sps->cfg, sps->cfgname));
206
207 GNUNET_asprintf (&home,
208 "$GNUNET_TMP/test-transport/api-tcp-p%u",
209 sps->no);
210
211 GNUNET_asprintf (&transport_unix_path,
212 "$GNUNET_RUNTIME_DIR/tng-p%u.sock",
213 sps->no);
214
215 GNUNET_asprintf (&communicator_unix_path,
216 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
217 sps->no);
218
219 GNUNET_asprintf (&bindto,
220 "%s:60002",
221 sps->node_ip);
222
223
224 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "PATHS", "GNUNET_TEST_HOME",
225 home);
226 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "transport", "UNIXPATH",
227 transport_unix_path);
228 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
229 "BINDTO",
230 bindto);
231 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
232 "UNIXPATH",
233 communicator_unix_path);
234
235 system_cmd = GNUNET_TESTING_interpreter_lookup_command (sps->system_label);
236 GNUNET_TESTING_get_trait_test_system (system_cmd,
237 &tl_system);
238
239 sps->tl_system = tl_system;
240
241 if (GNUNET_SYSERR ==
242 GNUNET_TESTING_configuration_create (tl_system,
243 sps->cfg))
244 {
245 LOG (GNUNET_ERROR_TYPE_ERROR,
246 "Testing library failed to create unique configuration based on `%s'\n",
247 sps->cfgname);
248 GNUNET_CONFIGURATION_destroy (sps->cfg);
249 GNUNET_TESTING_interpreter_fail ();
250 return;
251 }
252
253 sps->peer = GNUNET_TESTING_peer_configure (sps->tl_system,
254 sps->cfg,
255 sps->no,
256 NULL,
257 &emsg);
258 if (NULL == sps->peer)
259 {
260 LOG (GNUNET_ERROR_TYPE_ERROR,
261 "Testing library failed to create unique configuration based on `%s': `%s'\n",
262 sps->cfgname,
263 emsg);
264 GNUNET_free (emsg);
265 GNUNET_TESTING_interpreter_fail ();
266 return;
267 }
268
269 if (GNUNET_OK != GNUNET_TESTING_peer_start (sps->peer))
270 {
271 LOG (GNUNET_ERROR_TYPE_ERROR,
272 "Testing library failed to create unique configuration based on `%s'\n",
273 sps->cfgname);
274 GNUNET_free (emsg);
275 GNUNET_TESTING_interpreter_fail ();
276 return;
277 }
278
279 memset (&dummy,
280 '\0',
281 sizeof(dummy));
282
283 GNUNET_TESTING_peer_get_identity (sps->peer,
284 &sps->id);
285
286 if (0 == memcmp (&dummy,
287 &sps->id,
288 sizeof(struct GNUNET_PeerIdentity)))
289 {
290 LOG (GNUNET_ERROR_TYPE_ERROR,
291 "Testing library failed to obtain peer identity for peer %u\n",
292 sps->no);
293 GNUNET_free (emsg);
294 GNUNET_TESTING_interpreter_fail ();
295 return;
296 }
297 LOG (GNUNET_ERROR_TYPE_DEBUG,
298 "Peer %u configured with identity `%s'\n",
299 sps->no,
300 GNUNET_i2s_full (&sps->id));
301
302 sps->th = GNUNET_TRANSPORT_core_connect (sps->cfg,
303 NULL,
304 sps->handlers,
305 sps,
306 &notify_connect,
307 &notify_disconnect);
308 if (NULL == sps->th)
309 {
310 LOG (GNUNET_ERROR_TYPE_ERROR,
311 "Failed to connect to transport service for peer `%s': `%s'\n",
312 sps->cfgname,
313 emsg);
314 GNUNET_free (emsg);
315 GNUNET_TESTING_interpreter_fail ();
316 return;
317 }
318
319 sps->ph = GNUNET_PEERSTORE_connect (sps->cfg);
320 if (NULL == sps->th)
321 {
322 LOG (GNUNET_ERROR_TYPE_ERROR,
323 "Failed to connect to peerstore service for peer `%s': `%s'\n",
324 sps->cfgname,
325 emsg);
326 GNUNET_free (emsg);
327 GNUNET_TESTING_interpreter_fail ();
328 return;
329 }
330
331 sps->ah = GNUNET_TRANSPORT_application_init (sps->cfg);
332 if (NULL == sps->ah)
333 {
334 LOG (GNUNET_ERROR_TYPE_ERROR,
335 "Failed to initialize the TRANSPORT application suggestion client handle for peer `%s': `%s'\n",
336 sps->cfgname,
337 emsg);
338 GNUNET_free (emsg);
339 GNUNET_TESTING_interpreter_fail ();
340 return;
341 }
342 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
343}
344
345
346/**
347 * The cleanup function of this cmd frees resources the cmd allocated.
348 *
349 */
350static void
351start_peer_cleanup (void *cls,
352 const struct GNUNET_TESTING_Command *cmd)
353{
354 struct StartPeerState_v2 *sps = cls;
355
356 if (NULL != sps->handlers)
357 {
358 GNUNET_free (sps->handlers);
359 sps->handlers = NULL;
360 }
361 if (NULL != sps->cfg)
362 {
363 GNUNET_CONFIGURATION_destroy (sps->cfg);
364 sps->cfg = NULL;
365 }
366 GNUNET_free (sps->hello);
367 GNUNET_free (sps->connected_peers_map);
368 GNUNET_free (sps);
369}
370
371
372/**
373 * This function prepares an array with traits.
374 *
375 */
376static int
377start_peer_traits (void *cls,
378 const void **ret,
379 const char *trait,
380 unsigned int index)
381{
382 struct StartPeerState_v2 *sps = cls;
383 struct GNUNET_TRANSPORT_ApplicationHandle *ah = sps->ah;
384 struct GNUNET_PeerIdentity *id = &sps->id;
385 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
386 sps->connected_peers_map;
387 char *hello = sps->hello;
388 size_t hello_size = sps->hello_size;
389
390
391 struct GNUNET_TESTING_Trait traits[] = {
392 {
393 .index = 0,
394 .trait_name = "application_handle",
395 .ptr = (const void *) ah,
396 },
397 {
398 .index = 1,
399 .trait_name = "peer_id",
400 .ptr = (const void *) id,
401 },
402 {
403 .index = 2,
404 .trait_name = "connected_peers_map",
405 .ptr = (const void *) connected_peers_map,
406 },
407 {
408 .index = 3,
409 .trait_name = "hello",
410 .ptr = (const void *) hello,
411 },
412 {
413 .index = 4,
414 .trait_name = "hello_size",
415 .ptr = (const void *) hello_size,
416 },
417 {
418 .index = 5,
419 .trait_name = "state",
420 .ptr = (const void *) sps,
421 },
422 GNUNET_TESTING_trait_end ()
423 };
424
425 return GNUNET_TESTING_get_trait (traits,
426 ret,
427 trait,
428 index);
429}
430
431
432/**
433 * Function to get the trait with the struct StartPeerState_v2.
434 *
435 * @param[out] sps struct StartPeerState_v2.
436 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
437 *
438 */
439int
440GNUNET_TRANSPORT_get_trait_state_v2 (const struct
441 GNUNET_TESTING_Command
442 *cmd,
443 struct StartPeerState_v2 **sps)
444{
445 return cmd->traits (cmd->cls,
446 (const void **) sps,
447 "state",
448 (unsigned int) 5);
449}
450
451
452/**
453 * Function to get the trait with the size of the hello.
454 *
455 * @param[out] hello_size size of hello.
456 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
457 *
458 */
459int
460GNUNET_TRANSPORT_get_trait_hello_size_v2 (const struct
461 GNUNET_TESTING_Command
462 *cmd,
463 size_t **hello_size)
464{
465 return cmd->traits (cmd->cls,
466 (const void **) hello_size,
467 "hello_size",
468 (unsigned int) 4);
469}
470
471
472/**
473 * Function to get the trait with the hello.
474 *
475 * @param[out] hello The hello for the peer.
476 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
477 *
478 */
479int
480GNUNET_TRANSPORT_get_trait_hello_v2 (const struct
481 GNUNET_TESTING_Command
482 *cmd,
483 char **hello)
484{
485 return cmd->traits (cmd->cls,
486 (const void **) hello,
487 "hello",
488 (unsigned int) 3);
489}
490
491
492/**
493 * Function to get the trait with the map of connected peers.
494 *
495 * @param[out] connected_peers_map The map with connected peers.
496 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
497 *
498 */
499int
500GNUNET_TRANSPORT_get_trait_connected_peers_map_v2 (const struct
501 GNUNET_TESTING_Command
502 *cmd,
503 struct
504 GNUNET_CONTAINER_MultiShortmap
505 *
506 *
507 connected_peers_map)
508{
509 return cmd->traits (cmd->cls,
510 (const void **) connected_peers_map,
511 "connected_peers_map",
512 (unsigned int) 2);
513}
514
515
516/**
517 * Function to get the trait with the transport application handle.
518 *
519 * @param[out] ah The application handle.
520 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
521 */
522int
523GNUNET_TRANSPORT_get_trait_application_handle_v2 (const struct
524 GNUNET_TESTING_Command *cmd,
525 struct
526 GNUNET_TRANSPORT_ApplicationHandle
527 **ah)
528{
529 return cmd->traits (cmd->cls,
530 (const void **) ah,
531 "application_handle",
532 (unsigned int) 0);
533}
534
535
536/**
537 * Function to get the trait with the peer id.
538 *
539 * @param[out] id The peer id.
540 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
541 */
542int
543GNUNET_TRANSPORT_get_trait_peer_id_v2 (const struct
544 GNUNET_TESTING_Command *cmd,
545 struct GNUNET_PeerIdentity **id)
546{
547 return cmd->traits (cmd->cls,
548 (const void **) id,
549 "peer_id",
550 (unsigned int) 1);
551}
552
553
554/**
555 * Create command.
556 *
557 * @param label name for command.
558 * @param system_label Label of the cmd to setup a test environment.
559 * @param m The number of the local node of the actual network namespace.
560 * @param n The number of the actual namespace.
561 * @param local_m Number of local nodes in each namespace.
562 * @param handlers Handler for messages received by this peer.
563 * @param cfgname Configuration file name for this peer.
564 * @return command.
565 */
566struct GNUNET_TESTING_Command
567GNUNET_TRANSPORT_cmd_start_peer_v2 (const char *label,
568 const char *system_label,
569 uint32_t no,
570 char *node_ip,
571 struct GNUNET_MQ_MessageHandler *handlers,
572 const char *cfgname)
573{
574 struct StartPeerState_v2 *sps;
575 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
576 GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO);
577 unsigned int i;
578
579 sps = GNUNET_new (struct StartPeerState_v2);
580 sps->no = no;
581 sps->system_label = system_label;
582 sps->connected_peers_map = connected_peers_map;
583 sps->cfgname = cfgname;
584 sps->node_ip = node_ip;
585
586 if (NULL != handlers)
587 {
588 for (i = 0; NULL != handlers[i].cb; i++)
589 ;
590 sps->handlers = GNUNET_new_array (i + 1,
591 struct GNUNET_MQ_MessageHandler);
592 GNUNET_memcpy (sps->handlers,
593 handlers,
594 i * sizeof(struct GNUNET_MQ_MessageHandler));
595 }
596
597 struct GNUNET_TESTING_Command cmd = {
598 .cls = sps,
599 .label = label,
600 .run = &start_peer_run,
601 .finish = &start_peer_finish,
602 .cleanup = &start_peer_cleanup,
603 .traits = &start_peer_traits
604 };
605
606 return cmd;
607}
diff --git a/src/transport/transport_api_cmd_start_peer_v3.c b/src/transport/transport_api_cmd_start_peer_v3.c
deleted file mode 100644
index b5cefecc8..000000000
--- a/src/transport/transport_api_cmd_start_peer_v3.c
+++ /dev/null
@@ -1,619 +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_peerstore_service.h"
30#include "gnunet_transport_core_service.h"
31#include "gnunet_transport_application_service.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
40static void
41retrieve_hello (void *cls);
42
43
44/**
45 * Callback delivering the hello of this peer from peerstore.
46 *
47 */
48static void
49hello_iter_cb (void *cb_cls,
50 const struct GNUNET_PEERSTORE_Record *record,
51 const char *emsg)
52{
53 struct StartPeerState_v2 *sps = cb_cls;
54 if (NULL == record)
55 {
56 sps->pic = NULL;
57 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
58 return;
59 }
60 // Check record type et al?
61 sps->hello_size = record->value_size;
62 sps->hello = GNUNET_malloc (sps->hello_size);
63 memcpy (sps->hello, record->value, sps->hello_size);
64 sps->hello[sps->hello_size - 1] = '\0';
65
66 GNUNET_PEERSTORE_iterate_cancel (sps->pic);
67 sps->pic = NULL;
68 sps->finished = GNUNET_YES;
69}
70
71
72/**
73 * Function to start the retrieval task to retrieve the hello of this peer
74 * from the peerstore.
75 *
76 */
77static void
78retrieve_hello (void *cls)
79{
80 struct StartPeerState_v2 *sps = cls;
81 sps->rh_task = NULL;
82 sps->pic = GNUNET_PEERSTORE_iterate (sps->ph,
83 "transport",
84 &sps->id,
85 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
86 hello_iter_cb,
87 sps);
88
89}
90
91
92/**
93 * This function checks StartPeerState_v2#finished, which is set when the hello was retrieved.
94 *
95 */
96static int
97start_peer_finish (void *cls,
98 GNUNET_SCHEDULER_TaskCallback cont,
99 void *cont_cls)
100{
101 struct StartPeerState_v2 *sps = cls;
102
103 if (GNUNET_YES == sps->finished)
104 {
105 cont (cont_cls);
106 }
107
108 return sps->finished;
109}
110
111
112/**
113 * Disconnect callback for the connection to the core service.
114 *
115 */
116static void
117notify_disconnect (void *cls,
118 const struct GNUNET_PeerIdentity *peer,
119 void *handler_cls)
120{
121 struct StartPeerState_v2 *sps = cls;
122
123 LOG (GNUNET_ERROR_TYPE_DEBUG,
124 "Peer %s disconnected from peer %u (`%s')\n",
125 GNUNET_i2s (peer),
126 sps->no,
127 GNUNET_i2s (&sps->id));
128
129}
130
131
132/**
133 * Connect callback for the connection to the core service.
134 *
135 */
136static void *
137notify_connect (void *cls,
138 const struct GNUNET_PeerIdentity *peer,
139 struct GNUNET_MQ_Handle *mq)
140{
141 struct StartPeerState_v2 *sps = cls;
142 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
143 struct GNUNET_HashCode hc;
144 struct GNUNET_CRYPTO_EddsaPublicKey public_key = peer->public_key;
145
146 void *ret = NULL;
147
148
149 LOG (GNUNET_ERROR_TYPE_DEBUG,
150 "Peer %s connected to peer %u (`%s')\n",
151 GNUNET_i2s (peer),
152 sps->no,
153 GNUNET_i2s (&sps->id));
154
155 GNUNET_CRYPTO_hash (&public_key, sizeof(public_key), &hc);
156
157
158 memcpy (key,
159 &hc,
160 sizeof (*key));
161 GNUNET_CONTAINER_multishortmap_put (sps->connected_peers_map,
162 key,
163 mq,
164 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
165
166 GNUNET_free (key);
167 // TODO what does the handler function need?
168 return ret;
169}
170
171
172/**
173 * The run method of this cmd will start all services of a peer to test the transport service.
174 *
175 */
176static void
177start_peer_run (void *cls,
178 const struct GNUNET_TESTING_Command *cmd,
179 struct GNUNET_TESTING_Interpreter *is)
180{
181 struct StartPeerState_v2 *sps = cls;
182 char *emsg = NULL;
183 struct GNUNET_PeerIdentity dummy;
184 const struct GNUNET_TESTING_Command *system_cmd;
185 struct GNUNET_TESTING_System *tl_system;
186 char *home;
187 char *transport_unix_path;
188 char *tcp_communicator_unix_path;
189 char *udp_communicator_unix_path;
190 char *bindto;
191
192 if (GNUNET_NO == GNUNET_DISK_file_test (sps->cfgname))
193 {
194 LOG (GNUNET_ERROR_TYPE_ERROR,
195 "File not found: `%s'\n",
196 sps->cfgname);
197 GNUNET_TESTING_interpreter_fail ();
198 return;
199 }
200
201
202 sps->cfg = GNUNET_CONFIGURATION_create ();
203 GNUNET_assert (GNUNET_OK ==
204 GNUNET_CONFIGURATION_load (sps->cfg, sps->cfgname));
205
206 GNUNET_asprintf (&home,
207 "$GNUNET_TMP/test-transport/api-tcp-p%u",
208 sps->no);
209
210 GNUNET_asprintf (&transport_unix_path,
211 "$GNUNET_RUNTIME_DIR/tng-p%u.sock",
212 sps->no);
213
214 GNUNET_asprintf (&tcp_communicator_unix_path,
215 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
216 sps->no);
217
218 GNUNET_asprintf (&udp_communicator_unix_path,
219 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
220 sps->no);
221
222 GNUNET_asprintf (&bindto,
223 "%s:60002",
224 sps->node_ip);
225
226 LOG (GNUNET_ERROR_TYPE_ERROR,
227 "node_ip %s\n",
228 bindto);
229
230 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "PATHS", "GNUNET_TEST_HOME",
231 home);
232 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "transport", "UNIXPATH",
233 transport_unix_path);
234 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
235 "BINDTO",
236 bindto);
237 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-udp",
238 "BINDTO",
239 bindto);
240 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
241 "UNIXPATH",
242 tcp_communicator_unix_path);
243 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-udp",
244 "UNIXPATH",
245 udp_communicator_unix_path);
246
247 system_cmd = GNUNET_TESTING_interpreter_lookup_command (sps->system_label);
248 GNUNET_TESTING_get_trait_test_system (system_cmd,
249 &tl_system);
250
251 sps->tl_system = tl_system;
252
253 if (GNUNET_SYSERR ==
254 GNUNET_TESTING_configuration_create (tl_system,
255 sps->cfg))
256 {
257 LOG (GNUNET_ERROR_TYPE_ERROR,
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 ();
262 return;
263 }
264
265 sps->peer = GNUNET_TESTING_peer_configure (sps->tl_system,
266 sps->cfg,
267 sps->no,
268 NULL,
269 &emsg);
270 if (NULL == sps->peer)
271 {
272 LOG (GNUNET_ERROR_TYPE_ERROR,
273 "Testing library failed to create unique configuration based on `%s': `%s'\n",
274 sps->cfgname,
275 emsg);
276 GNUNET_free (emsg);
277 GNUNET_TESTING_interpreter_fail ();
278 return;
279 }
280
281 if (GNUNET_OK != GNUNET_TESTING_peer_start (sps->peer))
282 {
283 LOG (GNUNET_ERROR_TYPE_ERROR,
284 "Testing library failed to create unique configuration based on `%s'\n",
285 sps->cfgname);
286 GNUNET_free (emsg);
287 GNUNET_TESTING_interpreter_fail ();
288 return;
289 }
290
291 memset (&dummy,
292 '\0',
293 sizeof(dummy));
294
295 GNUNET_TESTING_peer_get_identity (sps->peer,
296 &sps->id);
297
298 if (0 == memcmp (&dummy,
299 &sps->id,
300 sizeof(struct GNUNET_PeerIdentity)))
301 {
302 LOG (GNUNET_ERROR_TYPE_ERROR,
303 "Testing library failed to obtain peer identity for peer %u\n",
304 sps->no);
305 GNUNET_free (emsg);
306 GNUNET_TESTING_interpreter_fail ();
307 return;
308 }
309 LOG (GNUNET_ERROR_TYPE_DEBUG,
310 "Peer %u configured with identity `%s'\n",
311 sps->no,
312 GNUNET_i2s_full (&sps->id));
313
314 sps->th = GNUNET_TRANSPORT_core_connect (sps->cfg,
315 NULL,
316 sps->handlers,
317 sps,
318 &notify_connect,
319 &notify_disconnect);
320 if (NULL == sps->th)
321 {
322 LOG (GNUNET_ERROR_TYPE_ERROR,
323 "Failed to connect to transport service for peer `%s': `%s'\n",
324 sps->cfgname,
325 emsg);
326 GNUNET_free (emsg);
327 GNUNET_TESTING_interpreter_fail ();
328 return;
329 }
330
331 sps->ph = GNUNET_PEERSTORE_connect (sps->cfg);
332 if (NULL == sps->th)
333 {
334 LOG (GNUNET_ERROR_TYPE_ERROR,
335 "Failed to connect to peerstore service for peer `%s': `%s'\n",
336 sps->cfgname,
337 emsg);
338 GNUNET_free (emsg);
339 GNUNET_TESTING_interpreter_fail ();
340 return;
341 }
342
343 sps->ah = GNUNET_TRANSPORT_application_init (sps->cfg);
344 if (NULL == sps->ah)
345 {
346 LOG (GNUNET_ERROR_TYPE_ERROR,
347 "Failed to initialize the TRANSPORT application suggestion client handle for peer `%s': `%s'\n",
348 sps->cfgname,
349 emsg);
350 GNUNET_free (emsg);
351 GNUNET_TESTING_interpreter_fail ();
352 return;
353 }
354 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
355}
356
357
358/**
359 * The cleanup function of this cmd frees resources the cmd allocated.
360 *
361 */
362static void
363start_peer_cleanup (void *cls,
364 const struct GNUNET_TESTING_Command *cmd)
365{
366 struct StartPeerState_v2 *sps = cls;
367
368 if (NULL != sps->handlers)
369 {
370 GNUNET_free (sps->handlers);
371 sps->handlers = NULL;
372 }
373 if (NULL != sps->cfg)
374 {
375 GNUNET_CONFIGURATION_destroy (sps->cfg);
376 sps->cfg = NULL;
377 }
378 GNUNET_free (sps->hello);
379 GNUNET_free (sps->connected_peers_map);
380 GNUNET_free (sps);
381}
382
383
384/**
385 * This function prepares an array with traits.
386 *
387 */
388static int
389start_peer_traits (void *cls,
390 const void **ret,
391 const char *trait,
392 unsigned int index)
393{
394 struct StartPeerState_v2 *sps = cls;
395 struct GNUNET_TRANSPORT_ApplicationHandle *ah = sps->ah;
396 struct GNUNET_PeerIdentity *id = &sps->id;
397 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
398 sps->connected_peers_map;
399 char *hello = sps->hello;
400 size_t hello_size = sps->hello_size;
401
402
403 struct GNUNET_TESTING_Trait traits[] = {
404 {
405 .index = 0,
406 .trait_name = "application_handle",
407 .ptr = (const void *) ah,
408 },
409 {
410 .index = 1,
411 .trait_name = "peer_id",
412 .ptr = (const void *) id,
413 },
414 {
415 .index = 2,
416 .trait_name = "connected_peers_map",
417 .ptr = (const void *) connected_peers_map,
418 },
419 {
420 .index = 3,
421 .trait_name = "hello",
422 .ptr = (const void *) hello,
423 },
424 {
425 .index = 4,
426 .trait_name = "hello_size",
427 .ptr = (const void *) hello_size,
428 },
429 {
430 .index = 5,
431 .trait_name = "state",
432 .ptr = (const void *) sps,
433 },
434 GNUNET_TESTING_trait_end ()
435 };
436
437 return GNUNET_TESTING_get_trait (traits,
438 ret,
439 trait,
440 index);
441}
442
443
444/**
445 * Function to get the trait with the struct StartPeerState_v2.
446 *
447 * @param[out] sps struct StartPeerState_v2.
448 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
449 *
450 */
451int
452GNUNET_TRANSPORT_get_trait_state_v3 (const struct
453 GNUNET_TESTING_Command
454 *cmd,
455 struct StartPeerState_v2 **sps)
456{
457 return cmd->traits (cmd->cls,
458 (const void **) sps,
459 "state",
460 (unsigned int) 5);
461}
462
463
464/**
465 * Function to get the trait with the size of the hello.
466 *
467 * @param[out] hello_size size of hello.
468 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
469 *
470 */
471int
472GNUNET_TRANSPORT_get_trait_hello_size_v3 (const struct
473 GNUNET_TESTING_Command
474 *cmd,
475 size_t **hello_size)
476{
477 return cmd->traits (cmd->cls,
478 (const void **) hello_size,
479 "hello_size",
480 (unsigned int) 4);
481}
482
483
484/**
485 * Function to get the trait with the hello.
486 *
487 * @param[out] hello The hello for the peer.
488 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
489 *
490 */
491int
492GNUNET_TRANSPORT_get_trait_hello_v3 (const struct
493 GNUNET_TESTING_Command
494 *cmd,
495 char **hello)
496{
497 return cmd->traits (cmd->cls,
498 (const void **) hello,
499 "hello",
500 (unsigned int) 3);
501}
502
503
504/**
505 * Function to get the trait with the map of connected peers.
506 *
507 * @param[out] connected_peers_map The map with connected peers.
508 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
509 *
510 */
511int
512GNUNET_TRANSPORT_get_trait_connected_peers_map_v3 (const struct
513 GNUNET_TESTING_Command
514 *cmd,
515 struct
516 GNUNET_CONTAINER_MultiShortmap
517 *
518 *
519 connected_peers_map)
520{
521 return cmd->traits (cmd->cls,
522 (const void **) connected_peers_map,
523 "connected_peers_map",
524 (unsigned int) 2);
525}
526
527
528/**
529 * Function to get the trait with the transport application handle.
530 *
531 * @param[out] ah The application handle.
532 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
533 */
534int
535GNUNET_TRANSPORT_get_trait_application_handle_v3 (const struct
536 GNUNET_TESTING_Command *cmd,
537 struct
538 GNUNET_TRANSPORT_ApplicationHandle
539 **ah)
540{
541 return cmd->traits (cmd->cls,
542 (const void **) ah,
543 "application_handle",
544 (unsigned int) 0);
545}
546
547
548/**
549 * Function to get the trait with the peer id.
550 *
551 * @param[out] id The peer id.
552 * @return #GNUNET_OK if no error occurred, #GNUNET_SYSERR otherwise.
553 */
554int
555GNUNET_TRANSPORT_get_trait_peer_id_v3 (const struct
556 GNUNET_TESTING_Command *cmd,
557 struct GNUNET_PeerIdentity **id)
558{
559 return cmd->traits (cmd->cls,
560 (const void **) id,
561 "peer_id",
562 (unsigned int) 1);
563}
564
565
566/**
567 * Create command.
568 *
569 * @param label name for command.
570 * @param system_label Label of the cmd to setup a test environment.
571 * @param m The number of the local node of the actual network namespace.
572 * @param n The number of the actual namespace.
573 * @param local_m Number of local nodes in each namespace.
574 * @param handlers Handler for messages received by this peer.
575 * @param cfgname Configuration file name for this peer.
576 * @return command.
577 */
578struct GNUNET_TESTING_Command
579GNUNET_TRANSPORT_cmd_start_peer_v3 (const char *label,
580 const char *system_label,
581 uint32_t no,
582 char *node_ip,
583 struct GNUNET_MQ_MessageHandler *handlers,
584 const char *cfgname)
585{
586 struct StartPeerState_v2 *sps;
587 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
588 GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO);
589 unsigned int i;
590
591 sps = GNUNET_new (struct StartPeerState_v2);
592 sps->no = no;
593 sps->system_label = system_label;
594 sps->connected_peers_map = connected_peers_map;
595 sps->cfgname = cfgname;
596 sps->node_ip = node_ip;
597
598 if (NULL != handlers)
599 {
600 for (i = 0; NULL != handlers[i].cb; i++)
601 ;
602 sps->handlers = GNUNET_new_array (i + 1,
603 struct GNUNET_MQ_MessageHandler);
604 GNUNET_memcpy (sps->handlers,
605 handlers,
606 i * sizeof(struct GNUNET_MQ_MessageHandler));
607 }
608
609 struct GNUNET_TESTING_Command cmd = {
610 .cls = sps,
611 .label = label,
612 .run = &start_peer_run,
613 .finish = &start_peer_finish,
614 .cleanup = &start_peer_cleanup,
615 .traits = &start_peer_traits
616 };
617
618 return cmd;
619}
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 4d7228378..000000000
--- a/src/transport/transport_api_cmd_stop_peer.c
+++ /dev/null
@@ -1,163 +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_peerstore_service.h"
30#include "gnunet_transport_core_service.h"
31#include "gnunet_transport_application_service.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
40/**
41 * Struct to hold information for callbacks.
42 *
43 */
44struct StopPeerState
45{
46 // Label of the cmd to start the peer.
47 const char *start_label;
48};
49
50
51/**
52 * The run method of this cmd will stop all services of a peer which were used to test the transport service.
53 *
54 */
55static void
56stop_peer_run (void *cls,
57 const struct GNUNET_TESTING_Command *cmd,
58 struct GNUNET_TESTING_Interpreter *is)
59{
60 struct StopPeerState *stop_ps = cls;
61 struct StartPeerState *sps;
62 const struct GNUNET_TESTING_Command *start_cmd;
63
64 start_cmd = GNUNET_TESTING_interpreter_lookup_command (stop_ps->start_label);
65 GNUNET_TRANSPORT_get_trait_state (start_cmd,
66 &sps);
67
68 if (NULL != sps->pic)
69 {
70 GNUNET_PEERSTORE_iterate_cancel (sps->pic);
71 sps->pic = NULL;
72 }
73 if (NULL != sps->th)
74 {
75 GNUNET_TRANSPORT_core_disconnect (sps->th);
76 sps->th = NULL;
77 }
78 if (NULL != sps->ah)
79 {
80 GNUNET_TRANSPORT_application_done (sps->ah);
81 sps->ah = NULL;
82 }
83 if (NULL != sps->ph)
84 {
85 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
86 "Disconnecting from PEERSTORE service\n");
87 GNUNET_PEERSTORE_disconnect (sps->ph, GNUNET_NO);
88 sps->ph = NULL;
89 }
90 if (NULL != sps->peer)
91 {
92 if (GNUNET_OK !=
93 GNUNET_TESTING_peer_stop (sps->peer))
94 {
95 LOG (GNUNET_ERROR_TYPE_ERROR,
96 "Testing lib failed to stop peer %u (`%s')\n",
97 sps->no,
98 GNUNET_i2s (&sps->id));
99 }
100 GNUNET_TESTING_peer_destroy (sps->peer);
101 sps->peer = NULL;
102 }
103 if (NULL != sps->rh_task)
104 GNUNET_SCHEDULER_cancel (sps->rh_task);
105 sps->rh_task = NULL;
106
107}
108
109
110/**
111 * The cleanup function of this cmd frees resources the cmd allocated.
112 *
113 */
114static void
115stop_peer_cleanup (void *cls,
116 const struct GNUNET_TESTING_Command *cmd)
117{
118 struct StopPeerState *sps = cls;
119
120 GNUNET_free (sps);
121}
122
123
124/**
125 * Trait function of this cmd does nothing.
126 *
127 */
128static int
129stop_peer_traits (void *cls,
130 const void **ret,
131 const char *trait,
132 unsigned int index)
133{
134 return GNUNET_OK;
135}
136
137
138/**
139 * Create command.
140 *
141 * @param label name for command.
142 * @param start_label Label of the cmd to start the peer.
143 * @return command.
144 */
145struct GNUNET_TESTING_Command
146GNUNET_TRANSPORT_cmd_stop_peer (const char *label,
147 const char *start_label)
148{
149 struct StopPeerState *sps;
150
151 sps = GNUNET_new (struct StopPeerState);
152 sps->start_label = start_label;
153
154 struct GNUNET_TESTING_Command cmd = {
155 .cls = sps,
156 .label = label,
157 .run = &stop_peer_run,
158 .cleanup = &stop_peer_cleanup,
159 .traits = &stop_peer_traits
160 };
161
162 return cmd;
163}
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 */