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.am1687
-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.c3682
-rw-r--r--src/transport/gnunet-communicator-udp.c3953
-rw-r--r--src/transport/gnunet-communicator-unix.c1167
-rw-r--r--src/transport/gnunet-helper-transport-bluetooth.c2285
-rw-r--r--src/transport/gnunet-helper-transport-wlan-dummy.c520
-rw-r--r--src/transport/gnunet-helper-transport-wlan.c2184
-rw-r--r--src/transport/gnunet-service-tng.c11152
-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.conf32
-rw-r--r--src/transport/test_transport_api2_tcp_node2.conf22
-rw-r--r--src/transport/test_transport_api2_tcp_peer1.conf23
-rw-r--r--src/transport/test_transport_api2_tcp_peer2.conf22
-rw-r--r--src/transport/test_transport_api_blacklisting.c206
-rw-r--r--src/transport/test_transport_api_blacklisting_tcp_peer1.conf9
-rw-r--r--src/transport/test_transport_api_blacklisting_tcp_peer2.conf9
-rw-r--r--src/transport/test_transport_api_bluetooth_peer1.conf10
-rw-r--r--src/transport/test_transport_api_bluetooth_peer2.conf10
-rw-r--r--src/transport/test_transport_api_data.conf9
-rw-r--r--src/transport/test_transport_api_disconnect.c134
-rw-r--r--src/transport/test_transport_api_disconnect_tcp_peer1.conf7
-rw-r--r--src/transport/test_transport_api_disconnect_tcp_peer2.conf8
-rw-r--r--src/transport/test_transport_api_http_peer1.conf6
-rw-r--r--src/transport/test_transport_api_http_peer2.conf6
-rw-r--r--src/transport/test_transport_api_http_reverse_peer1.conf11
-rw-r--r--src/transport/test_transport_api_http_reverse_peer2.conf12
-rw-r--r--src/transport/test_transport_api_https_peer1.conf26
-rw-r--r--src/transport/test_transport_api_https_peer2.conf32
-rw-r--r--src/transport/test_transport_api_limited_sockets.c132
-rw-r--r--src/transport/test_transport_api_limited_sockets_tcp_peer1.conf7
-rw-r--r--src/transport/test_transport_api_limited_sockets_tcp_peer2.conf8
-rw-r--r--src/transport/test_transport_api_manipulation_cfg.c186
-rw-r--r--src/transport/test_transport_api_manipulation_cfg_peer1.conf8
-rw-r--r--src/transport/test_transport_api_manipulation_cfg_peer2.conf8
-rw-r--r--src/transport/test_transport_api_manipulation_recv_tcp.c203
-rw-r--r--src/transport/test_transport_api_manipulation_recv_tcp_peer1.conf29
-rw-r--r--src/transport/test_transport_api_manipulation_recv_tcp_peer2.conf29
-rw-r--r--src/transport/test_transport_api_manipulation_send_tcp.c199
-rw-r--r--src/transport/test_transport_api_manipulation_send_tcp_peer1.conf29
-rw-r--r--src/transport/test_transport_api_manipulation_send_tcp_peer2.conf29
-rw-r--r--src/transport/test_transport_api_monitor_peers.c226
-rw-r--r--src/transport/test_transport_api_monitor_peers_peer1.conf4
-rw-r--r--src/transport/test_transport_api_monitor_peers_peer2.conf5
-rw-r--r--src/transport/test_transport_api_monitor_validation_peer1.conf6
-rw-r--r--src/transport/test_transport_api_monitor_validation_peer2.conf7
-rw-r--r--src/transport/test_transport_api_multi_peer1.conf7
-rw-r--r--src/transport/test_transport_api_multi_peer2.conf9
-rw-r--r--src/transport/test_transport_api_reliability.c321
-rw-r--r--src/transport/test_transport_api_reliability_bluetooth_peer1.conf33
-rw-r--r--src/transport/test_transport_api_reliability_bluetooth_peer2.conf32
-rw-r--r--src/transport/test_transport_api_reliability_http_peer1.conf33
-rw-r--r--src/transport/test_transport_api_reliability_http_peer2.conf30
-rw-r--r--src/transport/test_transport_api_reliability_http_xhr_peer1.conf34
-rw-r--r--src/transport/test_transport_api_reliability_http_xhr_peer2.conf30
-rw-r--r--src/transport/test_transport_api_reliability_https_peer1.conf27
-rw-r--r--src/transport/test_transport_api_reliability_https_peer2.conf31
-rw-r--r--src/transport/test_transport_api_reliability_https_xhr_peer1.conf28
-rw-r--r--src/transport/test_transport_api_reliability_https_xhr_peer2.conf31
-rw-r--r--src/transport/test_transport_api_reliability_tcp_nat_peer1.conf35
-rw-r--r--src/transport/test_transport_api_reliability_tcp_nat_peer2.conf34
-rw-r--r--src/transport/test_transport_api_reliability_tcp_peer1.conf29
-rw-r--r--src/transport/test_transport_api_reliability_tcp_peer2.conf28
-rw-r--r--src/transport/test_transport_api_reliability_udp_peer1.conf29
-rw-r--r--src/transport/test_transport_api_reliability_udp_peer2.conf29
-rw-r--r--src/transport/test_transport_api_reliability_unix_peer1.conf28
-rw-r--r--src/transport/test_transport_api_reliability_unix_peer2.conf28
-rw-r--r--src/transport/test_transport_api_reliability_wlan_peer1.conf31
-rw-r--r--src/transport/test_transport_api_reliability_wlan_peer2.conf32
-rw-r--r--src/transport/test_transport_api_restart_1peer_peer1.conf9
-rw-r--r--src/transport/test_transport_api_restart_1peer_peer2.conf9
-rw-r--r--src/transport/test_transport_api_restart_2peers_peer1.conf9
-rw-r--r--src/transport/test_transport_api_restart_2peers_peer2.conf9
-rw-r--r--src/transport/test_transport_api_restart_reconnect.c217
-rw-r--r--src/transport/test_transport_api_slow_ats_peer1.conf7
-rw-r--r--src/transport/test_transport_api_slow_ats_peer2.conf9
-rw-r--r--src/transport/test_transport_api_tcp_nat_peer1.conf34
-rw-r--r--src/transport/test_transport_api_tcp_nat_peer2.conf32
-rw-r--r--src/transport/test_transport_api_tcp_peer1.conf9
-rw-r--r--src/transport/test_transport_api_tcp_peer2.conf9
-rw-r--r--src/transport/test_transport_api_timeout.c164
-rw-r--r--src/transport/test_transport_api_timeout_bluetooth_peer1.conf35
-rw-r--r--src/transport/test_transport_api_timeout_bluetooth_peer2.conf34
-rw-r--r--src/transport/test_transport_api_timeout_http_peer1.conf28
-rw-r--r--src/transport/test_transport_api_timeout_http_peer2.conf31
-rw-r--r--src/transport/test_transport_api_timeout_https_peer1.conf25
-rw-r--r--src/transport/test_transport_api_timeout_https_peer2.conf31
-rw-r--r--src/transport/test_transport_api_timeout_tcp_peer1.conf30
-rw-r--r--src/transport/test_transport_api_timeout_tcp_peer2.conf32
-rw-r--r--src/transport/test_transport_api_timeout_udp_peer1.conf33
-rw-r--r--src/transport/test_transport_api_timeout_udp_peer2.conf31
-rw-r--r--src/transport/test_transport_api_timeout_unix_peer1.conf28
-rw-r--r--src/transport/test_transport_api_timeout_unix_peer2.conf28
-rw-r--r--src/transport/test_transport_api_timeout_wlan_peer1.conf35
-rw-r--r--src/transport/test_transport_api_timeout_wlan_peer2.conf34
-rw-r--r--src/transport/test_transport_api_udp_nat_peer1.conf34
-rw-r--r--src/transport/test_transport_api_udp_nat_peer2.conf32
-rw-r--r--src/transport/test_transport_api_udp_peer1.conf17
-rw-r--r--src/transport/test_transport_api_udp_peer2.conf15
-rw-r--r--src/transport/test_transport_api_unix_abstract_peer1.conf31
-rw-r--r--src/transport/test_transport_api_unix_abstract_peer2.conf31
-rw-r--r--src/transport/test_transport_api_unix_peer1.conf10
-rw-r--r--src/transport/test_transport_api_unix_peer2.conf7
-rw-r--r--src/transport/test_transport_api_unreliability_bluetooth_peer1.conf30
-rw-r--r--src/transport/test_transport_api_unreliability_bluetooth_peer2.conf29
-rw-r--r--src/transport/test_transport_api_unreliability_constant_udp_peer1.conf30
-rw-r--r--src/transport/test_transport_api_unreliability_constant_udp_peer2.conf30
-rw-r--r--src/transport/test_transport_api_unreliability_wlan_peer1.conf29
-rw-r--r--src/transport/test_transport_api_unreliability_wlan_peer2.conf29
-rw-r--r--src/transport/test_transport_api_wlan_peer1.conf35
-rw-r--r--src/transport/test_transport_api_wlan_peer2.conf34
-rw-r--r--src/transport/test_transport_blacklisting.c582
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer1_full.conf16
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf13
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer1_plugin.conf13
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer2_full.conf12
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf12
-rw-r--r--src/transport/test_transport_blacklisting_cfg_blp_peer2_plugin.conf12
-rw-r--r--src/transport/test_transport_blacklisting_cfg_peer1.conf29
-rw-r--r--src/transport/test_transport_blacklisting_cfg_peer2.conf28
-rw-r--r--src/transport/test_transport_defaults.conf20
-rw-r--r--src/transport/test_transport_distance_vector_circle_topo.conf12
-rw-r--r--src/transport/test_transport_distance_vector_topo.conf8
-rw-r--r--src/transport/test_transport_plugin_cmd_simple_send.c369
-rw-r--r--src/transport/test_transport_plugin_cmd_simple_send_broadcast.c398
-rw-r--r--src/transport/test_transport_plugin_cmd_simple_send_dv.c427
-rw-r--r--src/transport/test_transport_plugin_cmd_udp_backchannel.c356
-rwxr-xr-xsrc/transport/test_transport_simple_send.sh11
-rwxr-xr-xsrc/transport/test_transport_simple_send_broadcast.sh11
-rw-r--r--src/transport/test_transport_simple_send_broadcast_topo.conf4
-rwxr-xr-xsrc/transport/test_transport_simple_send_dv.sh11
-rwxr-xr-xsrc/transport/test_transport_simple_send_dv_circle.sh11
-rwxr-xr-xsrc/transport/test_transport_simple_send_string.sh21
-rw-r--r--src/transport/test_transport_simple_send_topo.conf6
-rw-r--r--src/transport/test_transport_start_with_config.c122
-rw-r--r--src/transport/test_transport_test_transport_address_switch_tcp_peer1.conf29
-rw-r--r--src/transport/test_transport_test_transport_address_switch_tcp_peer2.conf29
-rw-r--r--src/transport/test_transport_testing_restart.c163
-rw-r--r--src/transport/test_transport_testing_startstop.c138
-rwxr-xr-xsrc/transport/test_transport_udp_backchannel.sh14
-rw-r--r--src/transport/test_transport_udp_backchannel_topo.conf7
-rw-r--r--src/transport/transport-testing-cmds.h347
-rw-r--r--src/transport/transport-testing-communicator.c1227
-rw-r--r--src/transport/transport-testing-communicator.h360
-rw-r--r--src/transport/transport-testing-filenames.c202
-rw-r--r--src/transport/transport-testing-filenames2.c202
-rw-r--r--src/transport/transport-testing-loggers.c80
-rw-r--r--src/transport/transport-testing-loggers2.c80
-rw-r--r--src/transport/transport-testing-main.c613
-rw-r--r--src/transport/transport-testing-main2.c613
-rw-r--r--src/transport/transport-testing-send.c240
-rw-r--r--src/transport/transport-testing-send2.c240
-rw-r--r--src/transport/transport-testing.c931
-rw-r--r--src/transport/transport-testing.h914
-rw-r--r--src/transport/transport-testing2.c961
-rw-r--r--src/transport/transport-testing2.h924
-rw-r--r--src/transport/transport.conf.in237
-rw-r--r--src/transport/transport.h1241
-rw-r--r--src/transport/transport_api2_application.c397
-rw-r--r--src/transport/transport_api2_communication.c1165
-rw-r--r--src/transport/transport_api2_core.c804
-rw-r--r--src/transport/transport_api2_monitor.c292
-rw-r--r--src/transport/transport_api_address_to_string.c264
-rw-r--r--src/transport/transport_api_blacklist.c197
-rw-r--r--src/transport/transport_api_cmd_backchannel_check.c602
-rw-r--r--src/transport/transport_api_cmd_connecting_peers.c265
-rw-r--r--src/transport/transport_api_cmd_send_simple.c212
-rw-r--r--src/transport/transport_api_cmd_start_peer.c491
-rw-r--r--src/transport/transport_api_cmd_stop_peer.c156
-rw-r--r--src/transport/transport_api_core.c968
-rw-r--r--src/transport/transport_api_hello_get.c274
-rw-r--r--src/transport/transport_api_manipulation.c249
-rw-r--r--src/transport/transport_api_monitor_peers.c469
-rw-r--r--src/transport/transport_api_monitor_plugins.c463
-rw-r--r--src/transport/transport_api_offer_hello.c142
-rw-r--r--src/transport/transport_api_traits.c32
291 files changed, 0 insertions, 99280 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 2b09ccf63..000000000
--- a/src/transport/Makefile.am
+++ /dev/null
@@ -1,1687 +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 test_transport_start_with_config \
127 gnunet-transport-profiler \
128 gnunet-communicator-udp \
129 $(WLAN_BIN_SENDER) \
130 $(WLAN_BIN_RECEIVER)
131
132TESTING_LIBS = \
133 libgnunettransporttesting.la \
134 libgnunettransporttesting2.la
135
136lib_LTLIBRARIES = \
137 libgnunettransport.la \
138 libgnunettransportapplication.la \
139 libgnunettransportcore.la \
140 libgnunettransportcommunicator.la \
141 libgnunettransportmonitor.la \
142 $(TESTING_LIBS)
143
144libgnunettransporttesting_la_SOURCES = \
145 transport-testing.c transport-testing.h \
146 transport-testing-filenames.c \
147 transport-testing-loggers.c \
148 transport-testing-main.c \
149 transport-testing-send.c
150libgnunettransporttesting_la_LIBADD = \
151 libgnunettransport.la \
152 $(top_builddir)/src/hello/libgnunethello.la \
153 $(top_builddir)/src/ats/libgnunetats.la \
154 $(top_builddir)/src/util/libgnunetutil.la \
155 $(top_builddir)/src/testing/libgnunettesting.la \
156 $(top_builddir)/src/arm/libgnunetarm.la \
157 $(GN_LIBINTL)
158libgnunettransporttesting_la_LDFLAGS = \
159 $(GN_LIB_LDFLAGS)
160
161libgnunettransporttesting2_la_SOURCES = \
162 transport_api_traits.c \
163 transport_api_cmd_connecting_peers.c \
164 transport_api_cmd_backchannel_check.c \
165 transport_api_cmd_start_peer.c \
166 transport_api_cmd_stop_peer.c \
167 transport_api_cmd_send_simple.c \
168 transport-testing2.c transport-testing2.h \
169 transport-testing-cmds.h \
170 transport-testing-filenames2.c \
171 transport-testing-loggers2.c \
172 transport-testing-main2.c \
173 transport-testing-send2.c \
174 transport-testing-communicator.c transport-testing-communicator.h
175libgnunettransporttesting2_la_LIBADD = \
176 libgnunettransportapplication.la \
177 libgnunettransportcore.la \
178 $(top_builddir)/src/arm/libgnunetarm.la \
179 $(top_builddir)/src/testing/libgnunettesting.la \
180 $(top_builddir)/src/ats/libgnunetats.la \
181 $(top_builddir)/src/hello/libgnunethello.la \
182 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
183 $(top_builddir)/src/util/libgnunetutil.la
184libgnunettransporttesting2_la_LDFLAGS = \
185 $(GN_LIBINTL) \
186 $(GN_LIB_LDFLAGS) \
187 -version-info 0:0:0
188
189libgnunettransport_la_SOURCES = \
190 transport.h \
191 transport_api_address_to_string.c \
192 transport_api_blacklist.c \
193 transport_api_core.c \
194 transport_api_hello_get.c \
195 transport_api_manipulation.c \
196 transport_api_monitor_peers.c \
197 transport_api_monitor_plugins.c \
198 transport_api_offer_hello.c
199
200libgnunettransport_la_LIBADD = \
201 $(top_builddir)/src/hello/libgnunethello.la \
202 $(top_builddir)/src/ats/libgnunetats.la \
203 $(top_builddir)/src/util/libgnunetutil.la \
204 $(GN_LIBINTL)
205libgnunettransport_la_LDFLAGS = \
206 $(GN_LIB_LDFLAGS) \
207 -version-info 4:0:2
208
209libgnunettransportapplication_la_SOURCES = \
210 transport_api2_application.c
211libgnunettransportapplication_la_LIBADD = \
212 $(top_builddir)/src/util/libgnunetutil.la \
213 $(LTLIBINTL)
214libgnunettransportapplication_la_LDFLAGS = \
215 $(GN_LIB_LDFLAGS) \
216 -version-info 0:0:0
217
218
219libgnunettransportcore_la_SOURCES = \
220 transport_api2_core.c
221libgnunettransportcore_la_LIBADD = \
222 $(top_builddir)/src/util/libgnunetutil.la \
223 $(GN_LIBINTL)
224libgnunettransportcore_la_LDFLAGS = \
225 $(GN_LIB_LDFLAGS) \
226 -version-info 0:0:0
227
228libgnunettransportcommunicator_la_SOURCES = \
229 transport_api2_communication.c
230libgnunettransportcommunicator_la_LIBADD = \
231 $(top_builddir)/src/util/libgnunetutil.la \
232 $(GN_LIBINTL)
233libgnunettransportcommunicator_la_LDFLAGS = \
234 $(GN_LIB_LDFLAGS) \
235 -version-info 0:0:0
236
237
238libgnunettransportmonitor_la_SOURCES = \
239 transport_api2_monitor.c
240libgnunettransportmonitor_la_LIBADD = \
241 $(top_builddir)/src/util/libgnunetutil.la \
242 $(GN_LIBINTL)
243libgnunettransportmonitor_la_LDFLAGS = \
244 $(GN_LIB_LDFLAGS) \
245 -version-info 0:0:0
246
247
248libexec_PROGRAMS = \
249 $(WLAN_BIN) \
250 $(WLAN_BIN_DUMMY) \
251 $(BT_BIN) \
252 gnunet-service-transport \
253 gnunet-service-tng \
254 gnunet-communicator-unix \
255 gnunet-communicator-udp \
256 gnunet-communicator-tcp
257
258
259
260bin_PROGRAMS = \
261 gnunet-transport
262
263bin_SCRIPTS = \
264 gnunet-transport-certificate-creation
265
266# See: https://www.gnu.org/software/automake/manual/html_node/Scripts.html#Scripts
267do_subst = sed -e 's,[@]pkgdatadir[@],$(pkgdatadir),g'
268
269
270gnunet-transport-certificate-creation: gnunet-transport-certificate-creation.in Makefile
271 $(do_subst) < $(srcdir)/gnunet-transport-certificate-creation.in > gnunet-transport-certificate-creation
272 chmod +x gnunet-transport-certificate-creation
273
274
275
276gnunet_communicator_unix_SOURCES = \
277 gnunet-communicator-unix.c
278gnunet_communicator_unix_LDADD = \
279 libgnunettransportcommunicator.la \
280 $(top_builddir)/src/statistics/libgnunetstatistics.la \
281 $(top_builddir)/src/util/libgnunetutil.la
282
283gnunet_communicator_tcp_SOURCES = \
284 gnunet-communicator-tcp.c
285gnunet_communicator_tcp_LDADD = \
286 libgnunettransportcommunicator.la \
287 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
288 $(top_builddir)/src/nat/libgnunetnatnew.la \
289 $(top_builddir)/src/nt/libgnunetnt.la \
290 $(top_builddir)/src/statistics/libgnunetstatistics.la \
291 $(top_builddir)/src/util/libgnunetutil.la \
292 $(LIBGCRYPT_LIBS)
293
294gnunet_communicator_udp_SOURCES = \
295 gnunet-communicator-udp.c
296gnunet_communicator_udp_LDADD = \
297 libgnunettransportapplication.la \
298 libgnunettransportcommunicator.la \
299 $(top_builddir)/src/nat/libgnunetnatnew.la \
300 $(top_builddir)/src/nt/libgnunetnt.la \
301 $(top_builddir)/src/statistics/libgnunetstatistics.la \
302 $(top_builddir)/src/util/libgnunetutil.la \
303 $(LIBGCRYPT_LIBS)
304
305
306gnunet_helper_transport_wlan_SOURCES = \
307 gnunet-helper-transport-wlan.c
308
309gnunet_helper_transport_wlan_dummy_SOURCES = \
310 gnunet-helper-transport-wlan-dummy.c
311gnunet_helper_transport_wlan_dummy_LDADD = \
312 $(top_builddir)/src/util/libgnunetutil.la
313
314gnunet_transport_wlan_sender_SOURCES = \
315 gnunet-transport-wlan-sender.c
316gnunet_transport_wlan_sender_LDADD = \
317 $(top_builddir)/src/util/libgnunetutil.la
318
319gnunet_transport_wlan_receiver_SOURCES = \
320 gnunet-transport-wlan-receiver.c
321gnunet_transport_wlan_receiver_LDADD = \
322 $(top_builddir)/src/util/libgnunetutil.la
323
324gnunet_helper_transport_bluetooth_SOURCES = \
325 gnunet-helper-transport-bluetooth.c
326
327gnunet_helper_transport_bluetooth_LDFLAGS = -lbluetooth
328
329
330gnunet_transport_profiler_SOURCES = \
331 gnunet-transport-profiler.c
332gnunet_transport_profiler_LDADD = \
333 libgnunettransport.la \
334 $(top_builddir)/src/hello/libgnunethello.la \
335 $(top_builddir)/src/ats/libgnunetats.la \
336 $(top_builddir)/src/util/libgnunetutil.la \
337 $(GN_LIBINTL)
338
339gnunet_transport_SOURCES = \
340 gnunet-transport.c
341gnunet_transport_LDADD = \
342 libgnunettransport.la \
343 $(top_builddir)/src/hello/libgnunethello.la \
344 $(top_builddir)/src/util/libgnunetutil.la \
345 $(GN_LIBINTL)
346
347gnunet_service_transport_SOURCES = \
348 gnunet-service-transport.c gnunet-service-transport.h \
349 gnunet-service-transport_ats.h gnunet-service-transport_ats.c \
350 gnunet-service-transport_hello.h gnunet-service-transport_hello.c \
351 gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \
352 gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \
353 gnunet-service-transport_validation.h gnunet-service-transport_validation.c \
354 gnunet-service-transport_manipulation.h gnunet-service-transport_manipulation.c
355# Note that while gnunet-service-transport does not use libgnunetnat
356# directly, we must link against it as GNUNET_NAT_mini_map_stop will
357# leave a 'dangling' task to process_unmap_output which will cause
358# a crash on unloading of a plugin unless the service links against
359# that library as well.
360gnunet_service_transport_LDADD = \
361 libgnunettransport.la \
362 $(top_builddir)/src/ats/libgnunetats.la \
363 $(top_builddir)/src/hello/libgnunethello.la \
364 $(top_builddir)/src/nt/libgnunetnt.la \
365 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
366 $(top_builddir)/src/statistics/libgnunetstatistics.la \
367 $(top_builddir)/src/util/libgnunetutil.la \
368 $(GN_GLPK) \
369 $(GN_LIBINTL)
370gnunet_service_transport_CFLAGS = \
371 $(AM_CFLAGS)
372# -DANALYZE
373
374
375gnunet_service_tng_SOURCES = \
376 gnunet-service-tng.c
377gnunet_service_tng_LDADD = \
378 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
379 $(top_builddir)/src/hello/libgnunethello.la \
380 $(top_builddir)/src/statistics/libgnunetstatistics.la \
381 $(top_builddir)/src/util/libgnunetutil.la \
382 $(LIBGCRYPT_LIBS) \
383 $(GN_LIBINTL)
384
385plugin_LTLIBRARIES = \
386 libgnunet_plugin_transport_tcp.la \
387 $(UNIX_PLUGIN_LA) \
388 $(HTTP_CLIENT_PLUGIN_LA) \
389 $(HTTPS_CLIENT_PLUGIN_LA) \
390 $(HTTP_SERVER_PLUGIN_LA) \
391 $(HTTPS_SERVER_PLUGIN_LA) \
392 $(WLAN_PLUGIN_LA) \
393 $(BT_PLUGIN_LA) \
394 libgnunet_test_transport_plugin_cmd_simple_send.la \
395 libgnunet_test_transport_plugin_cmd_simple_send_broadcast.la \
396 libgnunet_test_transport_plugin_cmd_simple_send_dv.la \
397 libgnunet_test_transport_plugin_cmd_udp_backchannel.la
398
399libgnunet_test_transport_plugin_cmd_udp_backchannel_la_SOURCES = \
400 test_transport_plugin_cmd_udp_backchannel.c
401libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LIBADD = \
402 libgnunettransporttesting2.la \
403 libgnunettransportapplication.la \
404 libgnunettransportcore.la \
405 $(top_builddir)/src/testing/libgnunettesting.la \
406 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
407 $(top_builddir)/src/statistics/libgnunetstatistics.la \
408 $(top_builddir)/src/hello/libgnunethello.la \
409 $(top_builddir)/src/ats/libgnunetats.la \
410 $(top_builddir)/src/arm/libgnunetarm.la \
411 $(top_builddir)/src/util/libgnunetutil.la \
412 $(LTLIBINTL)
413libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LDFLAGS = \
414 $(GN_PLUGIN_LDFLAGS)
415
416libgnunet_test_transport_plugin_cmd_simple_send_la_SOURCES = \
417 test_transport_plugin_cmd_simple_send.c
418libgnunet_test_transport_plugin_cmd_simple_send_la_LIBADD = \
419 libgnunettransporttesting2.la \
420 libgnunettransportapplication.la \
421 libgnunettransportcore.la \
422 $(top_builddir)/src/testing/libgnunettesting.la \
423 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
424 $(top_builddir)/src/statistics/libgnunetstatistics.la \
425 $(top_builddir)/src/hello/libgnunethello.la \
426 $(top_builddir)/src/ats/libgnunetats.la \
427 $(top_builddir)/src/arm/libgnunetarm.la \
428 $(top_builddir)/src/util/libgnunetutil.la \
429 $(LTLIBINTL)
430libgnunet_test_transport_plugin_cmd_simple_send_la_LDFLAGS = \
431 $(GN_PLUGIN_LDFLAGS)
432
433libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_SOURCES = \
434 test_transport_plugin_cmd_simple_send_broadcast.c
435libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_LIBADD = \
436 libgnunettransporttesting2.la \
437 libgnunettransportapplication.la \
438 libgnunettransportcore.la \
439 $(top_builddir)/src/testing/libgnunettesting.la \
440 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
441 $(top_builddir)/src/statistics/libgnunetstatistics.la \
442 $(top_builddir)/src/hello/libgnunethello.la \
443 $(top_builddir)/src/ats/libgnunetats.la \
444 $(top_builddir)/src/arm/libgnunetarm.la \
445 $(top_builddir)/src/util/libgnunetutil.la \
446 $(LTLIBINTL)
447libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_LDFLAGS = \
448 $(GN_PLUGIN_LDFLAGS)
449
450libgnunet_test_transport_plugin_cmd_simple_send_dv_la_SOURCES = \
451 test_transport_plugin_cmd_simple_send_dv.c
452libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LIBADD = \
453 libgnunettransporttesting2.la \
454 libgnunettransportapplication.la \
455 libgnunettransportcore.la \
456 $(top_builddir)/src/testing/libgnunettesting.la \
457 $(top_builddir)/src/peerstore/libgnunetpeerstore.la \
458 $(top_builddir)/src/statistics/libgnunetstatistics.la \
459 $(top_builddir)/src/hello/libgnunethello.la \
460 $(top_builddir)/src/ats/libgnunetats.la \
461 $(top_builddir)/src/arm/libgnunetarm.la \
462 $(top_builddir)/src/util/libgnunetutil.la \
463 $(LTLIBINTL)
464libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LDFLAGS = \
465 $(GN_PLUGIN_LDFLAGS)
466
467if HAVE_EXPERIMENTAL
468plugin_LTLIBRARIES += \
469 libgnunet_plugin_transport_udp.la
470endif
471
472# Note: real plugins of course need to be added
473# to the plugin_LTLIBRARIES above
474noinst_LTLIBRARIES = \
475 libgnunet_plugin_transport_template.la
476
477libgnunet_plugin_transport_tcp_la_SOURCES = \
478 plugin_transport_tcp.c
479libgnunet_plugin_transport_tcp_la_LIBADD = \
480 $(top_builddir)/src/hello/libgnunethello.la \
481 $(top_builddir)/src/statistics/libgnunetstatistics.la \
482 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
483 $(top_builddir)/src/nat/libgnunetnatnew.la \
484 $(top_builddir)/src/util/libgnunetutil.la \
485 $(LTLIBINTL)
486libgnunet_plugin_transport_tcp_la_LDFLAGS = \
487 $(GN_PLUGIN_LDFLAGS)
488
489libgnunet_plugin_transport_template_la_SOURCES = \
490 plugin_transport_template.c
491libgnunet_plugin_transport_template_la_LIBADD = \
492 $(top_builddir)/src/util/libgnunetutil.la \
493 $(LTLIBINTL)
494libgnunet_plugin_transport_template_la_LDFLAGS = \
495 $(GN_PLUGIN_LDFLAGS)
496
497libgnunet_plugin_transport_wlan_la_SOURCES = \
498 plugin_transport_wlan.c plugin_transport_wlan.h
499libgnunet_plugin_transport_wlan_la_LIBADD = \
500 $(top_builddir)/src/hello/libgnunethello.la \
501 $(top_builddir)/src/statistics/libgnunetstatistics.la \
502 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
503 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
504 $(top_builddir)/src/util/libgnunetutil.la
505libgnunet_plugin_transport_wlan_la_LDFLAGS = \
506 $(GN_PLUGIN_LDFLAGS)
507libgnunet_plugin_transport_wlan_la_CFLAGS = \
508 $(AM_CFLAGS) -DBUILD_WLAN
509
510libgnunet_plugin_transport_bluetooth_la_SOURCES = \
511 plugin_transport_wlan.c plugin_transport_wlan.h
512libgnunet_plugin_transport_bluetooth_la_LIBADD = \
513 $(top_builddir)/src/hello/libgnunethello.la \
514 $(top_builddir)/src/statistics/libgnunetstatistics.la \
515 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
516 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
517 $(top_builddir)/src/util/libgnunetutil.la
518libgnunet_plugin_transport_bluetooth_la_LDFLAGS = \
519 $(GN_PLUGIN_LDFLAGS)
520libgnunet_plugin_transport_bluetooth_la_CFLAGS = \
521 $(AM_CFLAGS) -DBUILD_BLUETOOTH
522
523if HAVE_EXPERIMENTAL
524libgnunet_plugin_transport_udp_la_SOURCES = \
525 plugin_transport_udp.c plugin_transport_udp.h \
526 plugin_transport_udp_broadcasting.c
527libgnunet_plugin_transport_udp_la_LIBADD = \
528 $(top_builddir)/src/hello/libgnunethello.la \
529 $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
530 $(top_builddir)/src/statistics/libgnunetstatistics.la \
531 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
532 $(top_builddir)/src/nat/libgnunetnatnew.la \
533 $(top_builddir)/src/util/libgnunetutil.la \
534 $(LTLIBINTL)
535libgnunet_plugin_transport_udp_la_LDFLAGS = \
536 $(GN_PLUGIN_LDFLAGS)
537endif
538
539libgnunet_plugin_transport_unix_la_SOURCES = \
540 plugin_transport_unix.c
541libgnunet_plugin_transport_unix_la_LIBADD = \
542 $(top_builddir)/src/hello/libgnunethello.la \
543 $(top_builddir)/src/statistics/libgnunetstatistics.la \
544 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
545 $(top_builddir)/src/util/libgnunetutil.la \
546 $(LTLIBINTL)
547libgnunet_plugin_transport_unix_la_LDFLAGS = \
548 $(GN_PLUGIN_LDFLAGS)
549
550
551libgnunet_plugin_transport_http_client_la_SOURCES = \
552 plugin_transport_http_client.c plugin_transport_http_common.c plugin_transport_http_common.h
553libgnunet_plugin_transport_http_client_la_LIBADD = \
554 $(top_builddir)/src/hello/libgnunethello.la \
555 $(top_builddir)/src/statistics/libgnunetstatistics.la \
556 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
557 $(LIB_GNURL) \
558 $(top_builddir)/src/util/libgnunetutil.la
559libgnunet_plugin_transport_http_client_la_LDFLAGS = \
560 $(GN_LIBINTL) \
561 $(GN_PLUGIN_LDFLAGS)
562libgnunet_plugin_transport_http_client_la_CFLAGS = \
563 $(CPP_GNURL) $(AM_CFLAGS)
564
565
566libgnunet_plugin_transport_http_server_la_SOURCES = \
567 plugin_transport_http_server.c plugin_transport_http_common.c
568libgnunet_plugin_transport_http_server_la_LIBADD = \
569 $(MHD_LIBS) \
570 $(top_builddir)/src/hello/libgnunethello.la \
571 $(top_builddir)/src/statistics/libgnunetstatistics.la \
572 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
573 $(top_builddir)/src/nat/libgnunetnatnew.la \
574 $(top_builddir)/src/util/libgnunetutil.la
575libgnunet_plugin_transport_http_server_la_LDFLAGS = \
576 $(GN_LIBINTL) \
577 $(GN_PLUGIN_LDFLAGS)
578libgnunet_plugin_transport_http_server_la_CFLAGS = \
579 $(MHD_CFLAGS) $(AM_CFLAGS)
580
581libgnunet_plugin_transport_https_client_la_SOURCES = \
582 plugin_transport_http_client.c plugin_transport_http_common.c
583libgnunet_plugin_transport_https_client_la_LIBADD = \
584 $(top_builddir)/src/hello/libgnunethello.la \
585 $(top_builddir)/src/statistics/libgnunetstatistics.la \
586 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
587 $(LIB_GNURL) \
588 $(top_builddir)/src/util/libgnunetutil.la
589libgnunet_plugin_transport_https_client_la_LDFLAGS = \
590 $(GN_LIBINTL) \
591 $(GN_PLUGIN_LDFLAGS)
592libgnunet_plugin_transport_https_client_la_CFLAGS = \
593 $(CPP_GNURL) $(AM_CFLAGS) -DBUILD_HTTPS
594
595
596libgnunet_plugin_transport_https_server_la_SOURCES = \
597 plugin_transport_http_server.c plugin_transport_http_common.c
598libgnunet_plugin_transport_https_server_la_LIBADD = \
599 $(MHD_LIBS) \
600 $(top_builddir)/src/hello/libgnunethello.la \
601 $(top_builddir)/src/statistics/libgnunetstatistics.la \
602 $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
603 $(top_builddir)/src/nat/libgnunetnatnew.la \
604 $(top_builddir)/src/util/libgnunetutil.la
605libgnunet_plugin_transport_https_server_la_LDFLAGS = \
606 $(GN_LIBINTL) \
607 $(GN_PLUGIN_LDFLAGS)
608libgnunet_plugin_transport_https_server_la_CFLAGS = \
609 $(MHD_CFLAGS) $(AM_CFLAGS) -DBUILD_HTTPS
610
611check_PROGRAMS = \
612 test_transport_address_switch_tcp \
613 test_transport_testing_startstop \
614 test_transport_testing_restart \
615 test_plugin_tcp \
616 $(UNIX_TEST) \
617 $(WLAN_PLUGIN_TEST) \
618 $(BT_PLUGIN_TEST) \
619 test_http_common \
620 $(HTTP_CLIENT_PLUGIN_TEST) \
621 $(HTTPS_CLIENT_PLUGIN_TEST) \
622 $(HTTP_SERVER_PLUGIN_TEST) \
623 $(HTTPS_SERVER_PLUGIN_TEST) \
624 test_transport_api_blacklisting_tcp \
625 test_transport_api_disconnect_tcp \
626 test_transport_api_tcp \
627 test_transport_api2_tcp \
628 test_transport_api_restart_1peer \
629 test_transport_api_restart_2peers \
630 test_transport_api_timeout_tcp \
631 test_transport_api_limited_sockets_tcp \
632 test_transport_api_tcp_nat \
633 $(UNIX_PLUGIN_TEST) \
634 $(UNIX_PLUGIN_TIMEOUT_TEST) \
635 $(UNIX_API_ABSTRACT_TEST) \
636 $(HTTP_API_TEST) \
637 $(HTTP_REVERSE_API_TEST) \
638 $(HTTP_API_TIMEOUT_TEST) \
639 $(HTTP_SWITCH) \
640 $(HTTPS_API_TEST) \
641 $(HTTPS_API_TIMEOUT_TEST) \
642 $(HTTPS_SWITCH) \
643 $(WLAN_API_TEST) \
644 $(WLAN_TIMEOUT_TEST) \
645 $(BT_API_TEST) \
646 $(BT_TIMEOUT_TEST) \
647 test_transport_api_multi \
648 test_transport_api_monitor_peers \
649 test_transport_blacklisting_no_bl \
650 test_transport_blacklisting_outbound_bl_full \
651 test_transport_blacklisting_outbound_bl_plugin \
652 test_transport_blacklisting_inbound_bl_plugin \
653 test_transport_blacklisting_inbound_bl_full \
654 test_transport_blacklisting_multiple_plugins \
655 test_transport_api_manipulation_send_tcp \
656 test_transport_api_manipulation_recv_tcp \
657 test_transport_api_manipulation_cfg \
658 test_transport_api_reliability_tcp \
659 test_transport_api_reliability_tcp_nat \
660 $(UNIX_REL_TEST) \
661 $(HTTP_REL_TEST) \
662 $(HTTPS_REL_TEST) \
663 $(WLAN_REL_TEST) \
664 $(WLAN_UREL_TEST) \
665 $(BT_REL_TEST) \
666 $(BT_UREL_TEST) \
667 test_quota_compliance_tcp \
668 test_quota_compliance_tcp_asymmetric \
669 $(UNIX_QUOTA_TEST) \
670 $(HTTP_QUOTA_TEST) \
671 $(HTTPS_QUOTA_TEST) \
672 $(WLAN_QUOTA_TEST) \
673 $(BT_QUOTA_TEST)
674if HAVE_GETOPT_BINARY
675check_PROGRAMS += \
676test_transport_api_slow_ats
677endif
678if HAVE_EXPERIMENTAL
679check_PROGRAMS += \
680 test_transport_address_switch_udp \
681 test_plugin_udp \
682 test_transport_api_udp \
683 test_transport_api_timeout_udp \
684 test_transport_api_udp_nat \
685 test_transport_api_reliability_udp \
686 test_quota_compliance_udp \
687 test_communicator_basic-unix \
688 test_communicator_basic-tcp \
689 test_communicator_basic-udp \
690 test_communicator_rekey-tcp \
691 test_communicator_rekey-udp \
692 test_communicator_backchannel-udp \
693 test_communicator_bidirect-tcp
694endif
695
696if ENABLE_TEST_RUN
697AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
698TESTS = \
699 test_transport_address_switch_tcp \
700 $(HTTP_SWITCH) \
701 $(HTTPS_SWITCH) \
702 test_transport_testing_startstop \
703 test_transport_testing_restart \
704 test_plugin_tcp \
705 $(UNIX_TEST) \
706 $(WLAN_PLUGIN_TEST) \
707 $(BT_PLUGIN_TEST) \
708 test_transport_api_blacklisting_tcp \
709 test_transport_api_disconnect_tcp \
710 test_transport_api_tcp \
711 test_transport_api_restart_1peer \
712 test_transport_api_restart_2peers \
713 test_transport_api_limited_sockets_tcp \
714 test_transport_api_tcp_nat \
715 $(UNIX_PLUGIN_TEST) \
716 $(UNIX_API_ABSTRACT_TEST) \
717 $(HTTP_API_TEST) \
718 $(HTTPS_API_TEST) \
719 $(WLAN_API_TEST) \
720 $(BT_API_TEST) \
721 test_transport_api_multi \
722 test_transport_api_monitor_peers \
723 test_transport_blacklisting_no_bl \
724 test_transport_blacklisting_outbound_bl_full \
725 test_transport_blacklisting_outbound_bl_plugin \
726 test_transport_blacklisting_inbound_bl_plugin \
727 test_transport_blacklisting_inbound_bl_full \
728 test_transport_blacklisting_multiple_plugins \
729 test_transport_api_manipulation_send_tcp \
730 test_transport_api_manipulation_recv_tcp \
731 test_transport_api_manipulation_cfg \
732 test_transport_api_reliability_tcp \
733 test_transport_api_reliability_tcp_nat \
734 $(UNIX_REL_TEST) \
735 $(HTTP_REL_TEST) \
736 $(HTTPS_REL_TEST) \
737 $(WLAN_REL_TEST) \
738 $(WLAN_UREL_TEST) \
739 $(BT_REL_TEST) \
740 $(BT_UREL_TEST) \
741 test_quota_compliance_tcp \
742 test_quota_compliance_tcp_asymmetric \
743 $(UNIX_QUOTA_TEST) \
744 $(HTTP_QUOTA_TEST) \
745 $(HTTPS_QUOTA_TEST) \
746 test_transport_api_timeout_tcp \
747 $(UNIX_PLUGIN_TIMEOUT_TEST) \
748 $(HTTP_API_TIMEOUT_TEST) \
749 $(HTTPS_API_TIMEOUT_TEST) \
750 $(WLAN_TIMEOUT_TEST) \
751 $(BT_TIMEOUT_TEST) \
752 $(check_SCRIPTS)
753if HAVE_GETOPT_BINARY
754TESTS += \
755test_transport_api_slow_ats
756endif
757if HAVE_EXPERIMENTAL
758TESTS += \
759 test_transport_address_switch_udp \
760 test_plugin_udp \
761 test_transport_api_udp \
762 test_transport_api_timeout_udp \
763 test_transport_api_udp_nat \
764 test_transport_api_reliability_udp \
765 test_quota_compliance_udp \
766 test_communicator_basic-unix \
767 test_communicator_basic-tcp \
768 test_communicator_basic-udp \
769 test_communicator_rekey-tcp \
770 test_communicator_rekey-udp \
771 test_communicator_backchannel-udp \
772 test_communicator_bidirect-tcp
773endif
774endif
775
776# Only test TNG if we run experimental
777if HAVE_EXPERIMENTAL
778check_SCRIPTS= \
779 test_transport_simple_send_string.sh \
780 test_transport_simple_send.sh \
781 test_transport_simple_send_broadcast.sh \
782 test_transport_udp_backchannel.sh \
783 test_transport_simple_send_dv_circle.sh
784 # test_transport_simple_send_dv_inverse.sh
785endif
786
787test_transport_start_with_config_SOURCES = \
788 test_transport_start_with_config.c
789test_transport_start_with_config_LDADD = \
790 $(top_builddir)/src/testing/libgnunettesting.la \
791 $(top_builddir)/src/util/libgnunetutil.la \
792 $(top_builddir)/src/hello/libgnunethello.la \
793 libgnunettransportcore.la \
794 libgnunettransporttesting2.la
795
796test_transport_testing_startstop_SOURCES = \
797 test_transport_testing_startstop.c
798test_transport_testing_startstop_LDADD = \
799 $(top_builddir)/src/util/libgnunetutil.la \
800 libgnunettransport.la \
801 $(top_builddir)/src/hello/libgnunethello.la \
802 libgnunettransporttesting.la
803
804test_transport_testing_restart_SOURCES = \
805 test_transport_testing_restart.c
806test_transport_testing_restart_LDADD = \
807 $(top_builddir)/src/util/libgnunetutil.la \
808 libgnunettransport.la \
809 $(top_builddir)/src/hello/libgnunethello.la \
810 libgnunettransporttesting.la
811
812test_transport_api_blacklisting_tcp_SOURCES = \
813 test_transport_api_blacklisting.c
814test_transport_api_blacklisting_tcp_LDADD = \
815 libgnunettransport.la \
816 $(top_builddir)/src/hello/libgnunethello.la \
817 $(top_builddir)/src/statistics/libgnunetstatistics.la \
818 $(top_builddir)/src/util/libgnunetutil.la \
819 libgnunettransporttesting.la
820
821test_transport_blacklisting_no_bl_SOURCES = \
822 test_transport_blacklisting.c
823test_transport_blacklisting_no_bl_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_outbound_bl_full_SOURCES = \
831 test_transport_blacklisting.c
832test_transport_blacklisting_outbound_bl_full_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_plugin_SOURCES = \
840 test_transport_blacklisting.c
841test_transport_blacklisting_outbound_bl_plugin_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_inbound_bl_full_SOURCES = \
849 test_transport_blacklisting.c
850test_transport_blacklisting_inbound_bl_full_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_plugin_SOURCES = \
858 test_transport_blacklisting.c
859test_transport_blacklisting_inbound_bl_plugin_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_multiple_plugins_SOURCES = \
867 test_transport_blacklisting.c
868test_transport_blacklisting_multiple_plugins_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
875
876test_transport_api_disconnect_tcp_SOURCES = \
877 test_transport_api_disconnect.c
878test_transport_api_disconnect_tcp_LDADD = \
879 libgnunettransport.la \
880 $(top_builddir)/src/hello/libgnunethello.la \
881 $(top_builddir)/src/statistics/libgnunetstatistics.la \
882 $(top_builddir)/src/util/libgnunetutil.la \
883 libgnunettransporttesting.la
884
885test_plugin_tcp_SOURCES = \
886 test_plugin_transport.c
887test_plugin_tcp_LDADD = \
888 libgnunettransport.la \
889 $(top_builddir)/src/statistics/libgnunetstatistics.la \
890 $(top_builddir)/src/hello/libgnunethello.la \
891 $(top_builddir)/src/util/libgnunetutil.la \
892 libgnunettransporttesting.la
893
894if HAVE_EXPERIMENTAL
895test_plugin_udp_SOURCES = \
896 test_plugin_transport.c
897test_plugin_udp_LDADD = \
898 libgnunettransport.la \
899 $(top_builddir)/src/statistics/libgnunetstatistics.la \
900 $(top_builddir)/src/hello/libgnunethello.la \
901 $(top_builddir)/src/util/libgnunetutil.la \
902 libgnunettransporttesting.la
903endif
904
905if HAVE_EXPERIMENTAL
906test_communicator_basic_unix_SOURCES = \
907 test_communicator_basic.c
908test_communicator_basic_unix_LDADD = \
909 libgnunettransporttesting2.la \
910 $(top_builddir)/src/testing/libgnunettesting.la \
911 $(top_builddir)/src/util/libgnunetutil.la \
912 $(top_builddir)/src/statistics/libgnunetstatistics.la
913
914test_communicator_basic_tcp_SOURCES = \
915 test_communicator_basic.c
916test_communicator_basic_tcp_LDADD = \
917 libgnunettransporttesting2.la \
918 $(top_builddir)/src/testing/libgnunettesting.la \
919 $(top_builddir)/src/util/libgnunetutil.la \
920 $(top_builddir)/src/statistics/libgnunetstatistics.la
921
922test_communicator_basic_udp_SOURCES = \
923 test_communicator_basic.c
924test_communicator_basic_udp_LDADD = \
925 libgnunettransporttesting2.la \
926 $(top_builddir)/src/testing/libgnunettesting.la \
927 $(top_builddir)/src/util/libgnunetutil.la \
928 $(top_builddir)/src/statistics/libgnunetstatistics.la
929
930test_communicator_rekey_tcp_SOURCES = \
931 test_communicator_basic.c
932test_communicator_rekey_tcp_LDADD = \
933 libgnunettransporttesting2.la \
934 $(top_builddir)/src/testing/libgnunettesting.la \
935 $(top_builddir)/src/util/libgnunetutil.la \
936 $(top_builddir)/src/statistics/libgnunetstatistics.la
937
938test_communicator_rekey_udp_SOURCES = \
939 test_communicator_basic.c
940test_communicator_rekey_udp_LDADD = \
941 libgnunettransporttesting2.la \
942 $(top_builddir)/src/testing/libgnunettesting.la \
943 $(top_builddir)/src/util/libgnunetutil.la \
944 $(top_builddir)/src/statistics/libgnunetstatistics.la
945
946test_communicator_backchannel_udp_SOURCES = \
947 test_communicator_basic.c
948test_communicator_backchannel_udp_LDADD = \
949 libgnunettransporttesting2.la \
950 $(top_builddir)/src/testing/libgnunettesting.la \
951 $(top_builddir)/src/util/libgnunetutil.la \
952 $(top_builddir)/src/statistics/libgnunetstatistics.la
953
954test_communicator_bidirect_tcp_SOURCES = \
955 test_communicator_basic.c
956test_communicator_bidirect_tcp_LDADD = \
957 libgnunettransporttesting2.la \
958 $(top_builddir)/src/testing/libgnunettesting.la \
959 $(top_builddir)/src/util/libgnunetutil.la \
960 $(top_builddir)/src/statistics/libgnunetstatistics.la
961endif
962
963test_plugin_unix_SOURCES = \
964 test_plugin_transport.c
965test_plugin_unix_LDADD = \
966 libgnunettransport.la \
967 $(top_builddir)/src/statistics/libgnunetstatistics.la \
968 $(top_builddir)/src/hello/libgnunethello.la \
969 $(top_builddir)/src/util/libgnunetutil.la \
970 libgnunettransporttesting.la
971
972test_plugin_wlan_SOURCES = \
973 test_plugin_transport.c
974test_plugin_wlan_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_bluetooth_SOURCES = \
982 test_plugin_transport.c
983test_plugin_bluetooth_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_http_common_SOURCES = \
991 test_http_common.c plugin_transport_http_common.c
992test_http_common_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_plugin_http_server_SOURCES = \
1000 test_plugin_transport.c
1001test_plugin_http_server_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_https_server_SOURCES = \
1009 test_plugin_transport.c
1010test_plugin_https_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_http_client_SOURCES = \
1018 test_plugin_transport.c
1019test_plugin_http_client_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_https_client_SOURCES = \
1027 test_plugin_transport.c
1028test_plugin_https_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_transport_api_tcp_SOURCES = \
1036 test_transport_api.c
1037test_transport_api_tcp_LDADD = \
1038 libgnunettransport.la \
1039 $(top_builddir)/src/hello/libgnunethello.la \
1040 $(top_builddir)/src/util/libgnunetutil.la \
1041 libgnunettransporttesting.la
1042
1043test_transport_api2_tcp_SOURCES = \
1044 test_transport_api2.c
1045test_transport_api2_tcp_LDADD = \
1046 $(top_builddir)/src/hello/libgnunethello.la \
1047 $(top_builddir)/src/util/libgnunetutil.la \
1048 libgnunettransporttesting2.la
1049
1050test_transport_api_restart_1peer_SOURCES = \
1051 test_transport_api_restart_reconnect.c
1052test_transport_api_restart_1peer_LDADD = \
1053 libgnunettransport.la \
1054 $(top_builddir)/src/hello/libgnunethello.la \
1055 $(top_builddir)/src/ats/libgnunetats.la \
1056 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1057 $(top_builddir)/src/util/libgnunetutil.la \
1058 libgnunettransporttesting.la
1059
1060test_transport_api_restart_2peers_SOURCES = \
1061 test_transport_api_restart_reconnect.c
1062test_transport_api_restart_2peers_LDADD = \
1063 libgnunettransport.la \
1064 $(top_builddir)/src/hello/libgnunethello.la \
1065 $(top_builddir)/src/ats/libgnunetats.la \
1066$(top_builddir)/src/statistics/libgnunetstatistics.la \
1067 $(top_builddir)/src/util/libgnunetutil.la \
1068 libgnunettransporttesting.la
1069
1070test_transport_api_limited_sockets_tcp_SOURCES = \
1071 test_transport_api_limited_sockets.c
1072test_transport_api_limited_sockets_tcp_LDADD = \
1073 libgnunettransport.la \
1074 $(top_builddir)/src/hello/libgnunethello.la \
1075 $(top_builddir)/src/util/libgnunetutil.la \
1076 libgnunettransporttesting.la
1077
1078test_transport_api_tcp_nat_SOURCES = \
1079 test_transport_api.c
1080test_transport_api_tcp_nat_LDADD = \
1081 libgnunettransport.la \
1082 $(top_builddir)/src/hello/libgnunethello.la \
1083 $(top_builddir)/src/util/libgnunetutil.la \
1084 libgnunettransporttesting.la
1085
1086test_transport_api_manipulation_send_tcp_SOURCES = \
1087 test_transport_api_manipulation_send_tcp.c
1088test_transport_api_manipulation_send_tcp_LDADD = \
1089 libgnunettransport.la \
1090 $(top_builddir)/src/hello/libgnunethello.la \
1091 $(top_builddir)/src/util/libgnunetutil.la \
1092 libgnunettransporttesting.la
1093
1094test_transport_api_manipulation_recv_tcp_SOURCES = \
1095 test_transport_api_manipulation_recv_tcp.c
1096test_transport_api_manipulation_recv_tcp_LDADD = \
1097 libgnunettransport.la \
1098 $(top_builddir)/src/hello/libgnunethello.la \
1099 $(top_builddir)/src/util/libgnunetutil.la \
1100 libgnunettransporttesting.la
1101
1102test_transport_api_manipulation_cfg_SOURCES = \
1103 test_transport_api_manipulation_cfg.c
1104test_transport_api_manipulation_cfg_LDADD = \
1105 libgnunettransport.la \
1106 $(top_builddir)/src/hello/libgnunethello.la \
1107 $(top_builddir)/src/util/libgnunetutil.la \
1108 libgnunettransporttesting.la
1109
1110test_transport_api_reliability_tcp_SOURCES = \
1111 test_transport_api_reliability.c
1112test_transport_api_reliability_tcp_LDADD = \
1113 libgnunettransport.la \
1114 $(top_builddir)/src/hello/libgnunethello.la \
1115 $(top_builddir)/src/util/libgnunetutil.la \
1116 libgnunettransporttesting.la
1117
1118test_transport_api_timeout_tcp_SOURCES = \
1119 test_transport_api_timeout.c
1120test_transport_api_timeout_tcp_LDADD = \
1121 libgnunettransport.la \
1122 $(top_builddir)/src/hello/libgnunethello.la \
1123 $(top_builddir)/src/util/libgnunetutil.la \
1124 libgnunettransporttesting.la
1125
1126test_transport_api_timeout_unix_SOURCES = \
1127 test_transport_api_timeout.c
1128test_transport_api_timeout_unix_LDADD = \
1129 libgnunettransport.la \
1130 $(top_builddir)/src/hello/libgnunethello.la \
1131 $(top_builddir)/src/util/libgnunetutil.la \
1132 libgnunettransporttesting.la
1133
1134test_transport_api_timeout_wlan_SOURCES = \
1135 test_transport_api_timeout.c
1136test_transport_api_timeout_wlan_LDADD = \
1137 libgnunettransport.la \
1138 $(top_builddir)/src/hello/libgnunethello.la \
1139 $(top_builddir)/src/util/libgnunetutil.la \
1140 libgnunettransporttesting.la
1141
1142test_transport_api_timeout_bluetooth_SOURCES = \
1143 test_transport_api_timeout.c
1144test_transport_api_timeout_bluetooth_LDADD = \
1145 libgnunettransport.la \
1146 $(top_builddir)/src/hello/libgnunethello.la \
1147 $(top_builddir)/src/util/libgnunetutil.la \
1148 libgnunettransporttesting.la
1149
1150test_transport_api_reliability_tcp_nat_SOURCES = \
1151 test_transport_api_reliability.c
1152test_transport_api_reliability_tcp_nat_LDADD = \
1153 libgnunettransport.la \
1154 $(top_builddir)/src/hello/libgnunethello.la \
1155 $(top_builddir)/src/util/libgnunetutil.la \
1156 libgnunettransporttesting.la
1157
1158test_transport_api_reliability_bluetooth_SOURCES = \
1159 test_transport_api_reliability.c
1160test_transport_api_reliability_bluetooth_LDADD = \
1161 libgnunettransport.la \
1162 $(top_builddir)/src/hello/libgnunethello.la \
1163 $(top_builddir)/src/util/libgnunetutil.la \
1164 libgnunettransporttesting.la
1165
1166test_transport_api_reliability_wlan_SOURCES = \
1167 test_transport_api_reliability.c
1168test_transport_api_reliability_wlan_LDADD = \
1169 libgnunettransport.la \
1170 $(top_builddir)/src/hello/libgnunethello.la \
1171 $(top_builddir)/src/util/libgnunetutil.la \
1172 libgnunettransporttesting.la
1173
1174if HAVE_EXPERIMENTAL
1175test_transport_api_udp_SOURCES = \
1176 test_transport_api.c
1177test_transport_api_udp_LDADD = \
1178 libgnunettransport.la \
1179 $(top_builddir)/src/hello/libgnunethello.la \
1180 $(top_builddir)/src/util/libgnunetutil.la \
1181 libgnunettransporttesting.la
1182
1183test_transport_api_timeout_udp_SOURCES = \
1184 test_transport_api_timeout.c
1185test_transport_api_timeout_udp_LDADD = \
1186 libgnunettransport.la \
1187 $(top_builddir)/src/hello/libgnunethello.la \
1188 $(top_builddir)/src/util/libgnunetutil.la \
1189 libgnunettransporttesting.la
1190
1191test_transport_api_udp_nat_SOURCES = \
1192 test_transport_api.c
1193test_transport_api_udp_nat_LDADD = \
1194 libgnunettransport.la \
1195 $(top_builddir)/src/hello/libgnunethello.la \
1196 $(top_builddir)/src/util/libgnunetutil.la \
1197 libgnunettransporttesting.la
1198endif
1199
1200test_transport_api_unix_SOURCES = \
1201 test_transport_api.c
1202test_transport_api_unix_LDADD = \
1203 libgnunettransport.la \
1204 $(top_builddir)/src/hello/libgnunethello.la \
1205 $(top_builddir)/src/util/libgnunetutil.la \
1206 libgnunettransporttesting.la
1207
1208test_transport_api_unix_abstract_SOURCES = \
1209 test_transport_api.c
1210test_transport_api_unix_abstract_LDADD = \
1211 libgnunettransport.la \
1212 $(top_builddir)/src/hello/libgnunethello.la \
1213 $(top_builddir)/src/util/libgnunetutil.la \
1214 libgnunettransporttesting.la
1215
1216# HTTP tests
1217test_transport_api_http_SOURCES = \
1218 test_transport_api.c
1219test_transport_api_http_LDADD = \
1220 libgnunettransport.la \
1221 $(top_builddir)/src/hello/libgnunethello.la \
1222 $(top_builddir)/src/util/libgnunetutil.la \
1223 libgnunettransporttesting.la
1224
1225test_transport_api_http_reverse_SOURCES = \
1226 test_transport_api.c
1227test_transport_api_http_reverse_LDADD = \
1228 libgnunettransport.la \
1229 $(top_builddir)/src/hello/libgnunethello.la \
1230 $(top_builddir)/src/util/libgnunetutil.la \
1231 libgnunettransporttesting.la
1232
1233test_transport_api_timeout_http_SOURCES = \
1234 test_transport_api_timeout.c
1235test_transport_api_timeout_http_LDADD = \
1236 libgnunettransport.la \
1237 $(top_builddir)/src/hello/libgnunethello.la \
1238 $(top_builddir)/src/util/libgnunetutil.la \
1239 libgnunettransporttesting.la
1240
1241test_transport_api_reliability_http_SOURCES = \
1242 test_transport_api_reliability.c
1243test_transport_api_reliability_http_LDADD = \
1244 libgnunettransport.la \
1245 $(top_builddir)/src/hello/libgnunethello.la \
1246 $(top_builddir)/src/util/libgnunetutil.la \
1247 libgnunettransporttesting.la
1248
1249test_transport_api_reliability_http_xhr_SOURCES = \
1250 test_transport_api_reliability.c
1251test_transport_api_reliability_http_xhr_LDADD = \
1252 libgnunettransport.la \
1253 $(top_builddir)/src/hello/libgnunethello.la \
1254 $(top_builddir)/src/util/libgnunetutil.la \
1255 libgnunettransporttesting.la
1256
1257test_quota_compliance_http_SOURCES = \
1258 test_quota_compliance.c
1259test_quota_compliance_http_LDADD = \
1260 libgnunettransport.la \
1261 $(top_builddir)/src/hello/libgnunethello.la \
1262 $(top_builddir)/src/ats/libgnunetats.la \
1263 $(top_builddir)/src/nt/libgnunetnt.la \
1264 $(top_builddir)/src/util/libgnunetutil.la \
1265 libgnunettransporttesting.la
1266
1267test_quota_compliance_http_asymmetric_SOURCES = \
1268 test_quota_compliance.c
1269test_quota_compliance_http_asymmetric_LDADD = \
1270 libgnunettransport.la \
1271 $(top_builddir)/src/hello/libgnunethello.la \
1272 $(top_builddir)/src/ats/libgnunetats.la \
1273 $(top_builddir)/src/nt/libgnunetnt.la \
1274 $(top_builddir)/src/util/libgnunetutil.la \
1275 libgnunettransporttesting.la
1276
1277test_quota_compliance_https_SOURCES = \
1278 test_quota_compliance.c
1279test_quota_compliance_https_LDADD = \
1280 libgnunettransport.la \
1281 $(top_builddir)/src/hello/libgnunethello.la \
1282 $(top_builddir)/src/ats/libgnunetats.la \
1283 $(top_builddir)/src/nt/libgnunetnt.la \
1284 $(top_builddir)/src/util/libgnunetutil.la \
1285 libgnunettransporttesting.la
1286
1287test_quota_compliance_https_asymmetric_SOURCES = \
1288 test_quota_compliance.c
1289test_quota_compliance_https_asymmetric_LDADD = \
1290 libgnunettransport.la \
1291 $(top_builddir)/src/hello/libgnunethello.la \
1292 $(top_builddir)/src/ats/libgnunetats.la \
1293 $(top_builddir)/src/nt/libgnunetnt.la \
1294 $(top_builddir)/src/util/libgnunetutil.la \
1295 libgnunettransporttesting.la
1296
1297# HTTPS tests
1298test_transport_api_https_SOURCES = \
1299 test_transport_api.c
1300test_transport_api_https_LDADD = \
1301 libgnunettransport.la \
1302 $(top_builddir)/src/hello/libgnunethello.la \
1303 $(top_builddir)/src/util/libgnunetutil.la \
1304 libgnunettransporttesting.la
1305
1306test_transport_api_timeout_https_SOURCES = \
1307 test_transport_api_timeout.c
1308test_transport_api_timeout_https_LDADD = \
1309 libgnunettransport.la \
1310 $(top_builddir)/src/hello/libgnunethello.la \
1311 $(top_builddir)/src/util/libgnunetutil.la \
1312 libgnunettransporttesting.la
1313
1314
1315test_transport_api_reliability_https_SOURCES = \
1316 test_transport_api_reliability.c
1317test_transport_api_reliability_https_LDADD = \
1318 libgnunettransport.la \
1319 $(top_builddir)/src/hello/libgnunethello.la \
1320 $(top_builddir)/src/util/libgnunetutil.la \
1321 libgnunettransporttesting.la
1322
1323test_transport_api_reliability_https_xhr_SOURCES = \
1324 test_transport_api_reliability.c
1325test_transport_api_reliability_https_xhr_LDADD = \
1326 libgnunettransport.la \
1327 $(top_builddir)/src/hello/libgnunethello.la \
1328 $(top_builddir)/src/util/libgnunetutil.la \
1329 libgnunettransporttesting.la
1330
1331test_transport_api_reliability_unix_SOURCES = \
1332 test_transport_api_reliability.c
1333test_transport_api_reliability_unix_LDADD = \
1334 libgnunettransport.la \
1335 $(top_builddir)/src/hello/libgnunethello.la \
1336 $(top_builddir)/src/util/libgnunetutil.la \
1337 libgnunettransporttesting.la
1338
1339if HAVE_EXPERIMENTAL
1340test_transport_api_reliability_udp_SOURCES = \
1341 test_transport_api_reliability.c
1342test_transport_api_reliability_udp_LDADD = \
1343 libgnunettransport.la \
1344 $(top_builddir)/src/hello/libgnunethello.la \
1345 $(top_builddir)/src/util/libgnunetutil.la \
1346 libgnunettransporttesting.la
1347endif
1348
1349if LINUX
1350test_transport_api_wlan_SOURCES = \
1351 test_transport_api.c
1352test_transport_api_wlan_LDADD = \
1353 libgnunettransport.la \
1354 $(top_builddir)/src/hello/libgnunethello.la \
1355 $(top_builddir)/src/util/libgnunetutil.la \
1356 libgnunettransporttesting.la
1357endif
1358
1359if LINUX
1360if HAVE_LIBBLUETOOTH
1361test_transport_api_bluetooth_SOURCES = \
1362 test_transport_api.c
1363test_transport_api_bluetooth_LDADD = \
1364 libgnunettransport.la \
1365 $(top_builddir)/src/hello/libgnunethello.la \
1366 $(top_builddir)/src/util/libgnunetutil.la \
1367 libgnunettransporttesting.la
1368endif
1369endif
1370
1371test_transport_address_switch_tcp_SOURCES = \
1372 test_transport_address_switch.c
1373test_transport_address_switch_tcp_LDADD = \
1374 libgnunettransport.la \
1375 $(top_builddir)/src/hello/libgnunethello.la \
1376 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1377 $(top_builddir)/src/util/libgnunetutil.la \
1378 libgnunettransporttesting.la
1379
1380if HAVE_EXPERIMENTAL
1381test_transport_address_switch_udp_SOURCES = \
1382 test_transport_address_switch.c
1383test_transport_address_switch_udp_LDADD = \
1384 libgnunettransport.la \
1385 $(top_builddir)/src/hello/libgnunethello.la \
1386 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1387 $(top_builddir)/src/util/libgnunetutil.la \
1388 libgnunettransporttesting.la
1389endif
1390
1391 test_transport_address_switch_http_SOURCES = \
1392 test_transport_address_switch.c
1393test_transport_address_switch_http_LDADD = \
1394 libgnunettransport.la \
1395 $(top_builddir)/src/hello/libgnunethello.la \
1396 $(top_builddir)/src/statistics/libgnunetstatistics.la \
1397 $(top_builddir)/src/util/libgnunetutil.la \
1398 libgnunettransporttesting.la
1399
1400 test_transport_address_switch_https_SOURCES = \
1401 test_transport_address_switch.c
1402test_transport_address_switch_https_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
1409test_quota_compliance_tcp_SOURCES = \
1410 test_quota_compliance.c
1411test_quota_compliance_tcp_LDADD = \
1412 libgnunettransport.la \
1413 $(top_builddir)/src/hello/libgnunethello.la \
1414 $(top_builddir)/src/ats/libgnunetats.la \
1415 $(top_builddir)/src/nt/libgnunetnt.la \
1416 $(top_builddir)/src/util/libgnunetutil.la \
1417 libgnunettransporttesting.la
1418
1419test_quota_compliance_tcp_asymmetric_SOURCES = \
1420 test_quota_compliance.c
1421test_quota_compliance_tcp_asymmetric_LDADD = \
1422 libgnunettransport.la \
1423 $(top_builddir)/src/hello/libgnunethello.la \
1424 $(top_builddir)/src/nt/libgnunetnt.la \
1425 $(top_builddir)/src/ats/libgnunetats.la \
1426 $(top_builddir)/src/util/libgnunetutil.la \
1427 libgnunettransporttesting.la
1428
1429if HAVE_EXPERIMENTAL
1430test_quota_compliance_udp_SOURCES = \
1431 test_quota_compliance.c
1432test_quota_compliance_udp_LDADD = \
1433 libgnunettransport.la \
1434 $(top_builddir)/src/hello/libgnunethello.la \
1435 $(top_builddir)/src/ats/libgnunetats.la \
1436 $(top_builddir)/src/nt/libgnunetnt.la \
1437 $(top_builddir)/src/util/libgnunetutil.la \
1438 libgnunettransporttesting.la
1439endif
1440
1441test_quota_compliance_unix_SOURCES = \
1442 test_quota_compliance.c
1443test_quota_compliance_unix_LDADD = \
1444 libgnunettransport.la \
1445 $(top_builddir)/src/hello/libgnunethello.la \
1446 $(top_builddir)/src/ats/libgnunetats.la \
1447 $(top_builddir)/src/nt/libgnunetnt.la \
1448 $(top_builddir)/src/util/libgnunetutil.la \
1449 libgnunettransporttesting.la
1450
1451test_quota_compliance_unix_asymmetric_SOURCES = \
1452 test_quota_compliance.c
1453test_quota_compliance_unix_asymmetric_LDADD = \
1454 libgnunettransport.la \
1455 $(top_builddir)/src/hello/libgnunethello.la \
1456 $(top_builddir)/src/ats/libgnunetats.la \
1457 $(top_builddir)/src/nt/libgnunetnt.la \
1458 $(top_builddir)/src/util/libgnunetutil.la \
1459 libgnunettransporttesting.la
1460
1461test_quota_compliance_wlan_SOURCES = \
1462 test_quota_compliance.c
1463test_quota_compliance_wlan_LDADD = \
1464 libgnunettransport.la \
1465 $(top_builddir)/src/hello/libgnunethello.la \
1466 $(top_builddir)/src/ats/libgnunetats.la \
1467 $(top_builddir)/src/nt/libgnunetnt.la \
1468 $(top_builddir)/src/util/libgnunetutil.la \
1469 libgnunettransporttesting.la
1470
1471test_quota_compliance_wlan_asymmetric_SOURCES = \
1472 test_quota_compliance.c
1473test_quota_compliance_wlan_asymmetric_LDADD = \
1474 libgnunettransport.la \
1475 $(top_builddir)/src/hello/libgnunethello.la \
1476 $(top_builddir)/src/ats/libgnunetats.la \
1477 $(top_builddir)/src/nt/libgnunetnt.la \
1478 $(top_builddir)/src/util/libgnunetutil.la \
1479 libgnunettransporttesting.la
1480
1481test_quota_compliance_bluetooth_SOURCES = \
1482 test_quota_compliance.c
1483test_quota_compliance_bluetooth_LDADD = \
1484 libgnunettransport.la \
1485 $(top_builddir)/src/hello/libgnunethello.la \
1486 $(top_builddir)/src/ats/libgnunetats.la \
1487 $(top_builddir)/src/nt/libgnunetnt.la \
1488 $(top_builddir)/src/util/libgnunetutil.la \
1489 libgnunettransporttesting.la
1490
1491test_quota_compliance_bluetooth_asymmetric_SOURCES = \
1492 test_quota_compliance.c
1493test_quota_compliance_bluetooth_asymmetric_LDADD = \
1494 libgnunettransport.la \
1495 $(top_builddir)/src/hello/libgnunethello.la \
1496 $(top_builddir)/src/ats/libgnunetats.la \
1497 $(top_builddir)/src/nt/libgnunetnt.la \
1498 $(top_builddir)/src/util/libgnunetutil.la \
1499 libgnunettransporttesting.la
1500
1501test_transport_api_multi_SOURCES = \
1502 test_transport_api.c
1503test_transport_api_multi_LDADD = \
1504 libgnunettransport.la \
1505 $(top_builddir)/src/hello/libgnunethello.la \
1506 $(top_builddir)/src/util/libgnunetutil.la \
1507 libgnunettransporttesting.la
1508
1509test_transport_api_monitor_peers_SOURCES = \
1510 test_transport_api_monitor_peers.c
1511test_transport_api_monitor_peers_LDADD = \
1512 libgnunettransport.la \
1513 $(top_builddir)/src/hello/libgnunethello.la \
1514 $(top_builddir)/src/util/libgnunetutil.la \
1515 libgnunettransporttesting.la
1516
1517test_transport_api_slow_ats_SOURCES = \
1518 test_transport_api.c
1519test_transport_api_slow_ats_LDADD = \
1520 libgnunettransport.la \
1521 $(top_builddir)/src/hello/libgnunethello.la \
1522 $(top_builddir)/src/util/libgnunetutil.la \
1523 libgnunettransporttesting.la
1524
1525
1526EXTRA_DIST = \
1527test_transport_simple_send_string.sh \
1528test_transport_simple_send.sh \
1529test_transport_simple_send_broadcast.sh \
1530test_transport_udp_backchannel.sh \
1531test_transport_simple_send_dv_circle.sh \
1532gnunet-transport-certificate-creation.in \
1533communicator-unix.conf \
1534test_plugin_hostkey \
1535test_plugin_hostkey.ecc \
1536test_delay \
1537template_cfg_peer1.conf\
1538template_cfg_peer2.conf\
1539test_plugin_transport_data.conf\
1540test_plugin_transport_data_udp.conf\
1541test_quota_compliance_data.conf\
1542test_quota_compliance_http_peer1.conf\
1543test_quota_compliance_http_peer2.conf\
1544test_quota_compliance_https_peer1.conf\
1545test_quota_compliance_https_peer2.conf\
1546test_quota_compliance_tcp_peer1.conf\
1547test_quota_compliance_tcp_peer2.conf\
1548test_quota_compliance_udp_peer1.conf\
1549test_quota_compliance_udp_peer2.conf\
1550test_quota_compliance_unix_peer1.conf\
1551test_quota_compliance_unix_peer2.conf\
1552test_quota_compliance_wlan_peer1.conf\
1553test_quota_compliance_wlan_peer2.conf\
1554test_quota_compliance_bluetooth_peer1.conf\
1555test_quota_compliance_bluetooth_peer2.conf\
1556test_quota_compliance_http_asymmetric_peer1.conf\
1557test_quota_compliance_http_asymmetric_peer2.conf\
1558test_quota_compliance_https_asymmetric_peer1.conf\
1559test_quota_compliance_https_asymmetric_peer2.conf\
1560test_quota_compliance_tcp_asymmetric_peer1.conf\
1561test_quota_compliance_tcp_asymmetric_peer2.conf\
1562test_quota_compliance_unix_asymmetric_peer1.conf\
1563test_quota_compliance_unix_asymmetric_peer2.conf\
1564test_quota_compliance_wlan_asymmetric_peer1.conf\
1565test_quota_compliance_wlan_asymmetric_peer2.conf\
1566test_quota_compliance_bluetooth_asymmetric_peer1.conf\
1567test_quota_compliance_bluetooth_asymmetric_peer2.conf\
1568test_transport_api_data.conf\
1569test_transport_api_blacklisting_tcp_peer1.conf \
1570test_transport_api_blacklisting_tcp_peer2.conf \
1571test_transport_api_http_peer1.conf\
1572test_transport_api_http_peer2.conf\
1573test_transport_api_https_peer1.conf\
1574test_transport_api_https_peer2.conf\
1575test_transport_api_limited_sockets_tcp_peer1.conf\
1576test_transport_api_limited_sockets_tcp_peer2.conf\
1577test_transport_api_timeout_tcp_peer1.conf\
1578test_transport_api_timeout_tcp_peer2.conf\
1579test_transport_api_multi_peer1.conf\
1580test_transport_api_multi_peer2.conf\
1581test_transport_api_restart_1peer_peer1.conf\
1582test_transport_api_restart_1peer_peer2.conf\
1583test_transport_api_reliability_http_peer1.conf\
1584test_transport_api_reliability_http_peer2.conf\
1585test_transport_api_reliability_https_peer1.conf\
1586test_transport_api_reliability_https_peer2.conf\
1587test_transport_api_reliability_tcp_nat_peer1.conf\
1588test_transport_api_reliability_tcp_nat_peer2.conf\
1589test_transport_api_reliability_tcp_peer1.conf\
1590test_transport_api_reliability_tcp_peer2.conf\
1591test_transport_api_reliability_wlan_peer1.conf\
1592test_transport_api_reliability_wlan_peer2.conf\
1593test_transport_api_reliability_bluetooth_peer1.conf\
1594test_transport_api_reliability_bluetooth_peer2.conf\
1595test_transport_api_manipulation_send_tcp_peer1.conf\
1596test_transport_api_manipulation_send_tcp_peer2.conf\
1597test_transport_api_manipulation_recv_tcp_peer1.conf\
1598test_transport_api_manipulation_recv_tcp_peer2.conf\
1599test_transport_api_manipulation_cfg_peer1.conf\
1600test_transport_api_manipulation_cfg_peer2.conf\
1601test_transport_api_restart_1peer_peer1.conf\
1602test_transport_api_restart_1peer_peer2.conf\
1603test_transport_api_restart_2peers_peer1.conf\
1604test_transport_api_restart_2peers_peer2.conf\
1605test_transport_api_tcp_nat_peer1.conf\
1606test_transport_api_tcp_nat_peer2.conf\
1607test_transport_api_tcp_peer1.conf\
1608test_transport_api_tcp_peer2.conf\
1609test_transport_api2_tcp_peer1.conf\
1610test_transport_api2_tcp_peer2.conf\
1611test_transport_api_udp_nat_peer1.conf\
1612test_transport_api_udp_nat_peer2.conf\
1613test_transport_api_udp_peer1.conf\
1614test_transport_api_udp_peer2.conf\
1615test_transport_api_timeout_udp_peer1.conf\
1616test_transport_api_timeout_udp_peer2.conf\
1617test_transport_api_unix_peer1.conf\
1618test_transport_api_unix_peer2.conf\
1619test_transport_api_unix_abstract_peer1.conf \
1620test_transport_api_unix_abstract_peer2.conf \
1621test_transport_api_timeout_unix_peer1.conf\
1622test_transport_api_timeout_unix_peer2.conf\
1623test_transport_api_timeout_wlan_peer1.conf \
1624test_transport_api_timeout_wlan_peer2.conf \
1625test_transport_api_timeout_bluetooth_peer1.conf\
1626test_transport_api_timeout_bluetooth_peer2.conf\
1627test_transport_api_reliability_udp_peer1.conf\
1628test_transport_api_reliability_udp_peer2.conf\
1629test_transport_api_reliability_http_xhr_peer1.conf\
1630test_transport_api_reliability_http_xhr_peer2.conf\
1631test_transport_api_reliability_https_xhr_peer1.conf\
1632test_transport_api_reliability_https_xhr_peer2.conf\
1633test_transport_api_reliability_unix_peer1.conf\
1634test_transport_api_reliability_unix_peer2.conf\
1635test_transport_api_reliability_wlan_peer1.conf\
1636test_transport_api_reliability_wlan_peer2.conf\
1637test_transport_api_unreliability_wlan_peer1.conf\
1638test_transport_api_unreliability_wlan_peer2.conf\
1639test_transport_api_reliability_bluetooth_peer1.conf\
1640test_transport_api_reliability_bluetooth_peer2.conf\
1641test_transport_api_wlan_peer1.conf\
1642test_transport_api_wlan_peer2.conf\
1643test_transport_api_bluetooth_peer1.conf\
1644test_transport_api_bluetooth_peer2.conf\
1645test_transport_api_monitor_peers_peer1.conf\
1646test_transport_api_monitor_peers_peer2.conf\
1647test_transport_api_monitor_validation_peer1.conf\
1648test_transport_api_monitor_validation_peer2.conf\
1649test_transport_defaults.conf\
1650test_transport_api_disconnect_tcp_peer1.conf\
1651test_transport_api_disconnect_tcp_peer2.conf\
1652test_transport_api_timeout_http_peer1.conf\
1653test_transport_api_timeout_http_peer2.conf\
1654test_transport_api_timeout_https_peer1.conf\
1655test_transport_api_timeout_https_peer2.conf\
1656test_transport_blacklisting_cfg_peer1.conf \
1657test_transport_blacklisting_cfg_peer2.conf \
1658test_transport_blacklisting_cfg_blp_peer1_full.conf\
1659test_transport_blacklisting_cfg_blp_peer1_plugin.conf \
1660test_transport_blacklisting_cfg_blp_peer2_full.conf\
1661test_transport_blacklisting_cfg_blp_peer2_plugin.conf \
1662test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf \
1663test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf \
1664test_transport_api_http_reverse_peer1.conf \
1665test_transport_api_http_reverse_peer2.conf \
1666perf_tcp_peer1.conf \
1667perf_tcp_peer2.conf \
1668test_transport_api_slow_ats_peer1.conf \
1669test_transport_api_slow_ats_peer2.conf \
1670 tcp_connection_legacy.c \
1671 tcp_server_mst_legacy.c \
1672 tcp_server_legacy.c \
1673 tcp_service_legacy.c \
1674test_communicator_unix_basic_peer1.conf \
1675test_communicator_unix_basic_peer2.conf \
1676test_communicator_tcp_basic_peer1.conf \
1677test_communicator_tcp_basic_peer2.conf \
1678test_communicator_udp_basic_peer1.conf \
1679test_communicator_udp_basic_peer2.conf \
1680test_communicator_tcp_rekey_peer1.conf \
1681test_communicator_tcp_rekey_peer2.conf \
1682test_communicator_udp_rekey_peer1.conf \
1683test_communicator_udp_rekey_peer2.conf \
1684test_communicator_udp_backchannel_peer1.conf \
1685test_communicator_udp_backchannel_peer2.conf \
1686test_communicator_tcp_bidirect_peer1.conf \
1687test_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 be75fa0e8..000000000
--- a/src/transport/gnunet-communicator-tcp.c
+++ /dev/null
@@ -1,3682 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014, 2018, 2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-communicator-tcp.c
23 * @brief Transport plugin using TCP.
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - support NAT connection reversal method (#5529)
28 * - support other TCP-specific NAT traversal methods (#5531)
29 */
30#include "platform.h"
31#include "gnunet_util_lib.h"
32#include "gnunet_core_service.h"
33#include "gnunet_peerstore_service.h"
34#include "gnunet_protocols.h"
35#include "gnunet_signatures.h"
36#include "gnunet_constants.h"
37#include "gnunet_nt_lib.h"
38#include "gnunet_nat_service.h"
39#include "gnunet_statistics_service.h"
40#include "gnunet_transport_communication_service.h"
41#include "gnunet_resolver_service.h"
42
43/**
44 * How long do we believe our addresses to remain up (before
45 * the other peer should revalidate).
46 */
47#define ADDRESS_VALIDITY_PERIOD \
48 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
49
50/**
51 * How many messages do we keep at most in the queue to the
52 * transport service before we start to drop (default,
53 * can be changed via the configuration file).
54 * Should be _below_ the level of the communicator API, as
55 * otherwise we may read messages just to have them dropped
56 * by the communicator API.
57 */
58#define DEFAULT_MAX_QUEUE_LENGTH 8
59
60/**
61 * Size of our IO buffers for ciphertext data. Must be at
62 * least UINT_MAX + sizeof (struct TCPBox).
63 */
64#define BUF_SIZE (2 * 64 * 1024 + sizeof(struct TCPBox))
65
66/**
67 * How often do we rekey based on time (at least)
68 */
69#define DEFAULT_REKEY_INTERVAL GNUNET_TIME_UNIT_DAYS
70
71/**
72 * How long do we wait until we must have received the initial KX?
73 */
74#define PROTO_QUEUE_TIMEOUT GNUNET_TIME_UNIT_MINUTES
75
76/**
77 * How often do we rekey based on number of bytes transmitted?
78 * (additionally randomized).
79 */
80#define REKEY_MAX_BYTES (1024LLU * 1024 * 1024 * 4LLU)
81
82/**
83 * Size of the initial key exchange message sent first in both
84 * directions.
85 */
86#define INITIAL_KX_SIZE \
87 (sizeof(struct GNUNET_CRYPTO_EcdhePublicKey) \
88 + sizeof(struct TCPConfirmation))
89
90/**
91 * Size of the initial core key exchange messages.
92 */
93#define INITIAL_CORE_KX_SIZE \
94 (sizeof(struct EphemeralKeyMessage) \
95 + sizeof(struct PingMessage) \
96 + sizeof(struct PongMessage))
97
98/**
99 * Address prefix used by the communicator.
100 */
101#define COMMUNICATOR_ADDRESS_PREFIX "tcp"
102
103/**
104 * Configuration section used by the communicator.
105 */
106#define COMMUNICATOR_CONFIG_SECTION "communicator-tcp"
107
108GNUNET_NETWORK_STRUCT_BEGIN
109
110
111/**
112 * Signature we use to verify that the ephemeral key was really chosen by
113 * the specified sender.
114 */
115struct TcpHandshakeSignature
116{
117 /**
118 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE
119 */
120 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
121
122 /**
123 * Identity of the inititor of the TCP connection (TCP client).
124 */
125 struct GNUNET_PeerIdentity sender;
126
127 /**
128 * Presumed identity of the target of the TCP connection (TCP server)
129 */
130 struct GNUNET_PeerIdentity receiver;
131
132 /**
133 * Ephemeral key used by the @e sender.
134 */
135 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
136
137 /**
138 * Monotonic time of @e sender, to possibly help detect replay attacks
139 * (if receiver persists times by sender).
140 */
141 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
142
143 /**
144 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
145 */
146 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
147};
148
149/**
150 * Signature we use to verify that the ack from the receiver of the ephemeral key was really send by
151 * the specified sender.
152 */
153struct TcpHandshakeAckSignature
154{
155 /**
156 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK
157 */
158 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
159
160 /**
161 * Identity of the inititor of the TCP connection (TCP client).
162 */
163 struct GNUNET_PeerIdentity sender;
164
165 /**
166 * Presumed identity of the target of the TCP connection (TCP server)
167 */
168 struct GNUNET_PeerIdentity receiver;
169
170 /**
171 * Monotonic time of @e sender, to possibly help detect replay attacks
172 * (if receiver persists times by sender).
173 */
174 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
175
176 /**
177 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
178 */
179 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
180};
181
182/**
183 * Encrypted continuation of TCP initial handshake.
184 */
185struct TCPConfirmation
186{
187 /**
188 * Sender's identity
189 */
190 struct GNUNET_PeerIdentity sender;
191
192 /**
193 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE
194 */
195 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
196
197 /**
198 * Monotonic time of @e sender, to possibly help detect replay attacks
199 * (if receiver persists times by sender).
200 */
201 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
202
203 /**
204 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
205 */
206 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
207
208};
209
210/**
211 * Ack for the encrypted continuation of TCP initial handshake.
212 */
213struct TCPConfirmationAck
214{
215
216
217 /**
218 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK.
219 */
220 struct GNUNET_MessageHeader header;
221
222 /**
223 * Sender's identity
224 */
225 struct GNUNET_PeerIdentity sender;
226
227 /**
228 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK
229 */
230 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
231
232 /**
233 * Monotonic time of @e sender, to possibly help detect replay attacks
234 * (if receiver persists times by sender).
235 */
236 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
237
238 /**
239 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
240 */
241 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
242
243};
244
245/**
246 * TCP message box. Always sent encrypted!
247 */
248struct TCPBox
249{
250 /**
251 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX. Warning: the
252 * header size EXCLUDES the size of the `struct TCPBox`. We usually
253 * never do this, but here the payload may truly be 64k *after* the
254 * TCPBox (as we have no MTU)!!
255 */
256 struct GNUNET_MessageHeader header;
257
258 /**
259 * HMAC for the following encrypted message. Yes, we MUST use
260 * mac-then-encrypt here, as we want to hide the message sizes on
261 * the wire (zero plaintext design!). Using CTR mode, padding oracle
262 * attacks do not apply. Besides, due to the use of ephemeral keys
263 * (hopefully with effective replay protection from monotonic time!)
264 * the attacker is limited in using the oracle.
265 */
266 struct GNUNET_ShortHashCode hmac;
267
268 /* followed by as may bytes of payload as indicated in @e header,
269 excluding the TCPBox itself! */
270};
271
272
273/**
274 * TCP rekey message box. Always sent encrypted! Data after
275 * this message will use the new key.
276 */
277struct TCPRekey
278{
279 /**
280 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY.
281 */
282 struct GNUNET_MessageHeader header;
283
284 /**
285 * HMAC for the following encrypted message. Yes, we MUST use
286 * mac-then-encrypt here, as we want to hide the message sizes on
287 * the wire (zero plaintext design!). Using CTR mode padding oracle
288 * attacks do not apply. Besides, due to the use of ephemeral keys
289 * (hopefully with effective replay protection from monotonic time!)
290 * the attacker is limited in using the oracle.
291 */
292 struct GNUNET_ShortHashCode hmac;
293
294 /**
295 * New ephemeral key.
296 */
297 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
298
299 /**
300 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY
301 */
302 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
303
304 /**
305 * Monotonic time of @e sender, to possibly help detect replay attacks
306 * (if receiver persists times by sender).
307 */
308 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
309};
310
311/**
312 * Signature we use to verify that the ephemeral key was really chosen by
313 * the specified sender.
314 */
315struct TcpRekeySignature
316{
317 /**
318 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY
319 */
320 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
321
322 /**
323 * Identity of the inititor of the TCP connection (TCP client).
324 */
325 struct GNUNET_PeerIdentity sender;
326
327 /**
328 * Presumed identity of the target of the TCP connection (TCP server)
329 */
330 struct GNUNET_PeerIdentity receiver;
331
332 /**
333 * Ephemeral key used by the @e sender.
334 */
335 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
336
337 /**
338 * Monotonic time of @e sender, to possibly help detect replay attacks
339 * (if receiver persists times by sender).
340 */
341 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
342};
343
344/**
345 * TCP finish. Sender asks for the connection to be closed.
346 * Needed/useful in case we drop RST/FIN packets on the GNUnet
347 * port due to the possibility of malicious RST/FIN injection.
348 */
349struct TCPFinish
350{
351 /**
352 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH.
353 */
354 struct GNUNET_MessageHeader header;
355
356 /**
357 * HMAC for the following encrypted message. Yes, we MUST use
358 * mac-then-encrypt here, as we want to hide the message sizes on
359 * the wire (zero plaintext design!). Using CTR mode padding oracle
360 * attacks do not apply. Besides, due to the use of ephemeral keys
361 * (hopefully with effective replay protection from monotonic time!)
362 * the attacker is limited in using the oracle.
363 */
364 struct GNUNET_ShortHashCode hmac;
365};
366
367
368GNUNET_NETWORK_STRUCT_END
369
370/**
371 * Struct to use as closure.
372 */
373struct ListenTask
374{
375 /**
376 * ID of listen task
377 */
378 struct GNUNET_SCHEDULER_Task *listen_task;
379
380 /**
381 * Listen socket.
382 */
383 struct GNUNET_NETWORK_Handle *listen_sock;
384};
385
386/**
387 * Handle for a queue.
388 */
389struct Queue
390{
391 /**
392 * To whom are we talking to.
393 */
394 struct GNUNET_PeerIdentity target;
395
396 /**
397 * Listen socket.
398 */
399 struct GNUNET_NETWORK_Handle *listen_sock;
400
401 /**
402 * socket that we transmit all data with on this queue
403 */
404 struct GNUNET_NETWORK_Handle *sock;
405
406 /**
407 * cipher for decryption of incoming data.
408 */
409 gcry_cipher_hd_t in_cipher;
410
411 /**
412 * cipher for encryption of outgoing data.
413 */
414 gcry_cipher_hd_t out_cipher;
415
416 /**
417 * Shared secret for HMAC verification on incoming data.
418 */
419 struct GNUNET_HashCode in_hmac;
420
421 /**
422 * Shared secret for HMAC generation on outgoing data, ratcheted after
423 * each operation.
424 */
425 struct GNUNET_HashCode out_hmac;
426
427 /**
428 * Our ephemeral key. Stored here temporarily during rekeying / key
429 * generation.
430 */
431 struct GNUNET_CRYPTO_EcdhePrivateKey ephemeral;
432
433 /**
434 * ID of read task for this connection.
435 */
436 struct GNUNET_SCHEDULER_Task *read_task;
437
438 /**
439 * ID of write task for this connection.
440 */
441 struct GNUNET_SCHEDULER_Task *write_task;
442
443 /**
444 * Address of the other peer.
445 */
446 struct sockaddr *address;
447
448 /**
449 * How many more bytes may we sent with the current @e out_cipher
450 * before we should rekey?
451 */
452 uint64_t rekey_left_bytes;
453
454 /**
455 * Until what time may we sent with the current @e out_cipher
456 * before we should rekey?
457 */
458 struct GNUNET_TIME_Absolute rekey_time;
459
460 /**
461 * Length of the address.
462 */
463 socklen_t address_len;
464
465 /**
466 * Message queue we are providing for the #ch.
467 */
468 struct GNUNET_MQ_Handle *mq;
469
470 /**
471 * handle for this queue with the #ch.
472 */
473 struct GNUNET_TRANSPORT_QueueHandle *qh;
474
475 /**
476 * Number of bytes we currently have in our write queue.
477 */
478 unsigned long long bytes_in_queue;
479
480 /**
481 * Buffer for reading ciphertext from network into.
482 */
483 char cread_buf[BUF_SIZE];
484
485 /**
486 * buffer for writing ciphertext to network.
487 */
488 char cwrite_buf[BUF_SIZE];
489
490 /**
491 * Plaintext buffer for decrypted plaintext.
492 */
493 char pread_buf[UINT16_MAX + 1 + sizeof(struct TCPBox)];
494
495 /**
496 * Plaintext buffer for messages to be encrypted.
497 */
498 char pwrite_buf[UINT16_MAX + 1 + sizeof(struct TCPBox)];
499
500 /**
501 * At which offset in the ciphertext read buffer should we
502 * append more ciphertext for transmission next?
503 */
504 size_t cread_off;
505
506 /**
507 * At which offset in the ciphertext write buffer should we
508 * append more ciphertext from reading next?
509 */
510 size_t cwrite_off;
511
512 /**
513 * At which offset in the plaintext input buffer should we
514 * append more plaintext from decryption next?
515 */
516 size_t pread_off;
517
518 /**
519 * At which offset in the plaintext output buffer should we
520 * append more plaintext for encryption next?
521 */
522 size_t pwrite_off;
523
524 /**
525 * Timeout for this queue.
526 */
527 struct GNUNET_TIME_Absolute timeout;
528
529 /**
530 * How may messages did we pass from this queue to CORE for which we
531 * have yet to receive an acknoweldgement that CORE is done with
532 * them? If "large" (or even just non-zero), we should throttle
533 * reading to provide flow control. See also #DEFAULT_MAX_QUEUE_LENGTH
534 * and #max_queue_length.
535 */
536 unsigned int backpressure;
537
538 /**
539 * Which network type does this queue use?
540 */
541 enum GNUNET_NetworkType nt;
542
543 /**
544 * The connection status of this queue.
545 */
546 enum GNUNET_TRANSPORT_ConnectionStatus cs;
547
548 /**
549 * Is MQ awaiting a #GNUNET_MQ_impl_send_continue() call?
550 */
551 int mq_awaits_continue;
552
553 /**
554 * Did we enqueue a finish message and are closing down the queue?
555 */
556 int finishing;
557
558 /**
559 * Did we technically destroy this queue, but kept the allocation
560 * around because of @e backpressure not being zero yet? Used
561 * simply to delay the final #GNUNET_free() operation until
562 * #core_read_finished_cb() has been called.
563 */
564 int destroyed;
565
566 /**
567 * #GNUNET_YES if we just rekeyed and must thus possibly
568 * re-decrypt ciphertext.
569 */
570 int rekeyed;
571
572 /**
573 * Monotonic time value for rekey message.
574 */
575 struct GNUNET_TIME_AbsoluteNBO rekey_monotonic_time;
576
577 /**
578 * Monotonic time value for handshake message.
579 */
580 struct GNUNET_TIME_AbsoluteNBO handshake_monotonic_time;
581
582 /**
583 * Monotonic time value for handshake ack message.
584 */
585 struct GNUNET_TIME_AbsoluteNBO handshake_ack_monotonic_time;
586
587 /**
588 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
589 */
590 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
591
592 /**
593 * Challenge value received. In case of inbound connection we have to remember the value, because we send the challenge back later after we received the GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK.
594 */
595 struct GNUNET_CRYPTO_ChallengeNonceP challenge_received;
596
597 /**
598 * Iteration Context for retrieving the monotonic time send with key for rekeying.
599 */
600 struct GNUNET_PEERSTORE_IterateContext *rekey_monotime_get;
601
602 /**
603 * Iteration Context for retrieving the monotonic time send with the handshake.
604 */
605 struct GNUNET_PEERSTORE_IterateContext *handshake_monotime_get;
606
607 /**
608 * Iteration Context for retrieving the monotonic time send with the handshake ack.
609 */
610 struct GNUNET_PEERSTORE_IterateContext *handshake_ack_monotime_get;
611
612 /**
613 * Store Context for retrieving the monotonic time send with key for rekeying.
614 */
615 struct GNUNET_PEERSTORE_StoreContext *rekey_monotime_sc;
616
617 /**
618 * Store Context for retrieving the monotonic time send with the handshake.
619 */
620 struct GNUNET_PEERSTORE_StoreContext *handshake_monotime_sc;
621
622 /**
623 * Store Context for retrieving the monotonic time send with the handshake ack.
624 */
625 struct GNUNET_PEERSTORE_StoreContext *handshake_ack_monotime_sc;
626};
627
628
629/**
630 * Handle for an incoming connection where we do not yet have enough
631 * information to setup a full queue.
632 */
633struct ProtoQueue
634{
635 /**
636 * Kept in a DLL.
637 */
638 struct ProtoQueue *next;
639
640 /**
641 * Kept in a DLL.
642 */
643 struct ProtoQueue *prev;
644
645 /**
646 * Listen socket.
647 */
648 struct GNUNET_NETWORK_Handle *listen_sock;
649
650 /**
651 * socket that we transmit all data with on this queue
652 */
653 struct GNUNET_NETWORK_Handle *sock;
654
655 /**
656 * ID of read task for this connection.
657 */
658 struct GNUNET_SCHEDULER_Task *read_task;
659
660 /**
661 * Address of the other peer.
662 */
663 struct sockaddr *address;
664
665 /**
666 * Length of the address.
667 */
668 socklen_t address_len;
669
670 /**
671 * Timeout for this protoqueue.
672 */
673 struct GNUNET_TIME_Absolute timeout;
674
675 /**
676 * Buffer for reading all the information we need to upgrade from
677 * protoqueue to queue.
678 */
679 char ibuf[INITIAL_KX_SIZE];
680
681 /**
682 * Current offset for reading into @e ibuf.
683 */
684 size_t ibuf_off;
685};
686
687/**
688 * In case of port only configuration we like to bind to ipv4 and ipv6 addresses.
689 */
690struct PortOnlyIpv4Ipv6
691{
692 /**
693 * Ipv4 address we like to bind to.
694 */
695 struct sockaddr *addr_ipv4;
696
697 /**
698 * Length of ipv4 address.
699 */
700 socklen_t addr_len_ipv4;
701
702 /**
703 * Ipv6 address we like to bind to.
704 */
705 struct sockaddr *addr_ipv6;
706
707 /**
708 * Length of ipv6 address.
709 */
710 socklen_t addr_len_ipv6;
711
712};
713
714/**
715 * DLL to store the addresses we like to register at NAT service.
716 */
717struct Addresses
718{
719 /**
720 * Kept in a DLL.
721 */
722 struct Addresses *next;
723
724 /**
725 * Kept in a DLL.
726 */
727 struct Addresses *prev;
728
729 /**
730 * Address we like to register at NAT service.
731 */
732 struct sockaddr *addr;
733
734 /**
735 * Length of address we like to register at NAT service.
736 */
737 socklen_t addr_len;
738
739};
740
741
742/**
743 * Maximum queue length before we stop reading towards the transport service.
744 */
745static unsigned long long max_queue_length;
746
747/**
748 * For logging statistics.
749 */
750static struct GNUNET_STATISTICS_Handle *stats;
751
752/**
753 * Our environment.
754 */
755static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
756
757/**
758 * Queues (map from peer identity to `struct Queue`)
759 */
760static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
761
762/**
763 * ListenTasks (map from socket to `struct ListenTask`)
764 */
765static struct GNUNET_CONTAINER_MultiHashMap *lt_map;
766
767/**
768 * Our public key.
769 */
770static struct GNUNET_PeerIdentity my_identity;
771
772/**
773 * The rekey interval
774 */
775static struct GNUNET_TIME_Relative rekey_interval;
776
777/**
778 * Our private key.
779 */
780static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
781
782/**
783 * Our configuration.
784 */
785static const struct GNUNET_CONFIGURATION_Handle *cfg;
786
787/**
788 * Network scanner to determine network types.
789 */
790static struct GNUNET_NT_InterfaceScanner *is;
791
792/**
793 * Connection to NAT service.
794 */
795static struct GNUNET_NAT_Handle *nat;
796
797/**
798 * Protoqueues DLL head.
799 */
800static struct ProtoQueue *proto_head;
801
802/**
803 * Protoqueues DLL tail.
804 */
805static struct ProtoQueue *proto_tail;
806
807/**
808 * Handle for DNS lookup of bindto address
809 */
810struct GNUNET_RESOLVER_RequestHandle *resolve_request_handle;
811
812/**
813 * Head of DLL with addresses we like to register at NAT servcie.
814 */
815struct Addresses *addrs_head;
816
817/**
818 * Head of DLL with addresses we like to register at NAT servcie.
819 */
820struct Addresses *addrs_tail;
821
822/**
823 * Head of DLL with ListenTasks.
824 */
825struct ListenTask *lts_head;
826
827/**
828 * Head of DLL with ListenTask.
829 */
830struct ListenTask *lts_tail;
831
832/**
833 * Number of addresses in the DLL for register at NAT service.
834 */
835int addrs_lens;
836
837/**
838 * Size of data received without KX challenge played back.
839 */
840// TODO remove?
841size_t unverified_size;
842
843/**
844 * Database for peer's HELLOs.
845 */
846static struct GNUNET_PEERSTORE_Handle *peerstore;
847
848/**
849 * A flag indicating we are already doing a shutdown.
850 */
851int shutdown_running = GNUNET_NO;
852
853/**
854 * The port the communicator should be assigned to.
855 */
856unsigned int bind_port;
857
858/**
859 * We have been notified that our listen socket has something to
860 * read. Do the read and reschedule this function to be called again
861 * once more is available.
862 *
863 * @param cls NULL
864 */
865static void
866listen_cb (void *cls);
867
868/**
869 * Functions with this signature are called whenever we need
870 * to close a queue due to a disconnect or failure to
871 * establish a connection.
872 *
873 * @param queue queue to close down
874 */
875static void
876queue_destroy (struct Queue *queue)
877{
878 struct ListenTask *lt = NULL;
879 struct GNUNET_HashCode h_sock;
880 int sockfd;
881
882 if (NULL != queue->listen_sock)
883 {
884 sockfd = GNUNET_NETWORK_get_fd (queue->listen_sock);
885 GNUNET_CRYPTO_hash (&sockfd,
886 sizeof(int),
887 &h_sock);
888
889 lt = GNUNET_CONTAINER_multihashmap_get (lt_map, &h_sock);
890 }
891
892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
893 "Disconnecting queue for peer `%s'\n",
894 GNUNET_i2s (&queue->target));
895 if (NULL != queue->rekey_monotime_sc)
896 {
897 GNUNET_PEERSTORE_store_cancel (queue->rekey_monotime_sc);
898 queue->rekey_monotime_sc = NULL;
899 }
900 if (NULL != queue->handshake_monotime_sc)
901 {
902 GNUNET_PEERSTORE_store_cancel (queue->handshake_monotime_sc);
903 queue->handshake_monotime_sc = NULL;
904 }
905 if (NULL != queue->handshake_ack_monotime_sc)
906 {
907 GNUNET_PEERSTORE_store_cancel (queue->handshake_ack_monotime_sc);
908 queue->handshake_ack_monotime_sc = NULL;
909 }
910 if (NULL != queue->rekey_monotime_get)
911 {
912 GNUNET_PEERSTORE_iterate_cancel (queue->rekey_monotime_get);
913 queue->rekey_monotime_get = NULL;
914 }
915 if (NULL != queue->handshake_monotime_get)
916 {
917 GNUNET_PEERSTORE_iterate_cancel (queue->handshake_monotime_get);
918 queue->handshake_monotime_get = NULL;
919 }
920 if (NULL != queue->handshake_ack_monotime_get)
921 {
922 GNUNET_PEERSTORE_iterate_cancel (queue->handshake_ack_monotime_get);
923 queue->handshake_ack_monotime_get = NULL;
924 }
925 if (NULL != queue->qh)
926 {
927 GNUNET_TRANSPORT_communicator_mq_del (queue->qh);
928 queue->qh = NULL;
929 }
930 GNUNET_assert (
931 GNUNET_YES ==
932 GNUNET_CONTAINER_multipeermap_remove (queue_map, &queue->target, queue));
933 GNUNET_STATISTICS_set (stats,
934 "# queues active",
935 GNUNET_CONTAINER_multipeermap_size (queue_map),
936 GNUNET_NO);
937 if (NULL != queue->read_task)
938 {
939 GNUNET_SCHEDULER_cancel (queue->read_task);
940 queue->read_task = NULL;
941 }
942 if (NULL != queue->write_task)
943 {
944 GNUNET_SCHEDULER_cancel (queue->write_task);
945 queue->write_task = NULL;
946 }
947 if (GNUNET_SYSERR == GNUNET_NETWORK_socket_close (queue->sock))
948 {
949 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
950 "closing socket failed\n");
951 }
952 gcry_cipher_close (queue->in_cipher);
953 gcry_cipher_close (queue->out_cipher);
954 GNUNET_free (queue->address);
955 if (0 != queue->backpressure)
956 queue->destroyed = GNUNET_YES;
957 else
958 GNUNET_free (queue);
959
960 if (NULL == lt)
961 return;
962
963 if ((! shutdown_running) && (NULL == lt->listen_task))
964 {
965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
966 "add read net listen\n");
967 lt->listen_task = GNUNET_SCHEDULER_add_read_net (
968 GNUNET_TIME_UNIT_FOREVER_REL,
969 lt->listen_sock,
970 &listen_cb,
971 lt);
972 }
973 else
974 GNUNET_free (lt);
975}
976
977
978/**
979 * Compute @a mac over @a buf, and ratched the @a hmac_secret.
980 *
981 * @param[in,out] hmac_secret secret for HMAC calculation
982 * @param buf buffer to MAC
983 * @param buf_size number of bytes in @a buf
984 * @param smac[out] where to write the HMAC
985 */
986static void
987calculate_hmac (struct GNUNET_HashCode *hmac_secret,
988 const void *buf,
989 size_t buf_size,
990 struct GNUNET_ShortHashCode *smac)
991{
992 struct GNUNET_HashCode mac;
993
994 GNUNET_CRYPTO_hmac_raw (hmac_secret,
995 sizeof(struct GNUNET_HashCode),
996 buf,
997 buf_size,
998 &mac);
999 /* truncate to `struct GNUNET_ShortHashCode` */
1000 memcpy (smac, &mac, sizeof(struct GNUNET_ShortHashCode));
1001 /* ratchet hmac key */
1002 GNUNET_CRYPTO_hash (hmac_secret,
1003 sizeof(struct GNUNET_HashCode),
1004 hmac_secret);
1005}
1006
1007
1008/**
1009 * Append a 'finish' message to the outgoing transmission. Once the
1010 * finish has been transmitted, destroy the queue.
1011 *
1012 * @param queue queue to shut down nicely
1013 */
1014static void
1015queue_finish (struct Queue *queue)
1016{
1017 struct TCPFinish fin;
1018
1019 memset (&fin, 0, sizeof(fin));
1020 fin.header.size = htons (sizeof(fin));
1021 fin.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH);
1022 calculate_hmac (&queue->out_hmac, &fin, sizeof(fin), &fin.hmac);
1023 /* if there is any message left in pwrite_buf, we
1024 overwrite it (possibly dropping the last message
1025 from CORE hard here) */
1026 memcpy (queue->pwrite_buf, &fin, sizeof(fin));
1027 queue->pwrite_off = sizeof(fin);
1028 /* This flag will ensure that #queue_write() no longer
1029 notifies CORE about the possibility of sending
1030 more data, and that #queue_write() will call
1031 #queue_destroy() once the @c fin was fully written. */
1032 queue->finishing = GNUNET_YES;
1033}
1034
1035
1036/**
1037 * Increment queue timeout due to activity. We do not immediately
1038 * notify the monitor here as that might generate excessive
1039 * signalling.
1040 *
1041 * @param queue queue for which the timeout should be rescheduled
1042 */
1043static void
1044reschedule_queue_timeout (struct Queue *queue)
1045{
1046 queue->timeout =
1047 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1048}
1049
1050
1051/**
1052 * Queue read task. If we hit the timeout, disconnect it
1053 *
1054 * @param cls the `struct Queue *` to disconnect
1055 */
1056static void
1057queue_read (void *cls);
1058
1059
1060/**
1061 * Core tells us it is done processing a message that transport
1062 * received on a queue with status @a success.
1063 *
1064 * @param cls a `struct Queue *` where the message originally came from
1065 * @param success #GNUNET_OK on success
1066 */
1067static void
1068core_read_finished_cb (void *cls, int success)
1069{
1070 struct Queue *queue = cls;
1071 if (GNUNET_OK != success)
1072 GNUNET_STATISTICS_update (stats,
1073 "# messages lost in communicator API towards CORE",
1074 1,
1075 GNUNET_NO);
1076 if (NULL == queue)
1077 return;
1078
1079 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1080 "backpressure %u\n",
1081 queue->backpressure);
1082
1083 queue->backpressure--;
1084 /* handle deferred queue destruction */
1085 if ((queue->destroyed) && (0 == queue->backpressure))
1086 {
1087 GNUNET_free (queue);
1088 return;
1089 }
1090 else if (GNUNET_YES != queue->destroyed)
1091 {
1092 reschedule_queue_timeout (queue);
1093 /* possibly unchoke reading, now that CORE made progress */
1094 if (NULL == queue->read_task)
1095 queue->read_task =
1096 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining (
1097 queue->timeout),
1098 queue->sock,
1099 &queue_read,
1100 queue);
1101 }
1102}
1103
1104
1105/**
1106 * We received @a plaintext_len bytes of @a plaintext on @a queue.
1107 * Pass it on to CORE. If transmission is actually happening,
1108 * increase backpressure counter.
1109 *
1110 * @param queue the queue that received the plaintext
1111 * @param plaintext the plaintext that was received
1112 * @param plaintext_len number of bytes of plaintext received
1113 */
1114static void
1115pass_plaintext_to_core (struct Queue *queue,
1116 const void *plaintext,
1117 size_t plaintext_len)
1118{
1119 const struct GNUNET_MessageHeader *hdr = plaintext;
1120 int ret;
1121
1122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1123 "pass message from %s to core\n",
1124 GNUNET_i2s (&queue->target));
1125
1126 if (ntohs (hdr->size) != plaintext_len)
1127 {
1128 /* NOTE: If we ever allow multiple CORE messages in one
1129 BOX, this will have to change! */
1130 GNUNET_break (0);
1131 return;
1132 }
1133 ret = GNUNET_TRANSPORT_communicator_receive (ch,
1134 &queue->target,
1135 hdr,
1136 ADDRESS_VALIDITY_PERIOD,
1137 &core_read_finished_cb,
1138 queue);
1139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1140 "passed to core\n");
1141 if (GNUNET_OK == ret)
1142 queue->backpressure++;
1143 GNUNET_break (GNUNET_NO != ret); /* backpressure not working!? */
1144 if (GNUNET_SYSERR == ret)
1145 GNUNET_STATISTICS_update (stats,
1146 "# bytes lost due to CORE not running",
1147 plaintext_len,
1148 GNUNET_NO);
1149}
1150
1151
1152/**
1153 * Setup @a cipher based on shared secret @a dh and decrypting
1154 * peer @a pid.
1155 *
1156 * @param dh shared secret
1157 * @param pid decrypting peer's identity
1158 * @param cipher[out] cipher to initialize
1159 * @param hmac_key[out] HMAC key to initialize
1160 */
1161static void
1162setup_cipher (const struct GNUNET_HashCode *dh,
1163 const struct GNUNET_PeerIdentity *pid,
1164 gcry_cipher_hd_t *cipher,
1165 struct GNUNET_HashCode *hmac_key)
1166{
1167 char key[256 / 8];
1168 char ctr[128 / 8];
1169
1170 GNUNET_assert (0 == gcry_cipher_open (cipher,
1171 GCRY_CIPHER_AES256 /* low level: go for speed */,
1172 GCRY_CIPHER_MODE_CTR,
1173 0 /* flags */));
1174 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (key,
1175 sizeof(key),
1176 "TCP-key",
1177 strlen ("TCP-key"),
1178 dh,
1179 sizeof(*dh),
1180 pid,
1181 sizeof(*pid),
1182 NULL,
1183 0));
1184 GNUNET_assert (0 == gcry_cipher_setkey (*cipher, key, sizeof(key)));
1185 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (ctr,
1186 sizeof(ctr),
1187 "TCP-ctr",
1188 strlen ("TCP-ctr"),
1189 dh,
1190 sizeof(*dh),
1191 pid,
1192 sizeof(*pid),
1193 NULL,
1194 0));
1195 gcry_cipher_setctr (*cipher, ctr, sizeof(ctr));
1196 GNUNET_assert (GNUNET_YES ==
1197 GNUNET_CRYPTO_kdf (hmac_key,
1198 sizeof(struct GNUNET_HashCode),
1199 "TCP-hmac",
1200 strlen ("TCP-hmac"),
1201 dh,
1202 sizeof(*dh),
1203 pid,
1204 sizeof(*pid),
1205 NULL,
1206 0));
1207}
1208
1209
1210/**
1211 * Callback called when peerstore store operation for rekey monotime value is finished.
1212 * @param cls Queue context the store operation was executed.
1213 * @param success Store operation was successful (GNUNET_OK) or not.
1214 */
1215static void
1216rekey_monotime_store_cb (void *cls, int success)
1217{
1218 struct Queue *queue = cls;
1219 if (GNUNET_OK != success)
1220 {
1221 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1222 "Failed to store rekey monotonic time in PEERSTORE!\n");
1223 }
1224 queue->rekey_monotime_sc = NULL;
1225}
1226
1227
1228/**
1229 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY
1230 * where found.
1231 * @param cls Queue context the store operation was executed.
1232 * @param record The record found or NULL if there is no record left.
1233 * @param emsg Message from peerstore.
1234 */
1235static void
1236rekey_monotime_cb (void *cls,
1237 const struct GNUNET_PEERSTORE_Record *record,
1238 const char *emsg)
1239{
1240 struct Queue *queue = cls;
1241 struct GNUNET_TIME_AbsoluteNBO *mtbe;
1242 struct GNUNET_TIME_Absolute mt;
1243 const struct GNUNET_PeerIdentity *pid;
1244 struct GNUNET_TIME_AbsoluteNBO *rekey_monotonic_time;
1245
1246 (void) emsg;
1247
1248 rekey_monotonic_time = &queue->rekey_monotonic_time;
1249 pid = &queue->target;
1250 if (NULL == record)
1251 {
1252 queue->rekey_monotime_get = NULL;
1253 return;
1254 }
1255 if (sizeof(*mtbe) != record->value_size)
1256 {
1257 GNUNET_break (0);
1258 return;
1259 }
1260 mtbe = record->value;
1261 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
1262 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
1263 queue->rekey_monotonic_time).abs_value_us)
1264 {
1265 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1266 "Queue from %s dropped, rekey monotime in the past\n",
1267 GNUNET_i2s (&queue->target));
1268 GNUNET_break (0);
1269 queue_finish (queue);
1270 return;
1271 }
1272 queue->rekey_monotime_sc = GNUNET_PEERSTORE_store (peerstore,
1273 "transport_tcp_communicator",
1274 pid,
1275 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY,
1276 rekey_monotonic_time,
1277 sizeof(*
1278 rekey_monotonic_time),
1279 GNUNET_TIME_UNIT_FOREVER_ABS,
1280 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
1281 &rekey_monotime_store_cb,
1282 queue);
1283}
1284
1285
1286/**
1287 * Setup cipher of @a queue for decryption.
1288 *
1289 * @param ephemeral ephemeral key we received from the other peer
1290 * @param queue[in,out] queue to initialize decryption cipher for
1291 */
1292static void
1293setup_in_cipher (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
1294 struct Queue *queue)
1295{
1296 struct GNUNET_HashCode dh;
1297
1298 GNUNET_CRYPTO_eddsa_ecdh (my_private_key, ephemeral, &dh);
1299 setup_cipher (&dh, &my_identity, &queue->in_cipher, &queue->in_hmac);
1300}
1301
1302
1303/**
1304 * Handle @a rekey message on @a queue. The message was already
1305 * HMAC'ed, but we should additionally still check the signature.
1306 * Then we need to stop the old cipher and start afresh.
1307 *
1308 * @param queue the queue @a rekey was received on
1309 * @param rekey the rekey message
1310 */
1311static void
1312do_rekey (struct Queue *queue, const struct TCPRekey *rekey)
1313{
1314 struct TcpRekeySignature thp;
1315
1316 thp.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY);
1317 thp.purpose.size = htonl (sizeof(thp));
1318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1319 "do_rekey size %u\n",
1320 thp.purpose.size);
1321 thp.sender = queue->target;
1322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1323 "sender %s\n",
1324 GNUNET_p2s (&thp.sender.public_key));
1325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326 "sender %s\n",
1327 GNUNET_p2s (&queue->target.public_key));
1328 thp.receiver = my_identity;
1329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1330 "receiver %s\n",
1331 GNUNET_p2s (&thp.receiver.public_key));
1332 thp.ephemeral = rekey->ephemeral;
1333 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1334 "ephemeral %s\n",
1335 GNUNET_e2s (&thp.ephemeral));
1336 thp.monotonic_time = rekey->monotonic_time;
1337 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1338 "time %s\n",
1339 GNUNET_STRINGS_absolute_time_to_string (
1340 GNUNET_TIME_absolute_ntoh (thp.monotonic_time)));
1341 GNUNET_assert (ntohl ((&thp)->purpose.size) == sizeof (*(&thp)));
1342 if (GNUNET_OK !=
1343 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY,
1344 &thp,
1345 &rekey->sender_sig,
1346 &queue->target.public_key))
1347 {
1348 GNUNET_break (0);
1349 queue_finish (queue);
1350 return;
1351 }
1352 queue->rekey_monotonic_time = rekey->monotonic_time;
1353 queue->rekey_monotime_get = GNUNET_PEERSTORE_iterate (peerstore,
1354 "transport_tcp_communicator",
1355 &queue->target,
1356 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY,
1357 &rekey_monotime_cb,
1358 queue);
1359 gcry_cipher_close (queue->in_cipher);
1360 queue->rekeyed = GNUNET_YES;
1361 setup_in_cipher (&rekey->ephemeral, queue);
1362}
1363
1364
1365/**
1366 * Callback called when peerstore store operation for handshake ack monotime value is finished.
1367 * @param cls Queue context the store operation was executed.
1368 * @param success Store operation was successful (GNUNET_OK) or not.
1369 */
1370static void
1371handshake_ack_monotime_store_cb (void *cls, int success)
1372{
1373 struct Queue *queue = cls;
1374
1375 if (GNUNET_OK != success)
1376 {
1377 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1378 "Failed to store handshake ack monotonic time in PEERSTORE!\n");
1379 }
1380 queue->handshake_ack_monotime_sc = NULL;
1381}
1382
1383
1384/**
1385 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK
1386 * where found.
1387 * @param cls Queue context the store operation was executed.
1388 * @param record The record found or NULL if there is no record left.
1389 * @param emsg Message from peerstore.
1390 */
1391static void
1392handshake_ack_monotime_cb (void *cls,
1393 const struct GNUNET_PEERSTORE_Record *record,
1394 const char *emsg)
1395{
1396 struct Queue *queue = cls;
1397 struct GNUNET_TIME_AbsoluteNBO *mtbe;
1398 struct GNUNET_TIME_Absolute mt;
1399 const struct GNUNET_PeerIdentity *pid;
1400 struct GNUNET_TIME_AbsoluteNBO *handshake_ack_monotonic_time;
1401
1402 (void) emsg;
1403
1404 handshake_ack_monotonic_time = &queue->handshake_ack_monotonic_time;
1405 pid = &queue->target;
1406 if (NULL == record)
1407 {
1408 queue->handshake_ack_monotime_get = NULL;
1409 return;
1410 }
1411 if (sizeof(*mtbe) != record->value_size)
1412 {
1413 GNUNET_break (0);
1414 return;
1415 }
1416 mtbe = record->value;
1417 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
1418 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
1419 queue->handshake_ack_monotonic_time).abs_value_us)
1420 {
1421 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1422 "Queue from %s dropped, handshake ack monotime in the past\n",
1423 GNUNET_i2s (&queue->target));
1424 GNUNET_break (0);
1425 queue_finish (queue);
1426 return;
1427 }
1428 queue->handshake_ack_monotime_sc =
1429 GNUNET_PEERSTORE_store (peerstore,
1430 "transport_tcp_communicator",
1431 pid,
1432 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK,
1433 handshake_ack_monotonic_time,
1434 sizeof(*handshake_ack_monotonic_time),
1435 GNUNET_TIME_UNIT_FOREVER_ABS,
1436 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
1437 &
1438 handshake_ack_monotime_store_cb,
1439 queue);
1440}
1441
1442
1443/**
1444 * Sending challenge with TcpConfirmationAck back to sender of ephemeral key.
1445 *
1446 * @param tc The TCPConfirmation originally send.
1447 * @param queue The queue context.
1448 */
1449static void
1450send_challenge (struct GNUNET_CRYPTO_ChallengeNonceP challenge, struct Queue *queue)
1451{
1452 struct TCPConfirmationAck tca;
1453 struct TcpHandshakeAckSignature thas;
1454
1455 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1456 "transport",
1457 "sending challenge\n");
1458
1459 tca.header.type = ntohs (
1460 GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK);
1461 tca.header.size = ntohs (sizeof(tca));
1462 tca.challenge = challenge;
1463 tca.sender = my_identity;
1464 tca.monotonic_time =
1465 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
1466 thas.purpose.purpose = htonl (
1467 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK);
1468 thas.purpose.size = htonl (sizeof(thas));
1469 thas.sender = my_identity;
1470 thas.receiver = queue->target;
1471 thas.monotonic_time = tca.monotonic_time;
1472 thas.challenge = tca.challenge;
1473 GNUNET_CRYPTO_eddsa_sign (my_private_key,
1474 &thas,
1475 &tca.sender_sig);
1476 GNUNET_assert (0 ==
1477 gcry_cipher_encrypt (queue->out_cipher,
1478 &queue->cwrite_buf[queue->cwrite_off],
1479 sizeof(tca),
1480 &tca,
1481 sizeof(tca)));
1482 queue->cwrite_off += sizeof(tca);
1483 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1484 "transport",
1485 "sending challenge done\n");
1486}
1487
1488
1489/**
1490 * Setup cipher for outgoing data stream based on target and
1491 * our ephemeral private key.
1492 *
1493 * @param queue queue to setup outgoing (encryption) cipher for
1494 */
1495static void
1496setup_out_cipher (struct Queue *queue)
1497{
1498 struct GNUNET_HashCode dh;
1499
1500 GNUNET_CRYPTO_ecdh_eddsa (&queue->ephemeral, &queue->target.public_key, &dh);
1501 /* we don't need the private key anymore, drop it! */
1502 memset (&queue->ephemeral, 0, sizeof(queue->ephemeral));
1503 setup_cipher (&dh, &queue->target, &queue->out_cipher, &queue->out_hmac);
1504 queue->rekey_time = GNUNET_TIME_relative_to_absolute (rekey_interval);
1505 queue->rekey_left_bytes =
1506 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, REKEY_MAX_BYTES);
1507}
1508
1509
1510/**
1511 * Inject a `struct TCPRekey` message into the queue's plaintext
1512 * buffer.
1513 *
1514 * @param queue queue to perform rekeying on
1515 */
1516static void
1517inject_rekey (struct Queue *queue)
1518{
1519 struct TCPRekey rekey;
1520 struct TcpRekeySignature thp;
1521
1522 GNUNET_assert (0 == queue->pwrite_off);
1523 memset (&rekey, 0, sizeof(rekey));
1524 GNUNET_CRYPTO_ecdhe_key_create (&queue->ephemeral);
1525 rekey.header.type = ntohs (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY);
1526 rekey.header.size = ntohs (sizeof(rekey));
1527 GNUNET_CRYPTO_ecdhe_key_get_public (&queue->ephemeral, &rekey.ephemeral);
1528 rekey.monotonic_time =
1529 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
1530 thp.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY);
1531 thp.purpose.size = htonl (sizeof(thp));
1532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1533 "inject_rekey size %u\n",
1534 thp.purpose.size);
1535 thp.sender = my_identity;
1536 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1537 "sender %s\n",
1538 GNUNET_p2s (&thp.sender.public_key));
1539 thp.receiver = queue->target;
1540 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1541 "receiver %s\n",
1542 GNUNET_p2s (&thp.receiver.public_key));
1543 thp.ephemeral = rekey.ephemeral;
1544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1545 "ephemeral %s\n",
1546 GNUNET_e2s (&thp.ephemeral));
1547 thp.monotonic_time = rekey.monotonic_time;
1548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1549 "time %s\n",
1550 GNUNET_STRINGS_absolute_time_to_string (
1551 GNUNET_TIME_absolute_ntoh (thp.monotonic_time)));
1552 GNUNET_CRYPTO_eddsa_sign (my_private_key,
1553 &thp,
1554 &rekey.sender_sig);
1555 calculate_hmac (&queue->out_hmac, &rekey, sizeof(rekey), &rekey.hmac);
1556 /* Encrypt rekey message with 'old' cipher */
1557 GNUNET_assert (0 ==
1558 gcry_cipher_encrypt (queue->out_cipher,
1559 &queue->cwrite_buf[queue->cwrite_off],
1560 sizeof(rekey),
1561 &rekey,
1562 sizeof(rekey)));
1563 queue->cwrite_off += sizeof(rekey);
1564 /* Setup new cipher for successive messages */
1565 gcry_cipher_close (queue->out_cipher);
1566 setup_out_cipher (queue);
1567}
1568
1569
1570/**
1571 * We have been notified that our socket is ready to write.
1572 * Then reschedule this function to be called again once more is available.
1573 *
1574 * @param cls a `struct Queue`
1575 */
1576static void
1577queue_write (void *cls)
1578{
1579 struct Queue *queue = cls;
1580 ssize_t sent;
1581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "In queue write\n");
1582 queue->write_task = NULL;
1583 if (0 != queue->cwrite_off)
1584 {
1585 sent = GNUNET_NETWORK_socket_send (queue->sock,
1586 queue->cwrite_buf,
1587 queue->cwrite_off);
1588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1589 "Sent %lu bytes to TCP queue\n", sent);
1590 if ((-1 == sent) && (EAGAIN != errno) && (EINTR != errno))
1591 {
1592 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
1593 queue_destroy (queue);
1594 return;
1595 }
1596 if (sent > 0)
1597 {
1598 size_t usent = (size_t) sent;
1599 queue->cwrite_off -= usent;
1600 memmove (queue->cwrite_buf,
1601 &queue->cwrite_buf[usent],
1602 queue->cwrite_off);
1603 reschedule_queue_timeout (queue);
1604 }
1605 }
1606 /* can we encrypt more? (always encrypt full messages, needed
1607 such that #mq_cancel() can work!) */
1608 if ((0 < queue->rekey_left_bytes) &&
1609 (queue->pwrite_off > 0) &&
1610 (queue->cwrite_off + queue->pwrite_off <= BUF_SIZE))
1611 {
1612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1613 "Encrypting %lu bytes\n", queue->pwrite_off);
1614 GNUNET_assert (0 ==
1615 gcry_cipher_encrypt (queue->out_cipher,
1616 &queue->cwrite_buf[queue->cwrite_off],
1617 queue->pwrite_off,
1618 queue->pwrite_buf,
1619 queue->pwrite_off));
1620 if (queue->rekey_left_bytes > queue->pwrite_off)
1621 queue->rekey_left_bytes -= queue->pwrite_off;
1622 else
1623 queue->rekey_left_bytes = 0;
1624 queue->cwrite_off += queue->pwrite_off;
1625 queue->pwrite_off = 0;
1626 }
1627 // if ((-1 != unverified_size)&& ((0 == queue->pwrite_off) &&
1628 if (((0 == queue->pwrite_off) &&
1629 ((0 == queue->rekey_left_bytes) ||
1630 (0 ==
1631 GNUNET_TIME_absolute_get_remaining (
1632 queue->rekey_time).rel_value_us))))
1633 {
1634 inject_rekey (queue);
1635 }
1636 if ((0 == queue->pwrite_off) && (! queue->finishing) &&
1637 (GNUNET_YES == queue->mq_awaits_continue))
1638 {
1639 queue->mq_awaits_continue = GNUNET_NO;
1640 GNUNET_MQ_impl_send_continue (queue->mq);
1641 }
1642 /* did we just finish writing 'finish'? */
1643 if ((0 == queue->cwrite_off) && (GNUNET_YES == queue->finishing))
1644 {
1645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1646 "Finishing queue\n");
1647 queue_destroy (queue);
1648 return;
1649 }
1650 /* do we care to write more? */
1651 if ((0 < queue->cwrite_off) || (0 < queue->pwrite_off))
1652 queue->write_task =
1653 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1654 queue->sock,
1655 &queue_write,
1656 queue);
1657}
1658
1659
1660/**
1661 * Test if we have received a full message in plaintext.
1662 * If so, handle it.
1663 *
1664 * @param queue queue to process inbound plaintext for
1665 * @return number of bytes of plaintext handled, 0 for none
1666 */
1667static size_t
1668try_handle_plaintext (struct Queue *queue)
1669{
1670 const struct GNUNET_MessageHeader *hdr =
1671 (const struct GNUNET_MessageHeader *) queue->pread_buf;
1672 const struct TCPConfirmationAck *tca = (const struct
1673 TCPConfirmationAck *) queue->pread_buf;
1674 const struct TCPBox *box = (const struct TCPBox *) queue->pread_buf;
1675 const struct TCPRekey *rekey = (const struct TCPRekey *) queue->pread_buf;
1676 const struct TCPFinish *fin = (const struct TCPFinish *) queue->pread_buf;
1677 struct TCPRekey rekeyz;
1678 struct TCPFinish finz;
1679 struct GNUNET_ShortHashCode tmac;
1680 uint16_t type;
1681 size_t size = 0; /* make compiler happy */
1682 struct TcpHandshakeAckSignature thas;
1683 const struct GNUNET_CRYPTO_ChallengeNonceP challenge = queue->challenge;
1684
1685 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1686 "try handle plaintext!\n");
1687
1688 if ((sizeof(*hdr) > queue->pread_off))
1689 {
1690 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1691 "Handling plaintext, not even a header!\n");
1692 return 0; /* not even a header */
1693 }
1694
1695 if ((-1 != unverified_size) && (unverified_size > INITIAL_CORE_KX_SIZE))
1696 {
1697 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1698 "Already received data of size %lu bigger than KX size %lu!\n",
1699 unverified_size,
1700 INITIAL_CORE_KX_SIZE);
1701 GNUNET_break_op (0);
1702 queue_finish (queue);
1703 return 0;
1704 }
1705
1706 type = ntohs (hdr->type);
1707 switch (type)
1708 {
1709 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK:
1710 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1711 "start processing ack\n");
1712 if (sizeof(*tca) > queue->pread_off)
1713 {
1714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1715 "Handling plaintext size of tca greater than pread offset.\n");
1716 return 0;
1717 }
1718 if (ntohs (hdr->size) != sizeof(*tca))
1719 {
1720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1721 "Handling plaintext size does not match message type.\n");
1722 GNUNET_break_op (0);
1723 queue_finish (queue);
1724 return 0;
1725 }
1726
1727 thas.purpose.purpose = htonl (
1728 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK);
1729 thas.purpose.size = htonl (sizeof(thas));
1730 thas.sender = tca->sender;
1731 thas.receiver = my_identity;
1732 thas.monotonic_time = tca->monotonic_time;
1733 thas.challenge = tca->challenge;
1734
1735 if (GNUNET_SYSERR == GNUNET_CRYPTO_eddsa_verify (
1736 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK,
1737 &thas,
1738 &tca->sender_sig,
1739 &tca->sender.public_key))
1740 {
1741 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1742 "Verification of signature failed!\n");
1743 GNUNET_break (0);
1744 queue_finish (queue);
1745 return 0;
1746 }
1747 if (0 != GNUNET_memcmp (&tca->challenge, &challenge))
1748 {
1749 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1750 "Challenge in TCPConfirmationAck not correct!\n");
1751 GNUNET_break (0);
1752 queue_finish (queue);
1753 return 0;
1754 }
1755
1756 queue->handshake_ack_monotime_get = GNUNET_PEERSTORE_iterate (peerstore,
1757 "transport_tcp_communicator",
1758 &queue->target,
1759 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK,
1760 &
1761 handshake_ack_monotime_cb,
1762 queue);
1763
1764 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1765 "Handling plaintext, ack processed!\n");
1766
1767 if (GNUNET_TRANSPORT_CS_INBOUND == queue->cs)
1768 {
1769 send_challenge (queue->challenge_received, queue);
1770 queue->write_task =
1771 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1772 queue->sock,
1773 &queue_write,
1774 queue);
1775 }
1776
1777 unverified_size = -1;
1778
1779 char *foreign_addr;
1780
1781 switch (queue->address->sa_family)
1782 {
1783 case AF_INET:
1784 GNUNET_asprintf (&foreign_addr,
1785 "%s-%s",
1786 COMMUNICATOR_ADDRESS_PREFIX,
1787 GNUNET_a2s (queue->address, queue->address_len));
1788 break;
1789
1790 case AF_INET6:
1791 GNUNET_asprintf (&foreign_addr,
1792 "%s-%s",
1793 COMMUNICATOR_ADDRESS_PREFIX,
1794 GNUNET_a2s (queue->address, queue->address_len));
1795 break;
1796
1797 default:
1798 GNUNET_assert (0);
1799 }
1800
1801 queue->qh = GNUNET_TRANSPORT_communicator_mq_add (ch,
1802 &queue->target,
1803 foreign_addr,
1804 UINT16_MAX, /* no MTU */
1805 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
1806 0, /* Priority */
1807 queue->nt,
1808 queue->cs,
1809 queue->mq);
1810
1811 GNUNET_free (foreign_addr);
1812
1813 size = ntohs (hdr->size);
1814 break;
1815 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX:
1816 /* Special case: header size excludes box itself! */
1817 if (ntohs (hdr->size) + sizeof(struct TCPBox) > queue->pread_off)
1818 return 0;
1819 calculate_hmac (&queue->in_hmac, &box[1], ntohs (hdr->size), &tmac);
1820 if (0 != memcmp (&tmac, &box->hmac, sizeof(tmac)))
1821 {
1822 GNUNET_break_op (0);
1823 queue_finish (queue);
1824 return 0;
1825 }
1826 pass_plaintext_to_core (queue, (const void *) &box[1], ntohs (hdr->size));
1827 size = ntohs (hdr->size) + sizeof(*box);
1828 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1829 "Handling plaintext, box processed!\n");
1830 break;
1831
1832 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY:
1833 if (sizeof(*rekey) > queue->pread_off)
1834 return 0;
1835 if (ntohs (hdr->size) != sizeof(*rekey))
1836 {
1837 GNUNET_break_op (0);
1838 queue_finish (queue);
1839 return 0;
1840 }
1841 rekeyz = *rekey;
1842 memset (&rekeyz.hmac, 0, sizeof(rekeyz.hmac));
1843 calculate_hmac (&queue->in_hmac, &rekeyz, sizeof(rekeyz), &tmac);
1844 if (0 != memcmp (&tmac, &rekey->hmac, sizeof(tmac)))
1845 {
1846 GNUNET_break_op (0);
1847 queue_finish (queue);
1848 return 0;
1849 }
1850 do_rekey (queue, rekey);
1851 size = ntohs (hdr->size);
1852 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1853 "Handling plaintext, rekey processed!\n");
1854 break;
1855
1856 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH:
1857 if (sizeof(*fin) > queue->pread_off)
1858 return 0;
1859 if (ntohs (hdr->size) != sizeof(*fin))
1860 {
1861 GNUNET_break_op (0);
1862 queue_finish (queue);
1863 return 0;
1864 }
1865 finz = *fin;
1866 memset (&finz.hmac, 0, sizeof(finz.hmac));
1867 calculate_hmac (&queue->in_hmac, &rekeyz, sizeof(rekeyz), &tmac);
1868 if (0 != memcmp (&tmac, &fin->hmac, sizeof(tmac)))
1869 {
1870 GNUNET_break_op (0);
1871 queue_finish (queue);
1872 return 0;
1873 }
1874 /* handle FINISH by destroying queue */
1875 queue_destroy (queue);
1876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1877 "Handling plaintext, finish processed!\n");
1878 break;
1879
1880 default:
1881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1882 "Handling plaintext, nothing processed!\n");
1883 GNUNET_break_op (0);
1884 queue_finish (queue);
1885 return 0;
1886 }
1887 GNUNET_assert (0 != size);
1888 if (-1 != unverified_size)
1889 unverified_size += size;
1890 return size;
1891}
1892
1893
1894/**
1895 * Queue read task. If we hit the timeout, disconnect it
1896 *
1897 * @param cls the `struct Queue *` to disconnect
1898 */
1899static void
1900queue_read (void *cls)
1901{
1902 struct Queue *queue = cls;
1903 struct GNUNET_TIME_Relative left;
1904 ssize_t rcvd;
1905
1906 queue->read_task = NULL;
1907 rcvd = GNUNET_NETWORK_socket_recv (queue->sock,
1908 &queue->cread_buf[queue->cread_off],
1909 BUF_SIZE - queue->cread_off);
1910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1911 "Received %lu bytes from TCP queue\n", rcvd);
1912 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1913 "transport",
1914 "Received %lu bytes from TCP queue\n", rcvd);
1915 if (-1 == rcvd)
1916 {
1917 if ((EAGAIN != errno) && (EINTR != errno))
1918 {
1919 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
1920 queue_finish (queue);
1921 return;
1922 }
1923 /* try again */
1924 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
1925 queue->read_task =
1926 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read, queue);
1927 return;
1928 }
1929 if (0 != rcvd)
1930 reschedule_queue_timeout (queue);
1931 queue->cread_off += rcvd;
1932 while ((queue->pread_off < sizeof(queue->pread_buf)) &&
1933 (queue->cread_off > 0))
1934 {
1935 size_t max = GNUNET_MIN (sizeof(queue->pread_buf) - queue->pread_off,
1936 queue->cread_off);
1937 size_t done;
1938 size_t total;
1939 size_t old_pread_off = queue->pread_off;
1940
1941 GNUNET_assert (0 ==
1942 gcry_cipher_decrypt (queue->in_cipher,
1943 &queue->pread_buf[queue->pread_off],
1944 max,
1945 queue->cread_buf,
1946 max));
1947 queue->pread_off += max;
1948 total = 0;
1949 while (0 != (done = try_handle_plaintext (queue)))
1950 {
1951 /* 'done' bytes of plaintext were used, shift buffer */
1952 GNUNET_assert (done <= queue->pread_off);
1953 /* NOTE: this memmove() could possibly sometimes be
1954 avoided if we pass 'total' into try_handle_plaintext()
1955 and use it at an offset into the buffer there! */
1956 memmove (queue->pread_buf,
1957 &queue->pread_buf[done],
1958 queue->pread_off - done);
1959 queue->pread_off -= done;
1960 total += done;
1961 /* The last plaintext was a rekey, abort for now */
1962 if (GNUNET_YES == queue->rekeyed)
1963 break;
1964 }
1965 /* when we encounter a rekey message, the decryption above uses the
1966 wrong key for everything after the rekey; in that case, we have
1967 to re-do the decryption at 'total' instead of at 'max'.
1968 However, we have to take into account that the plaintext buffer may have
1969 already contained data and not jumped too far ahead in the ciphertext.
1970 If there is no rekey and the last message is incomplete (max > total),
1971 it is safe to keep the decryption so we shift by 'max' */
1972 if (GNUNET_YES == queue->rekeyed)
1973 {
1974 max = total - old_pread_off;
1975 queue->rekeyed = GNUNET_NO;
1976 queue->pread_off = 0;
1977 }
1978 memmove (queue->cread_buf, &queue->cread_buf[max], queue->cread_off - max);
1979 queue->cread_off -= max;
1980 }
1981 if (BUF_SIZE == queue->cread_off)
1982 return; /* buffer full, suspend reading */
1983 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
1984 if (0 != left.rel_value_us)
1985 {
1986 if (max_queue_length > queue->backpressure)
1987 {
1988 /* continue reading */
1989 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
1990 queue->read_task =
1991 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read, queue);
1992 }
1993 return;
1994 }
1995 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1996 "Queue %p was idle for %s, disconnecting\n",
1997 queue,
1998 GNUNET_STRINGS_relative_time_to_string (
1999 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2000 GNUNET_YES));
2001 queue_finish (queue);
2002}
2003
2004
2005/**
2006 * Convert a `struct sockaddr_in6 to a `struct sockaddr *`
2007 *
2008 * @param[out] sock_len set to the length of the address.
2009 * @param v6 The sockaddr_in6 to be converted.
2010 * @return The struct sockaddr *.
2011 */
2012static struct sockaddr *
2013tcp_address_to_sockaddr_numeric_v6 (socklen_t *sock_len,
2014 struct sockaddr_in6 v6,
2015 unsigned int port)
2016{
2017 struct sockaddr *in;
2018
2019 v6.sin6_family = AF_INET6;
2020 v6.sin6_port = htons ((uint16_t) port);
2021#if HAVE_SOCKADDR_IN_SIN_LEN
2022 v6.sin6_len = sizeof(sizeof(struct sockaddr_in6));
2023#endif
2024 v6.sin6_flowinfo = 0;
2025 v6.sin6_scope_id = 0;
2026 in = GNUNET_memdup (&v6, sizeof(v6));
2027 *sock_len = sizeof(struct sockaddr_in6);
2028
2029 return in;
2030}
2031
2032
2033/**
2034 * Convert a `struct sockaddr_in4 to a `struct sockaddr *`
2035 *
2036 * @param[out] sock_len set to the length of the address.
2037 * @param v4 The sockaddr_in4 to be converted.
2038 * @return The struct sockaddr *.
2039 */
2040static struct sockaddr *
2041tcp_address_to_sockaddr_numeric_v4 (socklen_t *sock_len,
2042 struct sockaddr_in v4,
2043 unsigned int port)
2044{
2045 struct sockaddr *in;
2046
2047 v4.sin_family = AF_INET;
2048 v4.sin_port = htons ((uint16_t) port);
2049#if HAVE_SOCKADDR_IN_SIN_LEN
2050 v4.sin_len = sizeof(struct sockaddr_in);
2051#endif
2052 in = GNUNET_memdup (&v4, sizeof(v4));
2053 *sock_len = sizeof(struct sockaddr_in);
2054 return in;
2055}
2056
2057
2058/**
2059 * Convert TCP bind specification to a `struct PortOnlyIpv4Ipv6 *`
2060 *
2061 * @param bindto bind specification to convert.
2062 * @return The converted bindto specification.
2063 */
2064static struct PortOnlyIpv4Ipv6 *
2065tcp_address_to_sockaddr_port_only (const char *bindto, unsigned int *port)
2066{
2067 struct PortOnlyIpv4Ipv6 *po;
2068 struct sockaddr_in *i4;
2069 struct sockaddr_in6 *i6;
2070 socklen_t sock_len_ipv4;
2071 socklen_t sock_len_ipv6;
2072
2073 /* interpreting value as just a PORT number */
2074 if (*port > UINT16_MAX)
2075 {
2076 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2077 "BINDTO specification `%s' invalid: value too large for port\n",
2078 bindto);
2079 return NULL;
2080 }
2081
2082 po = GNUNET_new (struct PortOnlyIpv4Ipv6);
2083
2084 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
2085 (GNUNET_YES ==
2086 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2087 COMMUNICATOR_CONFIG_SECTION,
2088 "DISABLE_V6")))
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 else
2096 {
2097
2098 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2099 po->addr_ipv4 = tcp_address_to_sockaddr_numeric_v4 (&sock_len_ipv4, *i4,
2100 *port);
2101 po->addr_len_ipv4 = sock_len_ipv4;
2102
2103 i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
2104 po->addr_ipv6 = tcp_address_to_sockaddr_numeric_v6 (&sock_len_ipv6, *i6,
2105 *port);
2106
2107 po->addr_len_ipv6 = sock_len_ipv6;
2108
2109 GNUNET_free (i6);
2110 }
2111
2112 GNUNET_free (i4);
2113
2114 return po;
2115}
2116
2117
2118/**
2119 * This Method extracts the address part of the BINDTO string.
2120 *
2121 * @param bindto String we extract the address part from.
2122 * @return The extracted address string.
2123 */
2124static char *
2125extract_address (const char *bindto)
2126{
2127 char *addr;
2128 char *start;
2129 char *token;
2130 char *cp;
2131 char *rest = NULL;
2132 char *res;
2133
2134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2135 "extract address with bindto %s\n",
2136 bindto);
2137
2138 if (NULL == bindto)
2139 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2140 "bindto is NULL\n");
2141
2142 cp = GNUNET_strdup (bindto);
2143
2144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2145 "extract address 2\n");
2146
2147 start = cp;
2148 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
2149 {
2150 start++; /* skip over '['*/
2151 cp[strlen (cp) - 1] = '\0'; /* eat ']'*/
2152 addr = GNUNET_strdup (start);
2153 }
2154 else
2155 {
2156 token = strtok_r (cp, "]", &rest);
2157 if (strlen (bindto) == strlen (token))
2158 {
2159 token = strtok_r (cp, ":", &rest);
2160 addr = GNUNET_strdup (token);
2161 }
2162 else
2163 {
2164 token++;
2165 res = GNUNET_strdup (token);
2166 addr = GNUNET_strdup (res);
2167 }
2168 }
2169
2170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2171 "tcp address: %s\n",
2172 addr);
2173 GNUNET_free (cp);
2174 return addr;
2175}
2176
2177
2178/**
2179 * This Method extracts the port part of the BINDTO string.
2180 *
2181 * @param addr_and_port String we extract the port from.
2182 * @return The extracted port as unsigned int.
2183 */
2184static unsigned int
2185extract_port (const char *addr_and_port)
2186{
2187 unsigned int port;
2188 char dummy[2];
2189 char *token;
2190 char *addr;
2191 char *colon;
2192 char *cp;
2193 char *rest = NULL;
2194
2195 if (NULL != addr_and_port)
2196 {
2197 cp = GNUNET_strdup (addr_and_port);
2198 token = strtok_r (cp, "]", &rest);
2199 if (strlen (addr_and_port) == strlen (token))
2200 {
2201 colon = strrchr (cp, ':');
2202 if (NULL == colon)
2203 {
2204 GNUNET_free (cp);
2205 return 0;
2206 }
2207 addr = colon;
2208 addr++;
2209 }
2210 else
2211 {
2212 token = strtok_r (NULL, "]", &rest);
2213 if (NULL == token)
2214 {
2215 GNUNET_free (cp);
2216 return 0;
2217 }
2218 else
2219 {
2220 addr = token;
2221 addr++;
2222 }
2223 }
2224
2225
2226 if (1 == sscanf (addr, "%u%1s", &port, dummy))
2227 {
2228 /* interpreting value as just a PORT number */
2229 if (port > UINT16_MAX)
2230 {
2231 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2232 "Port `%u' invalid: value too large for port\n",
2233 port);
2234 GNUNET_free (cp);
2235 return 0;
2236 }
2237 }
2238 else
2239 {
2240 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2241 "BINDTO specification invalid: last ':' not followed by number\n");
2242 GNUNET_free (cp);
2243 return 0;
2244 }
2245 GNUNET_free (cp);
2246 }
2247 else
2248 {
2249 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2250 "return 0\n");
2251 /* interpret missing port as 0, aka pick any free one */
2252 port = 0;
2253 }
2254
2255 return port;
2256}
2257
2258
2259/**
2260 * Convert TCP bind specification to a `struct sockaddr *`
2261 *
2262 * @param bindto bind specification to convert
2263 * @param[out] sock_len set to the length of the address
2264 * @return converted bindto specification
2265 */
2266static struct sockaddr *
2267tcp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
2268{
2269 struct sockaddr *in;
2270 unsigned int port;
2271 struct sockaddr_in v4;
2272 struct sockaddr_in6 v6;
2273 char *start;
2274
2275 start = extract_address (bindto);
2276 // FIXME: check NULL == start
2277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2278 "start %s\n",
2279 start);
2280
2281 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2282 "!bindto %s\n",
2283 bindto);
2284
2285
2286 if (1 == inet_pton (AF_INET, start, &v4.sin_addr))
2287 {
2288 // colon = strrchr (cp, ':');
2289 port = extract_port (bindto);
2290
2291 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2292 "port %u\n",
2293 port);
2294
2295 in = tcp_address_to_sockaddr_numeric_v4 (sock_len, v4, port);
2296 }
2297 else if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
2298 {
2299 // colon = strrchr (cp, ':');
2300 port = extract_port (bindto);
2301 in = tcp_address_to_sockaddr_numeric_v6 (sock_len, v6, port);
2302 }
2303 else
2304 {
2305 GNUNET_assert (0);
2306 }
2307
2308 GNUNET_free (start);
2309 return in;
2310}
2311
2312
2313/**
2314 * Signature of functions implementing the sending functionality of a
2315 * message queue.
2316 *
2317 * @param mq the message queue
2318 * @param msg the message to send
2319 * @param impl_state our `struct Queue`
2320 */
2321static void
2322mq_send (struct GNUNET_MQ_Handle *mq,
2323 const struct GNUNET_MessageHeader *msg,
2324 void *impl_state)
2325{
2326 struct Queue *queue = impl_state;
2327 uint16_t msize = ntohs (msg->size);
2328 struct TCPBox box;
2329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2330 "In MQ send. Queue finishing: %s; write task running: %s\n",
2331 (GNUNET_YES == queue->finishing) ? "yes" : "no",
2332 (NULL == queue->write_task) ? "yes" : "no");
2333 GNUNET_assert (mq == queue->mq);
2334 queue->mq_awaits_continue = GNUNET_YES;
2335 if (GNUNET_YES == queue->finishing)
2336 return; /* this queue is dying, drop msg */
2337 GNUNET_assert (0 == queue->pwrite_off);
2338 box.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX);
2339 box.header.size = htons (msize);
2340 calculate_hmac (&queue->out_hmac, msg, msize, &box.hmac);
2341 memcpy (&queue->pwrite_buf[queue->pwrite_off], &box, sizeof(box));
2342 queue->pwrite_off += sizeof(box);
2343 memcpy (&queue->pwrite_buf[queue->pwrite_off], msg, msize);
2344 queue->pwrite_off += msize;
2345 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2346 "%lu bytes of plaintext to send\n", queue->pwrite_off);
2347 GNUNET_assert (NULL != queue->sock);
2348 if (NULL == queue->write_task)
2349 queue->write_task =
2350 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2351 queue->sock,
2352 &queue_write,
2353 queue);
2354}
2355
2356
2357/**
2358 * Signature of functions implementing the destruction of a message
2359 * queue. Implementations must not free @a mq, but should take care
2360 * of @a impl_state.
2361 *
2362 * @param mq the message queue to destroy
2363 * @param impl_state our `struct Queue`
2364 */
2365static void
2366mq_destroy (struct GNUNET_MQ_Handle *mq, void *impl_state)
2367{
2368 struct Queue *queue = impl_state;
2369
2370 if (mq == queue->mq)
2371 {
2372 queue->mq = NULL;
2373 queue_finish (queue);
2374 }
2375}
2376
2377
2378/**
2379 * Implementation function that cancels the currently sent message.
2380 *
2381 * @param mq message queue
2382 * @param impl_state our `struct Queue`
2383 */
2384static void
2385mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
2386{
2387 struct Queue *queue = impl_state;
2388
2389 GNUNET_assert (0 != queue->pwrite_off);
2390 queue->pwrite_off = 0;
2391}
2392
2393
2394/**
2395 * Generic error handler, called with the appropriate
2396 * error code and the same closure specified at the creation of
2397 * the message queue.
2398 * Not every message queue implementation supports an error handler.
2399 *
2400 * @param cls our `struct Queue`
2401 * @param error error code
2402 */
2403static void
2404mq_error (void *cls, enum GNUNET_MQ_Error error)
2405{
2406 struct Queue *queue = cls;
2407
2408 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2409 "MQ error in queue to %s: %d\n",
2410 GNUNET_i2s (&queue->target),
2411 (int) error);
2412 queue_finish (queue);
2413}
2414
2415
2416/**
2417 * Add the given @a queue to our internal data structure. Setup the
2418 * MQ processing and inform transport that the queue is ready. Must
2419 * be called after the KX for outgoing messages has been bootstrapped.
2420 *
2421 * @param queue queue to boot
2422 */
2423static void
2424boot_queue (struct Queue *queue)
2425{
2426 queue->nt =
2427 GNUNET_NT_scanner_get_type (is, queue->address, queue->address_len);
2428 (void) GNUNET_CONTAINER_multipeermap_put (
2429 queue_map,
2430 &queue->target,
2431 queue,
2432 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2433 GNUNET_STATISTICS_set (stats,
2434 "# queues active",
2435 GNUNET_CONTAINER_multipeermap_size (queue_map),
2436 GNUNET_NO);
2437 queue->timeout =
2438 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2439 queue->mq = GNUNET_MQ_queue_for_callbacks (&mq_send,
2440 &mq_destroy,
2441 &mq_cancel,
2442 queue,
2443 NULL,
2444 &mq_error,
2445 queue);
2446}
2447
2448
2449/**
2450 * Generate and transmit our ephemeral key and the signature for
2451 * the initial KX with the other peer. Must be called first, before
2452 * any other bytes are ever written to the output buffer. Note that
2453 * our cipher must already be initialized when calling thi function.
2454 * Helper function for #start_initial_kx_out().
2455 *
2456 * @param queue queue to do KX for
2457 * @param epub our public key for the KX
2458 */
2459static void
2460transmit_kx (struct Queue *queue,
2461 const struct GNUNET_CRYPTO_EcdhePublicKey *epub)
2462{
2463 struct TcpHandshakeSignature ths;
2464 struct TCPConfirmation tc;
2465
2466 memcpy (queue->cwrite_buf, epub, sizeof(*epub));
2467 queue->cwrite_off = sizeof(*epub);
2468 /* compute 'tc' and append in encrypted format to cwrite_buf */
2469 tc.sender = my_identity;
2470 tc.monotonic_time =
2471 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
2472 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
2473 &tc.challenge,
2474 sizeof(tc.challenge));
2475 ths.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE);
2476 ths.purpose.size = htonl (sizeof(ths));
2477 ths.sender = my_identity;
2478 ths.receiver = queue->target;
2479 ths.ephemeral = *epub;
2480 ths.monotonic_time = tc.monotonic_time;
2481 ths.challenge = tc.challenge;
2482 GNUNET_CRYPTO_eddsa_sign (my_private_key,
2483 &ths,
2484 &tc.sender_sig);
2485 GNUNET_assert (0 ==
2486 gcry_cipher_encrypt (queue->out_cipher,
2487 &queue->cwrite_buf[queue->cwrite_off],
2488 sizeof(tc),
2489 &tc,
2490 sizeof(tc)));
2491 queue->challenge = tc.challenge;
2492 queue->cwrite_off += sizeof(tc);
2493
2494 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2495 "transport",
2496 "handshake written\n");
2497}
2498
2499
2500/**
2501 * Initialize our key material for outgoing transmissions and
2502 * inform the other peer about it. Must be called first before
2503 * any data is sent.
2504 *
2505 * @param queue the queue to setup
2506 */
2507static void
2508start_initial_kx_out (struct Queue *queue)
2509{
2510 struct GNUNET_CRYPTO_EcdhePublicKey epub;
2511
2512 GNUNET_CRYPTO_ecdhe_key_create (&queue->ephemeral);
2513 GNUNET_CRYPTO_ecdhe_key_get_public (&queue->ephemeral, &epub);
2514 setup_out_cipher (queue);
2515 transmit_kx (queue, &epub);
2516}
2517
2518
2519/**
2520 * Callback called when peerstore store operation for handshake monotime is finished.
2521 * @param cls Queue context the store operation was executed.
2522 * @param success Store operation was successful (GNUNET_OK) or not.
2523 */
2524static void
2525handshake_monotime_store_cb (void *cls, int success)
2526{
2527 struct Queue *queue = cls;
2528 if (GNUNET_OK != success)
2529 {
2530 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2531 "Failed to store handshake monotonic time in PEERSTORE!\n");
2532 }
2533 queue->handshake_monotime_sc = NULL;
2534}
2535
2536
2537/**
2538 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE
2539 * where found.
2540 * @param cls Queue context the store operation was executed.
2541 * @param record The record found or NULL if there is no record left.
2542 * @param emsg Message from peerstore.
2543 */
2544static void
2545handshake_monotime_cb (void *cls,
2546 const struct GNUNET_PEERSTORE_Record *record,
2547 const char *emsg)
2548{
2549 struct Queue *queue = cls;
2550 struct GNUNET_TIME_AbsoluteNBO *mtbe;
2551 struct GNUNET_TIME_Absolute mt;
2552 const struct GNUNET_PeerIdentity *pid;
2553 struct GNUNET_TIME_AbsoluteNBO *handshake_monotonic_time;
2554
2555 (void) emsg;
2556
2557 handshake_monotonic_time = &queue->handshake_monotonic_time;
2558 pid = &queue->target;
2559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2560 "tcp handshake with us %s\n",
2561 GNUNET_i2s (&my_identity));
2562 if (NULL == record)
2563 {
2564 queue->handshake_monotime_get = NULL;
2565 return;
2566 }
2567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2568 "tcp handshake from peer %s\n",
2569 GNUNET_i2s (pid));
2570 if (sizeof(*mtbe) != record->value_size)
2571 {
2572 GNUNET_break (0);
2573 return;
2574 }
2575 mtbe = record->value;
2576 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
2577 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
2578 queue->handshake_monotonic_time).abs_value_us)
2579 {
2580 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2581 "Queue from %s dropped, handshake monotime in the past\n",
2582 GNUNET_i2s (&queue->target));
2583 GNUNET_break (0);
2584 queue_finish (queue);
2585 return;
2586 }
2587 queue->handshake_monotime_sc = GNUNET_PEERSTORE_store (peerstore,
2588 "transport_tcp_communicator",
2589 pid,
2590 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE,
2591 handshake_monotonic_time,
2592 sizeof(*
2593 handshake_monotonic_time),
2594 GNUNET_TIME_UNIT_FOREVER_ABS,
2595 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
2596 &
2597 handshake_monotime_store_cb,
2598 queue);
2599}
2600
2601
2602/**
2603 * We have received the first bytes from the other side on a @a queue.
2604 * Decrypt the @a tc contained in @a ibuf and check the signature.
2605 * Note that #setup_in_cipher() must have already been called.
2606 *
2607 * @param queue queue to decrypt initial bytes from other peer for
2608 * @param tc[out] where to store the result
2609 * @param ibuf incoming data, of size
2610 * `INITIAL_KX_SIZE`
2611 * @return #GNUNET_OK if the signature was OK, #GNUNET_SYSERR if not
2612 */
2613static int
2614decrypt_and_check_tc (struct Queue *queue,
2615 struct TCPConfirmation *tc,
2616 char *ibuf)
2617{
2618 struct TcpHandshakeSignature ths;
2619 enum GNUNET_GenericReturnValue ret;
2620
2621 GNUNET_assert (
2622 0 ==
2623 gcry_cipher_decrypt (queue->in_cipher,
2624 tc,
2625 sizeof(*tc),
2626 &ibuf[sizeof(struct GNUNET_CRYPTO_EcdhePublicKey)],
2627 sizeof(*tc)));
2628 ths.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE);
2629 ths.purpose.size = htonl (sizeof(ths));
2630 ths.sender = tc->sender;
2631 ths.receiver = my_identity;
2632 memcpy (&ths.ephemeral, ibuf, sizeof(struct GNUNET_CRYPTO_EcdhePublicKey));
2633 ths.monotonic_time = tc->monotonic_time;
2634 ths.challenge = tc->challenge;
2635 ret = GNUNET_CRYPTO_eddsa_verify (
2636 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE,
2637 &ths,
2638 &tc->sender_sig,
2639 &tc->sender.public_key);
2640 if (GNUNET_YES == ret)
2641 queue->handshake_monotime_get =
2642 GNUNET_PEERSTORE_iterate (peerstore,
2643 "transport_tcp_communicator",
2644 &queue->target,
2645 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE,
2646 &handshake_monotime_cb,
2647 queue);
2648 return ret;
2649}
2650
2651
2652/**
2653 * Closes socket and frees memory associated with @a pq.
2654 *
2655 * @param pq proto queue to free
2656 */
2657static void
2658free_proto_queue (struct ProtoQueue *pq)
2659{
2660 if (NULL != pq->listen_sock)
2661 {
2662 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pq->listen_sock));
2663 pq->listen_sock = NULL;
2664 }
2665 GNUNET_NETWORK_socket_close (pq->sock);
2666 GNUNET_free (pq->address);
2667 GNUNET_CONTAINER_DLL_remove (proto_head, proto_tail, pq);
2668 GNUNET_free (pq);
2669}
2670
2671
2672/**
2673 * Read from the socket of the proto queue until we have enough data
2674 * to upgrade to full queue.
2675 *
2676 * @param cls a `struct ProtoQueue`
2677 */
2678static void
2679proto_read_kx (void *cls)
2680{
2681 struct ProtoQueue *pq = cls;
2682 ssize_t rcvd;
2683 struct GNUNET_TIME_Relative left;
2684 struct Queue *queue;
2685 struct TCPConfirmation tc;
2686
2687 pq->read_task = NULL;
2688 left = GNUNET_TIME_absolute_get_remaining (pq->timeout);
2689 if (0 == left.rel_value_us)
2690 {
2691 free_proto_queue (pq);
2692 return;
2693 }
2694 rcvd = GNUNET_NETWORK_socket_recv (pq->sock,
2695 &pq->ibuf[pq->ibuf_off],
2696 sizeof(pq->ibuf) - pq->ibuf_off);
2697 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2698 "Received %lu bytes for KX\n", rcvd);
2699 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2700 "transport",
2701 "Received %lu bytes for KX\n", rcvd);
2702 if (-1 == rcvd)
2703 {
2704 if ((EAGAIN != errno) && (EINTR != errno))
2705 {
2706 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2707 free_proto_queue (pq);
2708 return;
2709 }
2710 /* try again */
2711 pq->read_task =
2712 GNUNET_SCHEDULER_add_read_net (left, pq->sock, &proto_read_kx, pq);
2713 return;
2714 }
2715 pq->ibuf_off += rcvd;
2716 if (pq->ibuf_off > sizeof(pq->ibuf))
2717 {
2718 /* read more */
2719 pq->read_task =
2720 GNUNET_SCHEDULER_add_read_net (left, pq->sock, &proto_read_kx, pq);
2721 return;
2722 }
2723 /* we got all the data, let's find out who we are talking to! */
2724 queue = GNUNET_new (struct Queue);
2725 setup_in_cipher ((const struct GNUNET_CRYPTO_EcdhePublicKey *) pq->ibuf,
2726 queue);
2727 if (GNUNET_OK != decrypt_and_check_tc (queue, &tc, pq->ibuf))
2728 {
2729 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2730 "Invalid TCP KX received from %s\n",
2731 GNUNET_a2s (pq->address, pq->address_len));
2732 gcry_cipher_close (queue->in_cipher);
2733 GNUNET_free (queue);
2734 free_proto_queue (pq);
2735 return;
2736 }
2737 queue->address = pq->address; /* steals reference */
2738 queue->address_len = pq->address_len;
2739 queue->target = tc.sender;
2740 queue->listen_sock = pq->listen_sock;
2741 queue->sock = pq->sock;
2742
2743 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2744 "created queue with target %s\n",
2745 GNUNET_i2s (&queue->target));
2746
2747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2748 "start kx proto\n");
2749
2750 start_initial_kx_out (queue);
2751 queue->cs = GNUNET_TRANSPORT_CS_INBOUND;
2752 boot_queue (queue);
2753 queue->read_task =
2754 GNUNET_SCHEDULER_add_read_net (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2755 queue->sock,
2756 &queue_read,
2757 queue);
2758 queue->write_task =
2759 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2760 queue->sock,
2761 &queue_write,
2762 queue);
2763 // TODO To early! Move it somewhere else.
2764 // send_challenge (tc.challenge, queue);
2765 queue->challenge_received = tc.challenge;
2766
2767 GNUNET_CONTAINER_DLL_remove (proto_head, proto_tail, pq);
2768 GNUNET_free (pq);
2769}
2770
2771
2772/**
2773 * We have been notified that our listen socket has something to
2774 * read. Do the read and reschedule this function to be called again
2775 * once more is available.
2776 *
2777 * @param cls ListenTask with listening socket and task
2778 */
2779static void
2780listen_cb (void *cls)
2781{
2782 struct sockaddr_storage in;
2783 socklen_t addrlen;
2784 struct GNUNET_NETWORK_Handle *sock;
2785 struct ProtoQueue *pq;
2786 struct ListenTask *lt;
2787
2788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2789 "listen_cb\n");
2790
2791 lt = cls;
2792
2793 lt->listen_task = NULL;
2794 GNUNET_assert (NULL != lt->listen_sock);
2795 addrlen = sizeof(in);
2796 memset (&in, 0, sizeof(in));
2797 sock = GNUNET_NETWORK_socket_accept (lt->listen_sock,
2798 (struct sockaddr*) &in,
2799 &addrlen);
2800 if ((NULL == sock) && ((EMFILE == errno) || (ENFILE == errno)))
2801 return; /* system limit reached, wait until connection goes down */
2802 lt->listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2803 lt->listen_sock,
2804 &listen_cb,
2805 lt);
2806 if ((NULL == sock) && ((EAGAIN == errno) || (ENOBUFS == errno)))
2807 return;
2808 if (NULL == sock)
2809 {
2810 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "accept");
2811 return;
2812 }
2813 pq = GNUNET_new (struct ProtoQueue);
2814 pq->address_len = addrlen;
2815 pq->address = GNUNET_memdup (&in, addrlen);
2816 pq->timeout = GNUNET_TIME_relative_to_absolute (PROTO_QUEUE_TIMEOUT);
2817 pq->sock = sock;
2818 pq->read_task = GNUNET_SCHEDULER_add_read_net (PROTO_QUEUE_TIMEOUT,
2819 pq->sock,
2820 &proto_read_kx,
2821 pq);
2822 GNUNET_CONTAINER_DLL_insert (proto_head, proto_tail, pq);
2823}
2824
2825
2826/**
2827 * Read from the socket of the queue until we have enough data
2828 * to initialize the decryption logic and can switch to regular
2829 * reading.
2830 *
2831 * @param cls a `struct Queue`
2832 */
2833static void
2834queue_read_kx (void *cls)
2835{
2836 struct Queue *queue = cls;
2837 ssize_t rcvd;
2838 struct GNUNET_TIME_Relative left;
2839 struct TCPConfirmation tc;
2840
2841 queue->read_task = NULL;
2842 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
2843 if (0 == left.rel_value_us)
2844 {
2845 queue_destroy (queue);
2846 return;
2847 }
2848 rcvd = GNUNET_NETWORK_socket_recv (queue->sock,
2849 &queue->cread_buf[queue->cread_off],
2850 BUF_SIZE - queue->cread_off);
2851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2852 "Received %lu bytes for KX\n",
2853 rcvd);
2854 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2855 "transport",
2856 "Received %lu bytes for KX\n",
2857 rcvd);
2858 if (-1 == rcvd)
2859 {
2860 if ((EAGAIN != errno) && (EINTR != errno))
2861 {
2862 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2863 queue_destroy (queue);
2864 return;
2865 }
2866 queue->read_task =
2867 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read_kx, queue);
2868 return;
2869 }
2870 queue->cread_off += rcvd;
2871 if (queue->cread_off < INITIAL_KX_SIZE)
2872 {
2873 /* read more */
2874 queue->read_task =
2875 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read_kx, queue);
2876 return;
2877 }
2878 /* we got all the data, let's find out who we are talking to! */
2879 setup_in_cipher ((const struct GNUNET_CRYPTO_EcdhePublicKey *)
2880 queue->cread_buf,
2881 queue);
2882 if (GNUNET_OK != decrypt_and_check_tc (queue, &tc, queue->cread_buf))
2883 {
2884 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2885 "Invalid TCP KX received from %s\n",
2886 GNUNET_a2s (queue->address, queue->address_len));
2887 queue_destroy (queue);
2888 return;
2889 }
2890 if (0 !=
2891 memcmp (&tc.sender, &queue->target, sizeof(struct GNUNET_PeerIdentity)))
2892 {
2893 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2894 "Invalid sender in TCP KX received from %s\n",
2895 GNUNET_a2s (queue->address, queue->address_len));
2896 queue_destroy (queue);
2897 return;
2898 }
2899 send_challenge (tc.challenge, queue);
2900 queue->write_task =
2901 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2902 queue->sock,
2903 &queue_write,
2904 queue);
2905
2906 /* update queue timeout */
2907 reschedule_queue_timeout (queue);
2908 /* prepare to continue with regular read task immediately */
2909 memmove (queue->cread_buf,
2910 &queue->cread_buf[INITIAL_KX_SIZE],
2911 queue->cread_off - (INITIAL_KX_SIZE));
2912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2913 "cread_off is %lu bytes before adjusting\n",
2914 queue->cread_off);
2915 queue->cread_off -= INITIAL_KX_SIZE;
2916 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2917 "cread_off set to %lu bytes\n",
2918 queue->cread_off);
2919 queue->read_task = GNUNET_SCHEDULER_add_now (&queue_read, queue);
2920}
2921
2922
2923/**
2924 * Function called by the transport service to initialize a
2925 * message queue given address information about another peer.
2926 * If and when the communication channel is established, the
2927 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
2928 * to notify the service that the channel is now up. It is
2929 * the responsibility of the communicator to manage sane
2930 * retries and timeouts for any @a peer/@a address combination
2931 * provided by the transport service. Timeouts and retries
2932 * do not need to be signalled to the transport service.
2933 *
2934 * @param cls closure
2935 * @param peer identity of the other peer
2936 * @param address where to send the message, human-readable
2937 * communicator-specific format, 0-terminated, UTF-8
2938 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is
2939 * invalid
2940 */
2941static int
2942mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
2943{
2944 struct Queue *queue;
2945 const char *path;
2946 struct sockaddr *in;
2947 socklen_t in_len = 0;
2948 struct GNUNET_NETWORK_Handle *sock;
2949
2950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2951 "Connecting to %s\n", address);
2952 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
2953 "transport",
2954 "Connecting to %s\n", address);
2955 if (0 != strncmp (address,
2956 COMMUNICATOR_ADDRESS_PREFIX "-",
2957 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
2958 {
2959 GNUNET_break_op (0);
2960 return GNUNET_SYSERR;
2961 }
2962 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
2963 in = tcp_address_to_sockaddr (path, &in_len);
2964
2965 if (NULL == in)
2966 {
2967 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2968 "Failed to setup TCP socket address\n");
2969 return GNUNET_SYSERR;
2970 }
2971
2972 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2973 "in %s\n",
2974 GNUNET_a2s (in, in_len));
2975
2976 sock = GNUNET_NETWORK_socket_create (in->sa_family, SOCK_STREAM, IPPROTO_TCP);
2977 if (NULL == sock)
2978 {
2979 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2980 "socket(%d) failed: %s",
2981 in->sa_family,
2982 strerror (errno));
2983 GNUNET_free (in);
2984 return GNUNET_SYSERR;
2985 }
2986 if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (sock, in, in_len)) &&
2987 (errno != EINPROGRESS))
2988 {
2989 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2990 "connect to `%s' failed: %s",
2991 address,
2992 strerror (errno));
2993 GNUNET_NETWORK_socket_close (sock);
2994 GNUNET_free (in);
2995 return GNUNET_SYSERR;
2996 }
2997
2998 queue = GNUNET_new (struct Queue);
2999 queue->target = *peer;
3000 queue->address = in;
3001 queue->address_len = in_len;
3002 queue->sock = sock;
3003 queue->cs = GNUNET_TRANSPORT_CS_OUTBOUND;
3004 boot_queue (queue);
3005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3006 "booted queue with target %s\n",
3007 GNUNET_i2s (&queue->target));
3008 // queue->mq_awaits_continue = GNUNET_YES;
3009 queue->read_task =
3010 GNUNET_SCHEDULER_add_read_net (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3011 queue->sock,
3012 &queue_read_kx,
3013 queue);
3014
3015
3016 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3017 "start kx mq_init\n");
3018
3019 start_initial_kx_out (queue);
3020 queue->write_task =
3021 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3022 queue->sock,
3023 &queue_write,
3024 queue);
3025 return GNUNET_OK;
3026}
3027
3028
3029/**
3030 * Iterator over all ListenTasks to clean up.
3031 *
3032 * @param cls NULL
3033 * @param key unused
3034 * @param value the ListenTask to cancel.
3035 * @return #GNUNET_OK to continue to iterate
3036 */
3037static int
3038get_lt_delete_it (void *cls,
3039 const struct GNUNET_HashCode *key,
3040 void *value)
3041{
3042 struct ListenTask *lt = value;
3043
3044 (void) cls;
3045 (void) key;
3046 if (NULL != lt->listen_task)
3047 {
3048 GNUNET_SCHEDULER_cancel (lt->listen_task);
3049 lt->listen_task = NULL;
3050 }
3051 if (NULL != lt->listen_sock)
3052 {
3053 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (lt->listen_sock));
3054 lt->listen_sock = NULL;
3055 }
3056 return GNUNET_OK;
3057}
3058
3059
3060/**
3061 * Iterator over all message queues to clean up.
3062 *
3063 * @param cls NULL
3064 * @param target unused
3065 * @param value the queue to destroy
3066 * @return #GNUNET_OK to continue to iterate
3067 */
3068static int
3069get_queue_delete_it (void *cls,
3070 const struct GNUNET_PeerIdentity *target,
3071 void *value)
3072{
3073 struct Queue *queue = value;
3074
3075 (void) cls;
3076 (void) target;
3077 queue_destroy (queue);
3078 return GNUNET_OK;
3079}
3080
3081
3082/**
3083 * Shutdown the UNIX communicator.
3084 *
3085 * @param cls NULL (always)
3086 */
3087static void
3088do_shutdown (void *cls)
3089{
3090 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3091 "Shutdown %s!\n",
3092 shutdown_running ? "running" : "not running");
3093
3094 if (GNUNET_YES == shutdown_running)
3095 return;
3096 else
3097 shutdown_running = GNUNET_YES;
3098
3099 while (NULL != proto_head)
3100 free_proto_queue (proto_head);
3101 if (NULL != nat)
3102 {
3103 GNUNET_NAT_unregister (nat);
3104 nat = NULL;
3105 }
3106 GNUNET_CONTAINER_multihashmap_iterate (lt_map, &get_lt_delete_it, NULL);
3107 GNUNET_CONTAINER_multipeermap_iterate (queue_map, &get_queue_delete_it, NULL);
3108 GNUNET_CONTAINER_multipeermap_destroy (queue_map);
3109 if (NULL != ch)
3110 {
3111 GNUNET_TRANSPORT_communicator_address_remove_all (ch);
3112 GNUNET_TRANSPORT_communicator_disconnect (ch);
3113 ch = NULL;
3114 }
3115 if (NULL != stats)
3116 {
3117 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3118 stats = NULL;
3119 }
3120 if (NULL != my_private_key)
3121 {
3122 GNUNET_free (my_private_key);
3123 my_private_key = NULL;
3124 }
3125 if (NULL != is)
3126 {
3127 GNUNET_NT_scanner_done (is);
3128 is = NULL;
3129 }
3130 if (NULL != peerstore)
3131 {
3132 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
3133 peerstore = NULL;
3134 }
3135 if (NULL != resolve_request_handle)
3136 {
3137 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3138 resolve_request_handle = NULL;
3139 }
3140 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3141 "Shutdown done!\n");
3142}
3143
3144
3145/**
3146 * Function called when the transport service has received an
3147 * acknowledgement for this communicator (!) via a different return
3148 * path.
3149 *
3150 * Not applicable for TCP.
3151 *
3152 * @param cls closure
3153 * @param sender which peer sent the notification
3154 * @param msg payload
3155 */
3156static void
3157enc_notify_cb (void *cls,
3158 const struct GNUNET_PeerIdentity *sender,
3159 const struct GNUNET_MessageHeader *msg)
3160{
3161 (void) cls;
3162 (void) sender;
3163 (void) msg;
3164 GNUNET_break_op (0);
3165}
3166
3167
3168/**
3169 * Signature of the callback passed to #GNUNET_NAT_register() for
3170 * a function to call whenever our set of 'valid' addresses changes.
3171 *
3172 * @param cls closure
3173 * @param app_ctx[in,out] location where the app can store stuff
3174 * on add and retrieve it on remove
3175 * @param add_remove #GNUNET_YES to add a new public IP address,
3176 * #GNUNET_NO to remove a previous (now invalid) one
3177 * @param ac address class the address belongs to
3178 * @param addr either the previous or the new public IP address
3179 * @param addrlen actual length of the @a addr
3180 */
3181static void
3182nat_address_cb (void *cls,
3183 void **app_ctx,
3184 int add_remove,
3185 enum GNUNET_NAT_AddressClass ac,
3186 const struct sockaddr *addr,
3187 socklen_t addrlen)
3188{
3189 char *my_addr;
3190 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
3191
3192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3193 "nat address cb %s %s\n",
3194 add_remove ? "add" : "remove",
3195 GNUNET_a2s (addr, addrlen));
3196
3197 if (GNUNET_YES == add_remove)
3198 {
3199 enum GNUNET_NetworkType nt;
3200
3201 GNUNET_asprintf (&my_addr,
3202 "%s-%s",
3203 COMMUNICATOR_ADDRESS_PREFIX,
3204 GNUNET_a2s (addr, addrlen));
3205 nt = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3206 ai =
3207 GNUNET_TRANSPORT_communicator_address_add (ch,
3208 my_addr,
3209 nt,
3210 GNUNET_TIME_UNIT_FOREVER_REL);
3211 GNUNET_free (my_addr);
3212 *app_ctx = ai;
3213 }
3214 else
3215 {
3216 ai = *app_ctx;
3217 GNUNET_TRANSPORT_communicator_address_remove (ai);
3218 *app_ctx = NULL;
3219 }
3220}
3221
3222
3223/**
3224 * This method adds addresses to the DLL, that are later register at the NAT service.
3225 */
3226static void
3227add_addr (struct sockaddr *in, socklen_t in_len)
3228{
3229
3230 struct Addresses *saddrs;
3231
3232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3233 "add address %s\n",
3234 GNUNET_a2s (in, in_len));
3235
3236 saddrs = GNUNET_new (struct Addresses);
3237 saddrs->addr = in;
3238 saddrs->addr_len = in_len;
3239 GNUNET_CONTAINER_DLL_insert (addrs_head, addrs_tail, saddrs);
3240
3241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3242 "after add address %s\n",
3243 GNUNET_a2s (in, in_len));
3244
3245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3246 "add address %s\n",
3247 GNUNET_a2s (saddrs->addr, saddrs->addr_len));
3248
3249 addrs_lens++;
3250}
3251
3252
3253/**
3254 * This method launch network interactions for each address we like to bind to.
3255 *
3256 * @param addr The address we will listen to.
3257 * @param in_len The length of the address we will listen to.
3258 * @return GNUNET_SYSERR in case of error. GNUNET_OK in case we are successfully listen to the address.
3259 */
3260static int
3261init_socket (struct sockaddr *addr,
3262 socklen_t in_len)
3263{
3264 struct sockaddr_storage in_sto;
3265 socklen_t sto_len;
3266 struct GNUNET_NETWORK_Handle *listen_sock;
3267 struct ListenTask *lt;
3268 int sockfd;
3269 struct GNUNET_HashCode h_sock;
3270
3271 if (NULL == addr)
3272 {
3273 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3274 "Address is NULL.\n");
3275 return GNUNET_SYSERR;
3276 }
3277
3278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3279 "address %s\n",
3280 GNUNET_a2s (addr, in_len));
3281
3282 listen_sock =
3283 GNUNET_NETWORK_socket_create (addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
3284 if (NULL == listen_sock)
3285 {
3286 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
3287 return GNUNET_SYSERR;
3288 }
3289
3290 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (listen_sock, addr, in_len))
3291 {
3292 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
3293 GNUNET_NETWORK_socket_close (listen_sock);
3294 listen_sock = NULL;
3295 return GNUNET_SYSERR;
3296 }
3297
3298 if (GNUNET_OK !=
3299 GNUNET_NETWORK_socket_listen (listen_sock,
3300 5))
3301 {
3302 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3303 "listen");
3304 GNUNET_NETWORK_socket_close (listen_sock);
3305 listen_sock = NULL;
3306 return GNUNET_SYSERR;
3307 }
3308
3309 /* We might have bound to port 0, allowing the OS to figure it out;
3310 thus, get the real IN-address from the socket */
3311 sto_len = sizeof(in_sto);
3312
3313 if (0 != getsockname (GNUNET_NETWORK_get_fd (listen_sock),
3314 (struct sockaddr *) &in_sto,
3315 &sto_len))
3316 {
3317 memcpy (&in_sto, addr, in_len);
3318 sto_len = in_len;
3319 }
3320
3321 // addr = (struct sockaddr *) &in_sto;
3322 in_len = sto_len;
3323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3324 "Bound to `%s'\n",
3325 GNUNET_a2s ((const struct sockaddr *) &in_sto, sto_len));
3326 stats = GNUNET_STATISTICS_create ("C-TCP", cfg);
3327
3328 if (NULL == is)
3329 is = GNUNET_NT_scanner_init ();
3330
3331 if (NULL == my_private_key)
3332 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
3333 if (NULL == my_private_key)
3334 {
3335 GNUNET_log (
3336 GNUNET_ERROR_TYPE_ERROR,
3337 _ (
3338 "Transport service is lacking key configuration settings. Exiting.\n"));
3339 if (NULL != resolve_request_handle)
3340 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3341 GNUNET_SCHEDULER_shutdown ();
3342 return GNUNET_SYSERR;
3343 }
3344 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
3345 /* start listening */
3346
3347 lt = GNUNET_new (struct ListenTask);
3348 lt->listen_sock = listen_sock;
3349
3350 lt->listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3351 listen_sock,
3352 &listen_cb,
3353 lt);
3354
3355 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3356 "creating hash\n");
3357 sockfd = GNUNET_NETWORK_get_fd (lt->listen_sock);
3358 GNUNET_CRYPTO_hash (&sockfd,
3359 sizeof(int),
3360 &h_sock);
3361
3362 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3363 "creating map\n");
3364 if (NULL == lt_map)
3365 lt_map = GNUNET_CONTAINER_multihashmap_create (2, GNUNET_NO);
3366
3367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3368 "creating map entry\n");
3369 GNUNET_assert (GNUNET_OK ==
3370 GNUNET_CONTAINER_multihashmap_put (lt_map,
3371 &h_sock,
3372 lt,
3373 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3374
3375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3376 "map entry created\n");
3377
3378 if (NULL == queue_map)
3379 queue_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
3380
3381 if (NULL == ch)
3382 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
3383 COMMUNICATOR_CONFIG_SECTION,
3384 COMMUNICATOR_ADDRESS_PREFIX,
3385 GNUNET_TRANSPORT_CC_RELIABLE,
3386 &mq_init,
3387 NULL,
3388 &enc_notify_cb,
3389 NULL);
3390
3391 if (NULL == ch)
3392 {
3393 GNUNET_break (0);
3394 if (NULL != resolve_request_handle)
3395 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3396 GNUNET_SCHEDULER_shutdown ();
3397 return GNUNET_SYSERR;
3398 }
3399
3400 add_addr (addr, in_len);
3401 return GNUNET_OK;
3402
3403}
3404
3405
3406/**
3407 * This method reads from the DLL addrs_head to register them at the NAT service.
3408 */
3409static void
3410nat_register ()
3411{
3412 struct sockaddr **saddrs;
3413 socklen_t *saddr_lens;
3414 int i;
3415 size_t len;
3416
3417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3418 "starting nat register!\n");
3419 len = 0;
3420 i = 0;
3421 saddrs = GNUNET_malloc ((addrs_lens) * sizeof(struct sockaddr *));
3422 saddr_lens = GNUNET_malloc ((addrs_lens) * sizeof(socklen_t));
3423 for (struct Addresses *pos = addrs_head; NULL != pos; pos = pos->next)
3424 {
3425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3426 "registering address %s\n",
3427 GNUNET_a2s (addrs_head->addr, addrs_head->addr_len));
3428
3429 saddr_lens[i] = addrs_head->addr_len;
3430 len += saddr_lens[i];
3431 saddrs[i] = GNUNET_memdup (addrs_head->addr, saddr_lens[i]);
3432 i++;
3433 }
3434
3435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3436 "registering addresses %lu %lu %lu %lu\n",
3437 (addrs_lens) * sizeof(struct sockaddr *),
3438 (addrs_lens) * sizeof(socklen_t),
3439 len,
3440 sizeof(COMMUNICATOR_CONFIG_SECTION));
3441 nat = GNUNET_NAT_register (cfg,
3442 COMMUNICATOR_CONFIG_SECTION,
3443 IPPROTO_TCP,
3444 addrs_lens,
3445 (const struct sockaddr **) saddrs,
3446 saddr_lens,
3447 &nat_address_cb,
3448 NULL /* FIXME: support reversal: #5529 */,
3449 NULL /* closure */);
3450 for (i = addrs_lens - 1; i >= 0; i--)
3451 GNUNET_free (saddrs[i]);
3452 GNUNET_free (saddrs);
3453 GNUNET_free (saddr_lens);
3454
3455 if (NULL == nat)
3456 {
3457 GNUNET_break (0);
3458 if (NULL != resolve_request_handle)
3459 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3460 GNUNET_SCHEDULER_shutdown ();
3461 }
3462}
3463
3464
3465/**
3466 * This method is the callback called by the resolver API, and wraps method init_socket.
3467 *
3468 * @param cls The port we will bind to.
3469 * @param addr The address we will bind to.
3470 * @param in_len The length of the address we will bind to.
3471 */
3472static void
3473init_socket_resolv (void *cls,
3474 const struct sockaddr *addr,
3475 socklen_t in_len)
3476{
3477 struct sockaddr_in *v4;
3478 struct sockaddr_in6 *v6;
3479 struct sockaddr *in;
3480
3481 (void) cls;
3482 if (NULL != addr)
3483 {
3484 if (AF_INET == addr->sa_family)
3485 {
3486 v4 = (struct sockaddr_in *) addr;
3487 in = tcp_address_to_sockaddr_numeric_v4 (&in_len, *v4, bind_port);// _global);
3488 }
3489 else if (AF_INET6 == addr->sa_family)
3490 {
3491 v6 = (struct sockaddr_in6 *) addr;
3492 in = tcp_address_to_sockaddr_numeric_v6 (&in_len, *v6, bind_port);// _global);
3493 }
3494 else
3495 {
3496 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3497 "Address family %u not suitable (not AF_INET %u nor AF_INET6 %u \n",
3498 addr->sa_family,
3499 AF_INET,
3500 AF_INET6);
3501 return;
3502 }
3503 init_socket (in, in_len);
3504 }
3505 else
3506 {
3507 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3508 "Address is NULL. This might be an error or the resolver finished resolving.\n");
3509 if (NULL == addrs_head)
3510 {
3511 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3512 "Resolver finished resolving, but we do not listen to an address!.\n");
3513 return;
3514 }
3515 nat_register ();
3516 }
3517}
3518
3519
3520/**
3521 * Setup communicator and launch network interactions.
3522 *
3523 * @param cls NULL (always)
3524 * @param args remaining command-line arguments
3525 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
3526 * @param c configuration
3527 */
3528static void
3529run (void *cls,
3530 char *const *args,
3531 const char *cfgfile,
3532 const struct GNUNET_CONFIGURATION_Handle *c)
3533{
3534 char *bindto;
3535 struct sockaddr *in;
3536 socklen_t in_len;
3537 struct sockaddr_in v4;
3538 struct sockaddr_in6 v6;
3539 char *start;
3540 unsigned int port;
3541 char dummy[2];
3542 char *rest = NULL;
3543 struct PortOnlyIpv4Ipv6 *po;
3544 socklen_t addr_len_ipv4;
3545 socklen_t addr_len_ipv6;
3546
3547 (void) cls;
3548 cfg = c;
3549 if (GNUNET_OK !=
3550 GNUNET_CONFIGURATION_get_value_string (cfg,
3551 COMMUNICATOR_CONFIG_SECTION,
3552 "BINDTO",
3553 &bindto))
3554 {
3555 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3556 COMMUNICATOR_CONFIG_SECTION,
3557 "BINDTO");
3558 return;
3559 }
3560 if (GNUNET_OK !=
3561 GNUNET_CONFIGURATION_get_value_number (cfg,
3562 COMMUNICATOR_CONFIG_SECTION,
3563 "MAX_QUEUE_LENGTH",
3564 &max_queue_length))
3565 max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
3566 if (GNUNET_OK !=
3567 GNUNET_CONFIGURATION_get_value_time (cfg,
3568 COMMUNICATOR_CONFIG_SECTION,
3569 "REKEY_INTERVAL",
3570 &rekey_interval))
3571 rekey_interval = DEFAULT_REKEY_INTERVAL;
3572
3573 peerstore = GNUNET_PEERSTORE_connect (cfg);
3574 if (NULL == peerstore)
3575 {
3576 GNUNET_free (bindto);
3577 GNUNET_break (0);
3578 GNUNET_SCHEDULER_shutdown ();
3579 return;
3580 }
3581
3582 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
3583
3584 if (1 == sscanf (bindto, "%u%1s", &bind_port, dummy))
3585 {
3586 po = tcp_address_to_sockaddr_port_only (bindto, &bind_port);
3587 addr_len_ipv4 = po->addr_len_ipv4;
3588 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3589 "address po %s\n",
3590 GNUNET_a2s (po->addr_ipv4, addr_len_ipv4));
3591 if (NULL != po->addr_ipv4)
3592 {
3593 init_socket (po->addr_ipv4, addr_len_ipv4);
3594 }
3595 if (NULL != po->addr_ipv6)
3596 {
3597 addr_len_ipv6 = po->addr_len_ipv6;
3598 init_socket (po->addr_ipv6, addr_len_ipv6);
3599 }
3600 GNUNET_free (po);
3601 nat_register ();
3602 GNUNET_free (bindto);
3603 return;
3604 }
3605
3606 start = extract_address (bindto);
3607 // FIXME: check for NULL == start...
3608 if (1 == inet_pton (AF_INET, start, &v4.sin_addr))
3609 {
3610 bind_port = extract_port (bindto);
3611
3612 in = tcp_address_to_sockaddr_numeric_v4 (&in_len, v4, bind_port);
3613 init_socket (in, in_len);
3614 nat_register ();
3615 GNUNET_free (start);
3616 GNUNET_free (bindto);
3617 return;
3618 }
3619
3620 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
3621 {
3622 bind_port = extract_port (bindto);
3623 in = tcp_address_to_sockaddr_numeric_v6 (&in_len, v6, bind_port);
3624 init_socket (in, in_len);
3625 nat_register ();
3626 GNUNET_free (start);
3627 GNUNET_free (bindto);
3628 return;
3629 }
3630
3631 bind_port = extract_port (bindto);
3632 resolve_request_handle = GNUNET_RESOLVER_ip_get (strtok_r (bindto,
3633 ":",
3634 &rest),
3635 AF_UNSPEC,
3636 GNUNET_TIME_UNIT_MINUTES,
3637 &init_socket_resolv,
3638 &port);
3639 GNUNET_free (bindto);
3640 GNUNET_free (start);
3641}
3642
3643
3644/**
3645 * The main function for the UNIX communicator.
3646 *
3647 * @param argc number of arguments from the command line
3648 * @param argv command line arguments
3649 * @return 0 ok, 1 on error
3650 */
3651int
3652main (int argc, char *const *argv)
3653{
3654 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
3655 GNUNET_GETOPT_OPTION_END
3656 };
3657 int ret;
3658
3659 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
3660 "transport",
3661 "Starting tcp communicator\n");
3662 if (GNUNET_OK !=
3663 GNUNET_STRINGS_get_utf8_args (argc, argv,
3664 &argc, &argv))
3665 return 2;
3666
3667 ret = (GNUNET_OK ==
3668 GNUNET_PROGRAM_run (argc,
3669 argv,
3670 "gnunet-communicator-tcp",
3671 _ ("GNUnet TCP communicator"),
3672 options,
3673 &run,
3674 NULL))
3675 ? 0
3676 : 1;
3677 GNUNET_free_nz ((void *) argv);
3678 return ret;
3679}
3680
3681
3682/* end of gnunet-communicator-tcp.c */
diff --git a/src/transport/gnunet-communicator-udp.c b/src/transport/gnunet-communicator-udp.c
deleted file mode 100644
index 70848ff79..000000000
--- a/src/transport/gnunet-communicator-udp.c
+++ /dev/null
@@ -1,3953 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014, 2018, 2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-communicator-udp.c
23 * @brief Transport plugin using UDP.
24 * @author Christian Grothoff
25 *
26 * TODO:
27 * - consider imposing transmission limits in the absence
28 * of ACKs; or: maybe this should be done at TNG service level?
29 * (at least the receiver might want to enforce limits on
30 * KX/DH operations per sender in here) (#5552)
31 * - overall, we should look more into flow control support
32 * (either in backchannel, or general solution in TNG service)
33 * - handle addresses discovered from broadcasts (#5551)
34 * (think: what was the story again on address validation?
35 * where is the API for that!?!)
36 * - support DNS names in BINDTO option (#5528)
37 * - support NAT connection reversal method (#5529)
38 * - support other UDP-specific NAT traversal methods (#)
39 */
40#include "platform.h"
41#include "gnunet_util_lib.h"
42#include "gnunet_protocols.h"
43#include "gnunet_signatures.h"
44#include "gnunet_constants.h"
45#include "gnunet_nt_lib.h"
46#include "gnunet_nat_service.h"
47#include "gnunet_statistics_service.h"
48#include "gnunet_transport_application_service.h"
49#include "gnunet_transport_communication_service.h"
50
51/**
52 * How often do we rekey based on time (at least)
53 */
54#define DEFAULT_REKEY_TIME_INTERVAL GNUNET_TIME_UNIT_DAYS
55
56/**
57 * How long do we wait until we must have received the initial KX?
58 */
59#define PROTO_QUEUE_TIMEOUT GNUNET_TIME_UNIT_MINUTES
60
61/**
62 * How often do we broadcast our presence on the LAN?
63 */
64#define BROADCAST_FREQUENCY GNUNET_TIME_UNIT_MINUTES
65
66/**
67 * How often do we scan for changes to our network interfaces?
68 */
69#define INTERFACE_SCAN_FREQUENCY \
70 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
71
72/**
73 * How long do we believe our addresses to remain up (before
74 * the other peer should revalidate).
75 */
76#define ADDRESS_VALIDITY_PERIOD GNUNET_TIME_UNIT_HOURS
77
78#define WORKING_QUEUE_INTERVALL \
79 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,1)
80
81/**
82 * AES key size.
83 */
84#define AES_KEY_SIZE (256 / 8)
85
86/**
87 * AES (GCM) IV size.
88 */
89#define AES_IV_SIZE (96 / 8)
90
91/**
92 * Size of the GCM tag.
93 */
94#define GCM_TAG_SIZE (128 / 8)
95
96#define GENERATE_AT_ONCE 2
97
98/**
99 * If we fall below this number of available KCNs,
100 * we generate additional ACKs until we reach
101 * #KCN_TARGET.
102 * Should be large enough that we don't generate ACKs all
103 * the time and still have enough time for the ACK to
104 * arrive before the sender runs out. So really this
105 * should ideally be based on the RTT.
106 */
107#define KCN_THRESHOLD 92
108
109/**
110 * How many KCNs do we keep around *after* we hit
111 * the #KCN_THRESHOLD? Should be larger than
112 * #KCN_THRESHOLD so we do not generate just one
113 * ACK at the time.
114 */
115#define KCN_TARGET 128
116
117/**
118 * What is the maximum delta between KCN sequence numbers
119 * that we allow. Used to expire 'ancient' KCNs that likely
120 * were dropped by the network. Must be larger than
121 * KCN_TARGET (otherwise we generate new KCNs all the time),
122 * but not too large (otherwise packet loss may cause
123 * sender to fall back to KX needlessly when sender runs
124 * out of ACK'ed KCNs due to losses).
125 */
126#define MAX_SQN_DELTA 160
127
128/**
129 * How many shared master secrets do we keep around
130 * at most per sender? Should be large enough so
131 * that we generally have a chance of sending an ACK
132 * before the sender already rotated out the master
133 * secret. Generally values around #KCN_TARGET make
134 * sense. Might make sense to adapt to RTT if we had
135 * a good measurement...
136 */
137#define MAX_SECRETS 128000
138
139/**
140 * Default value for how often we do rekey based on number of bytes transmitted?
141 * (additionally randomized).
142 */
143#define DEFAULT_REKEY_MAX_BYTES (1024LLU * 1024 * 1024 * 4LLU)
144
145/**
146 * Address prefix used by the communicator.
147 */
148
149#define COMMUNICATOR_ADDRESS_PREFIX "udp"
150
151/**
152 * Configuration section used by the communicator.
153 */
154#define COMMUNICATOR_CONFIG_SECTION "communicator-udp"
155
156GNUNET_NETWORK_STRUCT_BEGIN
157
158
159/**
160 * Signature we use to verify that the ephemeral key was really chosen by
161 * the specified sender. If possible, the receiver should respond with
162 * a `struct UDPAck` (possibly via backchannel).
163 */
164struct UdpHandshakeSignature
165{
166 /**
167 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE
168 */
169 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
170
171 /**
172 * Identity of the inititor of the UDP connection (UDP client).
173 */
174 struct GNUNET_PeerIdentity sender;
175
176 /**
177 * Presumed identity of the target of the UDP connection (UDP server)
178 */
179 struct GNUNET_PeerIdentity receiver;
180
181 /**
182 * Ephemeral key used by the @e sender.
183 */
184 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
185
186 /**
187 * Monotonic time of @e sender, to possibly help detect replay attacks
188 * (if receiver persists times by sender).
189 */
190 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
191};
192
193
194/**
195 * "Plaintext" header at beginning of KX message. Followed
196 * by encrypted `struct UDPConfirmation`.
197 */
198struct InitialKX
199{
200 /**
201 * Ephemeral key for KX.
202 */
203 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
204
205 /**
206 * HMAC for the following encrypted message, using GCM. HMAC uses
207 * key derived from the handshake with sequence number zero.
208 */
209 char gcm_tag[GCM_TAG_SIZE];
210
211 /**
212 * A flag indicating, if the sender is doing rekeying.
213 */
214 int rekeying;
215};
216
217
218/**
219 * Encrypted continuation of UDP initial handshake, followed
220 * by message header with payload.
221 */
222struct UDPConfirmation
223{
224 /**
225 * Sender's identity
226 */
227 struct GNUNET_PeerIdentity sender;
228
229 /**
230 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE
231 */
232 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
233
234 /**
235 * Monotonic time of @e sender, to possibly help detect replay attacks
236 * (if receiver persists times by sender).
237 */
238 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
239
240 /* followed by messages */
241
242 /* padding may follow actual messages */
243};
244
245
246/**
247 * UDP key acknowledgement. May be sent via backchannel. Allows the
248 * sender to use `struct UDPBox` with the acknowledge key henceforth.
249 */
250struct UDPAck
251{
252 /**
253 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK.
254 */
255 struct GNUNET_MessageHeader header;
256
257 /**
258 * Sequence acknowledgement limit. Specifies current maximum sequence
259 * number supported by receiver.
260 */
261 uint32_t sequence_max GNUNET_PACKED;
262
263 /**
264 * Sequence acknowledgement limit. Specifies current maximum sequence
265 * number supported by receiver.
266 */
267 uint32_t acks_available GNUNET_PACKED;
268
269 /**
270 * CMAC of the base key being acknowledged.
271 */
272 struct GNUNET_HashCode cmac;
273};
274
275
276/**
277 * Signature we use to verify that the broadcast was really made by
278 * the peer that claims to have made it. Basically, affirms that the
279 * peer is really using this IP address (albeit possibly not in _our_
280 * LAN). Makes it difficult for peers in the LAN to claim to
281 * be just any global peer -- an attacker must have at least
282 * shared a LAN with the peer they're pretending to be here.
283 */
284struct UdpBroadcastSignature
285{
286 /**
287 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST
288 */
289 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
290
291 /**
292 * Identity of the inititor of the UDP broadcast.
293 */
294 struct GNUNET_PeerIdentity sender;
295
296 /**
297 * Hash of the sender's UDP address.
298 */
299 struct GNUNET_HashCode h_address;
300};
301
302
303/**
304 * Broadcast by peer in LAN announcing its presence. Unusual in that
305 * we don't pad these to full MTU, as we cannot prevent being
306 * recognized in LAN as GNUnet peers if this feature is enabled
307 * anyway. Also, the entire message is in cleartext.
308 */
309struct UDPBroadcast
310{
311 /**
312 * Sender's peer identity.
313 */
314 struct GNUNET_PeerIdentity sender;
315
316 /**
317 * Sender's signature of type
318 * #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST
319 */
320 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
321};
322
323
324/**
325 * UDP message box. Always sent encrypted, only allowed after
326 * the receiver sent a `struct UDPAck` for the base key!
327 */
328struct UDPBox
329{
330 /**
331 * Key and IV identification code. KDF applied to an acknowledged
332 * base key and a sequence number. Sequence numbers must be used
333 * monotonically increasing up to the maximum specified in
334 * `struct UDPAck`. Without further `struct UDPAck`s, the sender
335 * must fall back to sending handshakes!
336 */
337 struct GNUNET_ShortHashCode kid;
338
339 /**
340 * 128-bit authentication tag for the following encrypted message,
341 * from GCM. MAC starts at the @e body_start that follows and
342 * extends until the end of the UDP payload. If the @e hmac is
343 * wrong, the receiver should check if the message might be a
344 * `struct UdpHandshakeSignature`.
345 */
346 char gcm_tag[GCM_TAG_SIZE];
347
348 /**
349 * A flag indicating, if the sender is doing rekeying.
350 */
351 int rekeying;
352};
353
354/**
355 * UDP message box. Always sent encrypted, only allowed after
356 * the receiver sent a `struct UDPAck` for the base key!
357 */
358struct UDPRekey
359{
360 /**
361 * Key and IV identification code. KDF applied to an acknowledged
362 * base key and a sequence number. Sequence numbers must be used
363 * monotonically increasing up to the maximum specified in
364 * `struct UDPAck`. Without further `struct UDPAck`s, the sender
365 * must fall back to sending handshakes!
366 */
367 struct GNUNET_ShortHashCode kid;
368
369 /**
370 * 128-bit authentication tag for the following encrypted message,
371 * from GCM. MAC starts at the @e body_start that follows and
372 * extends until the end of the UDP payload. If the @e hmac is
373 * wrong, the receiver should check if the message might be a
374 * `struct UdpHandshakeSignature`.
375 */
376 char gcm_tag[GCM_TAG_SIZE];
377
378 /**
379 * Sender's identity
380 */
381 struct GNUNET_PeerIdentity sender;
382};
383
384GNUNET_NETWORK_STRUCT_END
385
386/**
387 * Shared secret we generated for a particular sender or receiver.
388 */
389struct SharedSecret;
390
391
392/**
393 * Pre-generated "kid" code (key and IV identification code) to
394 * quickly derive master key for a `struct UDPBox`.
395 */
396struct KeyCacheEntry
397{
398 /**
399 * Kept in a DLL.
400 */
401 struct KeyCacheEntry *next;
402
403 /**
404 * Kept in a DLL.
405 */
406 struct KeyCacheEntry *prev;
407
408 /**
409 * Key and IV identification code. KDF applied to an acknowledged
410 * base key and a sequence number. Sequence numbers must be used
411 * monotonically increasing up to the maximum specified in
412 * `struct UDPAck`. Without further `struct UDPAck`s, the sender
413 * must fall back to sending handshakes!
414 */
415 struct GNUNET_ShortHashCode kid;
416
417 /**
418 * Corresponding shared secret.
419 */
420 struct SharedSecret *ss;
421
422 /**
423 * Sequence number used to derive this entry from master key.
424 */
425 uint32_t sequence_number;
426};
427
428
429/**
430 * Information we track per sender address we have recently been
431 * in contact with (decryption from sender).
432 */
433struct SenderAddress;
434
435/**
436 * Information we track per receiving address we have recently been
437 * in contact with (encryption to receiver).
438 */
439struct ReceiverAddress;
440
441/**
442 * Shared secret we generated for a particular sender or receiver.
443 */
444struct SharedSecret
445{
446 /**
447 * Kept in a DLL.
448 */
449 struct SharedSecret *next;
450
451 /**
452 * Kept in a DLL.
453 */
454 struct SharedSecret *prev;
455
456 /**
457 * Kept in a DLL, sorted by sequence number. Only if we are decrypting.
458 */
459 struct KeyCacheEntry *kce_head;
460
461 /**
462 * Kept in a DLL, sorted by sequence number. Only if we are decrypting.
463 */
464 struct KeyCacheEntry *kce_tail;
465
466 /**
467 * Sender we use this shared secret with, or NULL.
468 */
469 struct SenderAddress *sender;
470
471 /**
472 * Receiver we use this shared secret with, or NULL.
473 */
474 struct ReceiverAddress *receiver;
475
476 /**
477 * Master shared secret.
478 */
479 struct GNUNET_HashCode master;
480
481 /**
482 * CMAC is used to identify @e master in ACKs.
483 */
484 struct GNUNET_HashCode cmac;
485
486 /**
487 * Up to which sequence number did we use this @e master already?
488 * (for encrypting only)
489 */
490 uint32_t sequence_used;
491
492 /**
493 * Up to which sequence number did the other peer allow us to use
494 * this key, or up to which number did we allow the other peer to
495 * use this key?
496 */
497 uint32_t sequence_allowed;
498
499 /**
500 * Number of active KCN entries.
501 */
502 unsigned int active_kce_count;
503};
504
505
506/**
507 * Information we track per sender address we have recently been
508 * in contact with (we decrypt messages from the sender).
509 */
510struct SenderAddress
511{
512 /**
513 * Shared secret we use with @e target for rekeying.
514 */
515 struct SharedSecret *ss_rekey;
516
517 /**
518 * Flag indicating sender is initiated rekeying for this receiver.
519 */
520 int rekeying;
521
522 /**
523 * To whom are we talking to.
524 */
525 struct GNUNET_PeerIdentity target;
526
527 /**
528 * Entry in sender expiration heap.
529 */
530 struct GNUNET_CONTAINER_HeapNode *hn;
531
532 /**
533 * Shared secrets we used with @e target, first used is head.
534 */
535 struct SharedSecret *ss_head;
536
537 /**
538 * Shared secrets we used with @e target, last used is tail.
539 */
540 struct SharedSecret *ss_tail;
541
542 /**
543 * Address of the other peer.
544 */
545 struct sockaddr *address;
546
547 /**
548 * Length of the address.
549 */
550 socklen_t address_len;
551
552 /**
553 * Timeout for this sender.
554 */
555 struct GNUNET_TIME_Absolute timeout;
556
557 /**
558 * Length of the DLL at @a ss_head.
559 */
560 unsigned int num_secrets;
561
562 /**
563 * Number of BOX keys from ACKs we have currently
564 * available for this sender.
565 */
566 unsigned int acks_available;
567
568 /**
569 * Which network type does this queue use?
570 */
571 enum GNUNET_NetworkType nt;
572
573 /**
574 * sender_destroy already called on sender.
575 */
576 int sender_destroy_called;
577
578
579 /**
580 * ID of kce working queue task
581 */
582 struct GNUNET_SCHEDULER_Task *kce_task;
583
584 /**
585 * ID of kce rekey working queue task
586 */
587 struct GNUNET_SCHEDULER_Task *kce_task_rekey;
588
589 /**
590 * Is the kce_task finished?
591 */
592 int kce_task_finished;
593};
594
595
596/**
597 * Information we track per receiving address we have recently been
598 * in contact with (encryption to receiver).
599 */
600struct ReceiverAddress
601{
602
603 /**
604 * Shared secret we use with @e target for rekeying.
605 */
606 struct SharedSecret *ss_rekey;
607
608 /**
609 * Acks available when we started rekeying.
610 */
611 unsigned int rekey_acks_available;
612
613 /**
614 * Send bytes for this receiver address.
615 */
616 uint64_t rekey_send_bytes;
617
618 /**
619 * Timeout for this receiver address.
620 */
621 struct GNUNET_TIME_Absolute rekey_timeout;
622
623 /**
624 * Flag indicating sender is initiated rekeying for this receiver.
625 */
626 int rekeying;
627
628 /**
629 * Number of kce we retain for sending the rekeying shared secret.
630 */
631 int number_rekeying_kce;
632
633 /**
634 * To whom are we talking to.
635 */
636 struct GNUNET_PeerIdentity target;
637
638 /**
639 * Shared secrets we received from @e target, first used is head.
640 */
641 struct SharedSecret *ss_head;
642
643 /**
644 * Shared secrets we received with @e target, last used is tail.
645 */
646 struct SharedSecret *ss_tail;
647
648 /**
649 * Address of the receiver in the human-readable format
650 * with the #COMMUNICATOR_ADDRESS_PREFIX.
651 */
652 char *foreign_addr;
653
654 /**
655 * Address of the other peer.
656 */
657 struct sockaddr *address;
658
659 /**
660 * Length of the address.
661 */
662 socklen_t address_len;
663
664 /**
665 * Entry in sender expiration heap.
666 */
667 struct GNUNET_CONTAINER_HeapNode *hn;
668
669 /**
670 * KX message queue we are providing for the #ch.
671 */
672 struct GNUNET_MQ_Handle *kx_mq;
673
674 /**
675 * Default message queue we are providing for the #ch.
676 */
677 struct GNUNET_MQ_Handle *d_mq;
678
679 /**
680 * handle for KX queue with the #ch.
681 */
682 struct GNUNET_TRANSPORT_QueueHandle *kx_qh;
683
684 /**
685 * handle for default queue with the #ch.
686 */
687 struct GNUNET_TRANSPORT_QueueHandle *d_qh;
688
689 /**
690 * Timeout for this receiver address.
691 */
692 struct GNUNET_TIME_Absolute timeout;
693
694 /**
695 * MTU we allowed transport for this receiver's KX queue.
696 */
697 size_t kx_mtu;
698
699 /**
700 * MTU we allowed transport for this receiver's default queue.
701 */
702 size_t d_mtu;
703
704 /**
705 * Length of the DLL at @a ss_head.
706 */
707 unsigned int num_secrets;
708
709 /**
710 * Number of BOX keys from ACKs we have currently
711 * available for this receiver.
712 */
713 unsigned int acks_available;
714
715 /**
716 * Which network type does this queue use?
717 */
718 enum GNUNET_NetworkType nt;
719
720 /**
721 * receiver_destroy already called on receiver.
722 */
723 int receiver_destroy_called;
724};
725
726/**
727 * Interface we broadcast our presence on.
728 */
729struct BroadcastInterface
730{
731 /**
732 * Kept in a DLL.
733 */
734 struct BroadcastInterface *next;
735
736 /**
737 * Kept in a DLL.
738 */
739 struct BroadcastInterface *prev;
740
741 /**
742 * Task for this broadcast interface.
743 */
744 struct GNUNET_SCHEDULER_Task *broadcast_task;
745
746 /**
747 * Sender's address of the interface.
748 */
749 struct sockaddr *sa;
750
751 /**
752 * Broadcast address to use on the interface.
753 */
754 struct sockaddr *ba;
755
756 /**
757 * Message we broadcast on this interface.
758 */
759 struct UDPBroadcast bcm;
760
761 /**
762 * If this is an IPv6 interface, this is the request
763 * we use to join/leave the group.
764 */
765 struct ipv6_mreq mcreq;
766
767 /**
768 * Number of bytes in @e sa.
769 */
770 socklen_t salen;
771
772 /**
773 * Was this interface found in the last #iface_proc() scan?
774 */
775 int found;
776};
777
778/**
779 * The rekey interval
780 */
781static struct GNUNET_TIME_Relative rekey_interval;
782
783/**
784 * How often we do rekey based on number of bytes transmitted
785 */
786static unsigned long long rekey_max_bytes;
787/**
788 * Shared secret we finished the last kce working queue for.
789 */
790struct SharedSecret *ss_finished;
791
792/**
793 * Cache of pre-generated key IDs.
794 */
795static struct GNUNET_CONTAINER_MultiShortmap *key_cache;
796
797/**
798 * ID of read task
799 */
800static struct GNUNET_SCHEDULER_Task *read_task;
801
802/**
803 * ID of timeout task
804 */
805static struct GNUNET_SCHEDULER_Task *timeout_task;
806
807/**
808 * ID of master broadcast task
809 */
810static struct GNUNET_SCHEDULER_Task *broadcast_task;
811
812/**
813 * For logging statistics.
814 */
815static struct GNUNET_STATISTICS_Handle *stats;
816
817/**
818 * Our environment.
819 */
820static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
821
822/**
823 * Receivers (map from peer identity to `struct ReceiverAddress`)
824 */
825static struct GNUNET_CONTAINER_MultiPeerMap *receivers;
826
827/**
828 * Senders (map from peer identity to `struct SenderAddress`)
829 */
830static struct GNUNET_CONTAINER_MultiPeerMap *senders;
831
832/**
833 * Expiration heap for senders (contains `struct SenderAddress`)
834 */
835static struct GNUNET_CONTAINER_Heap *senders_heap;
836
837/**
838 * Expiration heap for receivers (contains `struct ReceiverAddress`)
839 */
840static struct GNUNET_CONTAINER_Heap *receivers_heap;
841
842/**
843 * Broadcast interface tasks. Kept in a DLL.
844 */
845static struct BroadcastInterface *bi_head;
846
847/**
848 * Broadcast interface tasks. Kept in a DLL.
849 */
850static struct BroadcastInterface *bi_tail;
851
852/**
853 * Our socket.
854 */
855static struct GNUNET_NETWORK_Handle *udp_sock;
856
857/**
858 * #GNUNET_YES if #udp_sock supports IPv6.
859 */
860static int have_v6_socket;
861
862/**
863 * Our public key.
864 */
865static struct GNUNET_PeerIdentity my_identity;
866
867/**
868 * Our private key.
869 */
870static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
871
872/**
873 * Our configuration.
874 */
875static const struct GNUNET_CONFIGURATION_Handle *cfg;
876
877/**
878 * Our handle to report addresses for validation to TRANSPORT.
879 */
880static struct GNUNET_TRANSPORT_ApplicationHandle *ah;
881
882/**
883 * Network scanner to determine network types.
884 */
885static struct GNUNET_NT_InterfaceScanner *is;
886
887/**
888 * Connection to NAT service.
889 */
890static struct GNUNET_NAT_Handle *nat;
891
892/**
893 * Port number to which we are actually bound.
894 */
895static uint16_t my_port;
896
897
898/**
899 * An interface went away, stop broadcasting on it.
900 *
901 * @param bi entity to close down
902 */
903static void
904bi_destroy (struct BroadcastInterface *bi)
905{
906 if (AF_INET6 == bi->sa->sa_family)
907 {
908 /* Leave the multicast group */
909 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
910 IPPROTO_IPV6,
911 IPV6_LEAVE_GROUP,
912 &bi->mcreq,
913 sizeof(bi->mcreq)))
914 {
915 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
916 }
917 }
918 GNUNET_CONTAINER_DLL_remove (bi_head, bi_tail, bi);
919 GNUNET_SCHEDULER_cancel (bi->broadcast_task);
920 GNUNET_free (bi->sa);
921 GNUNET_free (bi->ba);
922 GNUNET_free (bi);
923}
924
925
926/**
927 * Destroys a receiving state due to timeout or shutdown.
928 *
929 * @param receiver entity to close down
930 */
931static void
932receiver_destroy (struct ReceiverAddress *receiver)
933{
934
935 receiver->receiver_destroy_called = GNUNET_YES;
936
937 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
938 "Disconnecting receiver for peer `%s'\n",
939 GNUNET_i2s (&receiver->target));
940 /*if (NULL != (mq = receiver->kx_mq))
941 {
942 receiver->kx_mq = NULL;
943 GNUNET_MQ_destroy (mq);
944 }*/
945 if (NULL != receiver->kx_qh)
946 {
947 GNUNET_TRANSPORT_communicator_mq_del (receiver->kx_qh);
948 receiver->kx_qh = NULL;
949 receiver->kx_mq = NULL;
950 }
951 /*if (NULL != (mq = receiver->d_mq))
952 {
953 receiver->d_mq = NULL;
954 GNUNET_MQ_destroy (mq);
955 }*/
956 if (NULL != receiver->d_qh)
957 {
958 GNUNET_TRANSPORT_communicator_mq_del (receiver->d_qh);
959 receiver->d_qh = NULL;
960 }
961 GNUNET_assert (GNUNET_YES ==
962 GNUNET_CONTAINER_multipeermap_remove (receivers,
963 &receiver->target,
964 receiver));
965 GNUNET_assert (receiver == GNUNET_CONTAINER_heap_remove_node (receiver->hn));
966 GNUNET_STATISTICS_set (stats,
967 "# receivers active",
968 GNUNET_CONTAINER_multipeermap_size (receivers),
969 GNUNET_NO);
970 GNUNET_free (receiver->address);
971 GNUNET_free (receiver->foreign_addr);
972 GNUNET_free (receiver);
973}
974
975
976/**
977 * Free memory used by key cache entry.
978 *
979 * @param kce the key cache entry
980 */
981static void
982kce_destroy (struct KeyCacheEntry *kce)
983{
984 struct SharedSecret *ss = kce->ss;
985
986 ss->active_kce_count--;
987 ss->sender->acks_available--;
988 GNUNET_CONTAINER_DLL_remove (ss->kce_head, ss->kce_tail, kce);
989 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multishortmap_remove (key_cache,
990 &kce->kid,
991 kce));
992 GNUNET_free (kce);
993}
994
995
996/**
997 * Compute @a kid.
998 *
999 * @param msec master secret for HMAC calculation
1000 * @param serial number for the @a smac calculation
1001 * @param kid[out] where to write the key ID
1002 */
1003static void
1004get_kid (const struct GNUNET_HashCode *msec,
1005 uint32_t serial,
1006 struct GNUNET_ShortHashCode *kid)
1007{
1008 uint32_t sid = htonl (serial);
1009
1010 GNUNET_CRYPTO_hkdf (kid,
1011 sizeof(*kid),
1012 GCRY_MD_SHA512,
1013 GCRY_MD_SHA256,
1014 &sid,
1015 sizeof(sid),
1016 msec,
1017 sizeof(*msec),
1018 "UDP-KID",
1019 strlen ("UDP-KID"),
1020 NULL,
1021 0);
1022}
1023
1024
1025/**
1026 * Setup key cache entry for sequence number @a seq and shared secret @a ss.
1027 *
1028 * @param ss shared secret
1029 * @param seq sequence number for the key cache entry
1030 */
1031static void
1032kce_generate (struct SharedSecret *ss, uint32_t seq)
1033{
1034 struct KeyCacheEntry *kce;
1035
1036 GNUNET_assert (0 < seq);
1037 kce = GNUNET_new (struct KeyCacheEntry);
1038 kce->ss = ss;
1039 kce->sequence_number = seq;
1040 get_kid (&ss->master, seq, &kce->kid);
1041 GNUNET_CONTAINER_DLL_insert (ss->kce_head, ss->kce_tail, kce);
1042 ss->active_kce_count++;
1043 ss->sender->acks_available++;
1044 (void) GNUNET_CONTAINER_multishortmap_put (
1045 key_cache,
1046 &kce->kid,
1047 kce,
1048 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1049 GNUNET_STATISTICS_set (stats,
1050 "# KIDs active",
1051 GNUNET_CONTAINER_multishortmap_size (key_cache),
1052 GNUNET_NO);
1053}
1054
1055
1056/**
1057 * Destroy @a ss and associated key cache entries.
1058 *
1059 * @param ss shared secret to destroy
1060 * @param withoutKce If GNUNET_YES shared secrets with kce will not be destroyed.
1061 */
1062static int
1063secret_destroy (struct SharedSecret *ss, int withoutKce)
1064{
1065 struct SenderAddress *sender;
1066 struct ReceiverAddress *receiver;
1067 struct KeyCacheEntry *kce;
1068
1069 if (withoutKce && (ss->sequence_allowed > 0))
1070 return GNUNET_NO;
1071
1072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1073 "secret %s destroy %u %u\n",
1074 GNUNET_h2s (&ss->master),
1075 withoutKce,
1076 ss->sequence_allowed);
1077 if (NULL != (sender = ss->sender))
1078 {
1079 GNUNET_CONTAINER_DLL_remove (sender->ss_head, sender->ss_tail, ss);
1080 sender->num_secrets--;
1081 }
1082 if (NULL != (receiver = ss->receiver))
1083 {
1084 GNUNET_CONTAINER_DLL_remove (receiver->ss_head, receiver->ss_tail, ss);
1085 receiver->num_secrets--;
1086 // Uncomment this for alternativ 1 of backchannel functionality
1087 receiver->acks_available -= (ss->sequence_allowed - ss->sequence_used);
1088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1089 "%u receiver->acks_available 3\n",
1090 receiver->acks_available);
1091 // Until here for alternativ 1
1092 }
1093 while (NULL != (kce = ss->kce_head))
1094 kce_destroy (kce);
1095 GNUNET_STATISTICS_update (stats, "# Secrets active", -1, GNUNET_NO);
1096 GNUNET_STATISTICS_set (stats,
1097 "# KIDs active",
1098 GNUNET_CONTAINER_multishortmap_size (key_cache),
1099 GNUNET_NO);
1100 GNUNET_free (ss);
1101 return GNUNET_YES;
1102}
1103
1104
1105/**
1106 * Functions with this signature are called whenever we need
1107 * to close a sender's state due to timeout.
1108 *
1109 * @param sender entity to close down
1110 */
1111static void
1112sender_destroy (struct SenderAddress *sender)
1113{
1114 sender->sender_destroy_called = GNUNET_YES;
1115 GNUNET_assert (
1116 GNUNET_YES ==
1117 GNUNET_CONTAINER_multipeermap_remove (senders, &sender->target, sender));
1118 GNUNET_assert (sender == GNUNET_CONTAINER_heap_remove_node (sender->hn));
1119 GNUNET_STATISTICS_set (stats,
1120 "# senders active",
1121 GNUNET_CONTAINER_multipeermap_size (senders),
1122 GNUNET_NO);
1123 GNUNET_free (sender->address);
1124 GNUNET_free (sender);
1125}
1126
1127
1128/**
1129 * Compute @a key and @a iv.
1130 *
1131 * @param msec master secret for calculation
1132 * @param serial number for the @a smac calculation
1133 * @param key[out] where to write the decryption key
1134 * @param iv[out] where to write the IV
1135 */
1136static void
1137get_iv_key (const struct GNUNET_HashCode *msec,
1138 uint32_t serial,
1139 char key[AES_KEY_SIZE],
1140 char iv[AES_IV_SIZE])
1141{
1142 uint32_t sid = htonl (serial);
1143 char res[AES_KEY_SIZE + AES_IV_SIZE];
1144
1145 GNUNET_CRYPTO_hkdf (res,
1146 sizeof(res),
1147 GCRY_MD_SHA512,
1148 GCRY_MD_SHA256,
1149 &sid,
1150 sizeof(sid),
1151 msec,
1152 sizeof(*msec),
1153 "UDP-IV-KEY",
1154 strlen ("UDP-IV-KEY"),
1155 NULL,
1156 0);
1157 memcpy (key, res, AES_KEY_SIZE);
1158 memcpy (iv, &res[AES_KEY_SIZE], AES_IV_SIZE);
1159}
1160
1161
1162/**
1163 * Increment sender timeout due to activity.
1164 *
1165 * @param sender address for which the timeout should be rescheduled
1166 */
1167static void
1168reschedule_sender_timeout (struct SenderAddress *sender)
1169{
1170 sender->timeout =
1171 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1172 GNUNET_CONTAINER_heap_update_cost (sender->hn, sender->timeout.abs_value_us);
1173}
1174
1175
1176/**
1177 * Increment receiver timeout due to activity.
1178 *
1179 * @param receiver address for which the timeout should be rescheduled
1180 */
1181static void
1182reschedule_receiver_timeout (struct ReceiverAddress *receiver)
1183{
1184 receiver->timeout =
1185 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1186 GNUNET_CONTAINER_heap_update_cost (receiver->hn,
1187 receiver->timeout.abs_value_us);
1188}
1189
1190
1191/**
1192 * Task run to check #receiver_heap and #sender_heap for timeouts.
1193 *
1194 * @param cls unused, NULL
1195 */
1196static void
1197check_timeouts (void *cls)
1198{
1199 struct GNUNET_TIME_Relative st;
1200 struct GNUNET_TIME_Relative rt;
1201 struct GNUNET_TIME_Relative delay;
1202 struct ReceiverAddress *receiver;
1203 struct SenderAddress *sender;
1204
1205 (void) cls;
1206 timeout_task = NULL;
1207 rt = GNUNET_TIME_UNIT_FOREVER_REL;
1208 while (NULL != (receiver = GNUNET_CONTAINER_heap_peek (receivers_heap)))
1209 {
1210 /* if (GNUNET_YES != receiver->receiver_destroy_called) */
1211 /* { */
1212 rt = GNUNET_TIME_absolute_get_remaining (receiver->timeout);
1213 if (0 != rt.rel_value_us)
1214 break;
1215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1216 "Receiver timed out\n");
1217 receiver_destroy (receiver);
1218 // }
1219 }
1220 st = GNUNET_TIME_UNIT_FOREVER_REL;
1221 while (NULL != (sender = GNUNET_CONTAINER_heap_peek (senders_heap)))
1222 {
1223 if (GNUNET_YES != sender->sender_destroy_called)
1224 {
1225 st = GNUNET_TIME_absolute_get_remaining (sender->timeout);
1226 if (0 != st.rel_value_us)
1227 break;
1228 sender_destroy (sender);
1229 }
1230 }
1231 delay = GNUNET_TIME_relative_min (rt, st);
1232 if (delay.rel_value_us < GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1233 timeout_task = GNUNET_SCHEDULER_add_delayed (delay, &check_timeouts, NULL);
1234}
1235
1236
1237/**
1238 * Calculate cmac from master in @a ss.
1239 *
1240 * @param ss[in,out] data structure to complete
1241 */
1242static void
1243calculate_cmac (struct SharedSecret *ss)
1244{
1245 GNUNET_CRYPTO_hkdf (&ss->cmac,
1246 sizeof(ss->cmac),
1247 GCRY_MD_SHA512,
1248 GCRY_MD_SHA256,
1249 "CMAC",
1250 strlen ("CMAC"),
1251 &ss->master,
1252 sizeof(ss->master),
1253 "UDP-CMAC",
1254 strlen ("UDP-CMAC"),
1255 NULL,
1256 0);
1257}
1258
1259
1260/**
1261 * We received @a plaintext_len bytes of @a plaintext from a @a sender.
1262 * Pass it on to CORE.
1263 *
1264 * @param queue the queue that received the plaintext
1265 * @param plaintext the plaintext that was received
1266 * @param plaintext_len number of bytes of plaintext received
1267 */
1268static void
1269pass_plaintext_to_core (struct SenderAddress *sender,
1270 const void *plaintext,
1271 size_t plaintext_len)
1272{
1273 const struct GNUNET_MessageHeader *hdr = plaintext;
1274 const char *pos = plaintext;
1275
1276 while (ntohs (hdr->size) <= plaintext_len)
1277 {
1278 GNUNET_STATISTICS_update (stats,
1279 "# bytes given to core",
1280 ntohs (hdr->size),
1281 GNUNET_NO);
1282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1283 "Giving %u bytes to TNG\n", ntohs (hdr->size));
1284 GNUNET_assert (GNUNET_SYSERR !=
1285 GNUNET_TRANSPORT_communicator_receive (ch,
1286 &sender->target,
1287 hdr,
1288 ADDRESS_VALIDITY_PERIOD,
1289 NULL /* no flow control possible */
1290 ,
1291 NULL));
1292 /* move on to next message, if any */
1293 plaintext_len -= ntohs (hdr->size);
1294 if (plaintext_len < sizeof(*hdr))
1295 break;
1296 pos += ntohs (hdr->size);
1297 hdr = (const struct GNUNET_MessageHeader *) pos;
1298 // TODO for now..., we do not actually sen >1msg or have a way of telling
1299 // if we are done
1300 break;
1301 }
1302 GNUNET_STATISTICS_update (stats,
1303 "# bytes padding discarded",
1304 plaintext_len,
1305 GNUNET_NO);
1306}
1307
1308
1309/**
1310 * Setup @a cipher based on shared secret @a msec and
1311 * serial number @a serial.
1312 *
1313 * @param msec master shared secret
1314 * @param serial serial number of cipher to set up
1315 * @param cipher[out] cipher to initialize
1316 */
1317static void
1318setup_cipher (const struct GNUNET_HashCode *msec,
1319 uint32_t serial,
1320 gcry_cipher_hd_t *cipher)
1321{
1322 char key[AES_KEY_SIZE];
1323 char iv[AES_IV_SIZE];
1324 int rc;
1325
1326 GNUNET_assert (0 ==
1327 gcry_cipher_open (cipher,
1328 GCRY_CIPHER_AES256 /* low level: go for speed */,
1329 GCRY_CIPHER_MODE_GCM,
1330 0 /* flags */));
1331 get_iv_key (msec, serial, key, iv);
1332 rc = gcry_cipher_setkey (*cipher, key, sizeof(key));
1333 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
1334 rc = gcry_cipher_setiv (*cipher, iv, sizeof(iv));
1335 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
1336}
1337
1338
1339/**
1340 * Try to decrypt @a buf using shared secret @a ss and key/iv
1341 * derived using @a serial.
1342 *
1343 * @param ss shared secret
1344 * @param tag GCM authentication tag
1345 * @param serial serial number to use
1346 * @param in_buf input buffer to decrypt
1347 * @param in_buf_size number of bytes in @a in_buf and available in @a out_buf
1348 * @param out_buf where to write the result
1349 * @return #GNUNET_OK on success
1350 */
1351static int
1352try_decrypt (const struct SharedSecret *ss,
1353 const char tag[GCM_TAG_SIZE],
1354 uint32_t serial,
1355 const char *in_buf,
1356 size_t in_buf_size,
1357 char *out_buf)
1358{
1359 gcry_cipher_hd_t cipher;
1360
1361 setup_cipher (&ss->master, serial, &cipher);
1362 GNUNET_assert (
1363 0 ==
1364 gcry_cipher_decrypt (cipher, out_buf, in_buf_size, in_buf, in_buf_size));
1365 if (0 != gcry_cipher_checktag (cipher, tag, GCM_TAG_SIZE))
1366 {
1367 gcry_cipher_close (cipher);
1368 GNUNET_STATISTICS_update (stats,
1369 "# AEAD authentication failures",
1370 1,
1371 GNUNET_NO);
1372 return GNUNET_SYSERR;
1373 }
1374 gcry_cipher_close (cipher);
1375 return GNUNET_OK;
1376}
1377
1378
1379/**
1380 * Setup shared secret for decryption.
1381 *
1382 * @param ephemeral ephemeral key we received from the other peer
1383 * @return new shared secret
1384 */
1385static struct SharedSecret *
1386setup_shared_secret_dec (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral)
1387{
1388 struct SharedSecret *ss;
1389
1390 ss = GNUNET_new (struct SharedSecret);
1391 GNUNET_CRYPTO_eddsa_ecdh (my_private_key, ephemeral, &ss->master);
1392 return ss;
1393}
1394
1395
1396/**
1397 * Setup shared secret for encryption.
1398 *
1399 * @param ephemeral ephemeral key we are sending to the other peer
1400 * @param receiver[in,out] queue to initialize encryption key for
1401 * @return new shared secret
1402 */
1403static struct SharedSecret *
1404setup_shared_secret_enc (const struct GNUNET_CRYPTO_EcdhePrivateKey *ephemeral,
1405 struct ReceiverAddress *receiver, int add_to_receiver)
1406{
1407 struct SharedSecret *ss;
1408
1409 ss = GNUNET_new (struct SharedSecret);
1410 GNUNET_CRYPTO_ecdh_eddsa (ephemeral,
1411 &receiver->target.public_key,
1412 &ss->master);
1413 calculate_cmac (ss);
1414 ss->receiver = receiver;
1415 GNUNET_CONTAINER_DLL_insert (receiver->ss_head, receiver->ss_tail, ss);
1416 receiver->num_secrets++;
1417 GNUNET_STATISTICS_update (stats, "# Secrets active", 1, GNUNET_NO);
1418 return ss;
1419}
1420
1421
1422/**
1423 * Setup the MQ for the @a receiver. If a queue exists,
1424 * the existing one is destroyed. Then the MTU is
1425 * recalculated and a fresh queue is initialized.
1426 *
1427 * @param receiver receiver to setup MQ for
1428 */
1429static void
1430setup_receiver_mq (struct ReceiverAddress *receiver);
1431
1432/**
1433 * Destroying all secrets. Depending on parameter we keep those secrets having a kce.
1434 *
1435 * @param ss The secret we will not destroy.
1436 * @param withoutKce If GNUNET_YES shared secrets with kce will not be destroyed.
1437 */
1438static void
1439destroy_all_secrets (struct SharedSecret *ss, int withoutKce)
1440{
1441 struct SenderAddress *sender;
1442 struct ReceiverAddress *receiver;
1443 struct SharedSecret *ss_to_destroy;
1444 struct SharedSecret *ss_start;
1445 struct SharedSecret *pos;
1446 int at_least_one_destroyed = GNUNET_NO;
1447
1448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1449 "Starting destroy all withoutKce: %u.\n",
1450 withoutKce);
1451
1452 if (NULL != (sender = ss->sender))
1453 {
1454 ss_start = sender->ss_head;
1455 }
1456 else if (NULL != (receiver = ss->receiver))
1457 {
1458 ss_start = receiver->ss_head;
1459 }
1460 else
1461 {
1462 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1463 "Shared secret has no sender or receiver!\n");
1464 return;
1465 }
1466
1467 pos = ss_start;
1468 while (NULL != pos)
1469 {
1470 ss_to_destroy = pos;
1471 pos = pos->next;
1472
1473 if (ss != ss_to_destroy)
1474 at_least_one_destroyed = secret_destroy (ss_to_destroy, withoutKce);
1475 }
1476
1477 if ((ss != ss_start) && ! at_least_one_destroyed)
1478 {
1479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1480 "Really destroying all.\n");
1481 destroy_all_secrets (ss_start, GNUNET_NO);
1482 }
1483
1484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1485 "Finished destroy all.\n");
1486}
1487
1488
1489static void
1490add_acks (struct SharedSecret *ss, int acks_to_add)
1491{
1492
1493 struct ReceiverAddress *receiver = ss->receiver;
1494
1495 GNUNET_assert (NULL != ss);
1496 GNUNET_assert (NULL != receiver);
1497
1498 if (NULL == receiver->d_qh)
1499 {
1500 receiver->d_qh =
1501 GNUNET_TRANSPORT_communicator_mq_add (ch,
1502 &receiver->target,
1503 receiver->foreign_addr,
1504 receiver->d_mtu,
1505 acks_to_add,
1506 1, /* Priority */
1507 receiver->nt,
1508 GNUNET_TRANSPORT_CS_OUTBOUND,
1509 receiver->d_mq);
1510 }
1511 else
1512 {
1513 GNUNET_TRANSPORT_communicator_mq_update (ch,
1514 receiver->d_qh,
1515 acks_to_add,
1516 1);
1517 }
1518
1519 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1520 "Tell transport we have %u more acks!\n",
1521 acks_to_add);
1522 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1523 "%u kce for rekeying.\n",
1524 receiver->number_rekeying_kce);
1525
1526 // Until here for alternativ 1
1527
1528 /* move ss to head to avoid discarding it anytime soon! */
1529
1530 GNUNET_CONTAINER_DLL_remove (receiver->ss_head, receiver->ss_tail, ss);
1531 GNUNET_CONTAINER_DLL_insert (receiver->ss_head, receiver->ss_tail, ss);
1532 destroy_all_secrets (ss, GNUNET_YES);
1533}
1534
1535
1536static uint32_t
1537reset_rekey_kces (struct ReceiverAddress *receiver,
1538 uint32_t acks_to_add)
1539{
1540 int needed_for_rekeying;
1541
1542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1543 "%u kce for rekeying and %u acks_to_add\n",
1544 receiver->number_rekeying_kce,
1545 acks_to_add);
1546
1547 needed_for_rekeying = (3 - receiver->number_rekeying_kce);
1548 if (acks_to_add <= needed_for_rekeying)
1549 {
1550 receiver->number_rekeying_kce += acks_to_add;
1551 acks_to_add = 0;
1552 }
1553 else
1554 {
1555 acks_to_add -= (3 - receiver->number_rekeying_kce);
1556 receiver->number_rekeying_kce = 3;
1557 }
1558
1559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1560 "%u kce for rekeying and %u acks_to_add\n",
1561 receiver->number_rekeying_kce,
1562 acks_to_add);
1563 return acks_to_add;
1564}
1565
1566
1567static void
1568add_acks_rekey (struct ReceiverAddress *receiver)
1569{
1570 uint32_t acks_to_add = receiver->ss_rekey->sequence_allowed;
1571
1572 if (receiver->number_rekeying_kce < 3)
1573 acks_to_add = reset_rekey_kces (receiver, acks_to_add);
1574 receiver->acks_available = receiver->ss_rekey->sequence_allowed;
1575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1576 "%u receiver->acks_available 4\n",
1577 receiver->acks_available);
1578 /* add_acks (receiver->ss_rekey, acks_to_add - 3); */
1579 if (0 != acks_to_add)
1580 {
1581 add_acks (receiver->ss_rekey, acks_to_add);
1582 }
1583 receiver->ss_rekey = NULL;
1584 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1585 "# rekeying successful\n");
1586 GNUNET_STATISTICS_update (stats,
1587 "# rekeying successful",
1588 1,
1589 GNUNET_NO);
1590}
1591
1592
1593/**
1594 * We received an ACK for @a pid. Check if it is for
1595 * the receiver in @a value and if so, handle it and
1596 * return #GNUNET_NO. Otherwise, return #GNUNET_YES.
1597 *
1598 * @param cls a `const struct UDPAck`
1599 * @param pid peer the ACK is from
1600 * @param value a `struct ReceiverAddress`
1601 * @return #GNUNET_YES to continue to iterate
1602 */
1603static int
1604handle_ack (void *cls, const struct GNUNET_PeerIdentity *pid, void *value)
1605{
1606 const struct UDPAck *ack = cls;
1607 struct ReceiverAddress *receiver = value;
1608 uint32_t acks_to_add;
1609 uint32_t allowed;
1610 // int needed_for_rekeying;
1611
1612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1613 "in handle ack with cmac %s\n",
1614 GNUNET_h2s (&ack->cmac));
1615
1616 if (NULL != receiver->ss_rekey)
1617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1618 "We have rekey secret with cmac %s \n",
1619 GNUNET_h2s (&receiver->ss_rekey->cmac));
1620
1621 if ((NULL != receiver->ss_rekey) && (0 == memcmp (&ack->cmac,
1622 &receiver->ss_rekey->cmac,
1623 sizeof(struct
1624 GNUNET_HashCode))) )
1625 {
1626 allowed = ntohl (ack->sequence_max);
1627
1628 if (allowed > receiver->ss_rekey->sequence_allowed)
1629 {
1630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1631 "%u > %u (%u %u) for rekey secrect %s\n", allowed,
1632 receiver->ss_rekey->sequence_allowed,
1633 receiver->acks_available,
1634 ack->acks_available,
1635 GNUNET_h2s (&receiver->ss_rekey->master));
1636
1637 receiver->ss_rekey->sequence_allowed = allowed;
1638
1639 if (GNUNET_NO == receiver->rekeying)
1640 add_acks_rekey (receiver);
1641
1642 return GNUNET_NO;
1643 }
1644 }
1645
1646 (void) pid;
1647 for (struct SharedSecret *ss = receiver->ss_head; NULL != ss; ss = ss->next)
1648 {
1649 if (0 == memcmp (&ack->cmac, &ss->cmac, sizeof(struct GNUNET_HashCode)))
1650 {
1651
1652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1653 "Found matching mac\n");
1654
1655 allowed = ntohl (ack->sequence_max);
1656
1657 if (allowed > ss->sequence_allowed)
1658 {
1659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1660 "%u > %u (%u %u) for secrect %s\n", allowed,
1661 ss->sequence_allowed,
1662 receiver->acks_available,
1663 ack->acks_available,
1664 GNUNET_h2s (&ss->master));
1665 // Uncomment this for alternativ 1 of backchannel functionality
1666 acks_to_add = (allowed - ss->sequence_allowed);
1667 if ((GNUNET_NO == receiver->rekeying) &&
1668 (receiver->number_rekeying_kce < 3) )
1669 acks_to_add = reset_rekey_kces (receiver, acks_to_add);
1670 /* if ((GNUNET_NO == receiver->rekeying) && */
1671 /* (receiver->number_rekeying_kce < */
1672 /* 3) ) */
1673 /* { */
1674 /* needed_for_rekeying = (3 - receiver->number_rekeying_kce); */
1675 /* if (acks_to_add <= needed_for_rekeying) */
1676 /* { */
1677 /* receiver->number_rekeying_kce += acks_to_add; */
1678 /* acks_to_add = 0; */
1679 /* } */
1680 /* else */
1681 /* { */
1682 /* acks_to_add -= (3 - receiver->number_rekeying_kce); */
1683 /* receiver->number_rekeying_kce = 3; */
1684 /* } */
1685 /* } */
1686 /* GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, */
1687 /* "%u kce for rekeying\n", */
1688 /* receiver->number_rekeying_kce); */
1689
1690 if ((0 != acks_to_add) && (GNUNET_NO == receiver->rekeying))
1691 {
1692 receiver->acks_available += (allowed - ss->sequence_allowed);
1693 ss->sequence_allowed = allowed;
1694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1695 "%u receiver->acks_available 5\n",
1696 receiver->acks_available);
1697 add_acks (ss, acks_to_add);
1698 }
1699 }
1700 return GNUNET_NO;
1701 }
1702 }
1703 return GNUNET_YES;
1704}
1705
1706
1707/**
1708 * Test if we have received a valid message in plaintext.
1709 * If so, handle it.
1710 *
1711 * @param sender peer to process inbound plaintext for
1712 * @param buf buffer we received
1713 * @param buf_size number of bytes in @a buf
1714 */
1715static void
1716try_handle_plaintext (struct SenderAddress *sender,
1717 const void *buf,
1718 size_t buf_size)
1719{
1720 const struct GNUNET_MessageHeader *hdr =
1721 (const struct GNUNET_MessageHeader *) buf;
1722 const struct UDPAck *ack = (const struct UDPAck *) buf;
1723 uint16_t type;
1724
1725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1726 "try_handle_plaintext of size %u (%u %u) and type %u\n",
1727 buf_size,
1728 ntohs (hdr->size),
1729 sizeof(*hdr),
1730 ntohs (hdr->type));
1731 if (sizeof(*hdr) > buf_size)
1732 return; /* not even a header */
1733 if (ntohs (hdr->size) > buf_size)
1734 return; /* not even a header */
1735 type = ntohs (hdr->type);
1736 switch (type)
1737 {
1738 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK:
1739 /* lookup master secret by 'cmac', then update sequence_max */
1740 GNUNET_CONTAINER_multipeermap_get_multiple (receivers,
1741 &sender->target,
1742 &handle_ack,
1743 (void *) ack);
1744 /* There could be more messages after the ACK, handle those as well */
1745 buf += ntohs (hdr->size);
1746 buf_size -= ntohs (hdr->size);
1747 pass_plaintext_to_core (sender, buf, buf_size);
1748 break;
1749
1750 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD:
1751 /* skip padding */
1752 break;
1753
1754 default:
1755 pass_plaintext_to_core (sender, buf, buf_size);
1756 }
1757}
1758
1759
1760static void
1761kce_generate_cb (void *cls)
1762{
1763 struct SharedSecret *ss = cls;
1764
1765 ss->sender->kce_task = NULL;
1766
1767 if (((GNUNET_NO == ss->sender->rekeying) && (ss->sender->acks_available <
1768 KCN_TARGET) ) ||
1769 ((ss->sender->ss_rekey == ss) && (GNUNET_YES == ss->sender->rekeying) &&
1770 (ss->sender->acks_available < KCN_TARGET)))
1771 {
1772
1773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1774 "Precomputing keys for master %s\n",
1775 GNUNET_h2s (&(ss->master)));
1776
1777 for (int i = 0; i < GENERATE_AT_ONCE; i++)
1778 kce_generate (ss, ++ss->sequence_allowed);
1779
1780 if (KCN_TARGET > ss->sender->acks_available)
1781 {
1782 ss->sender->kce_task = GNUNET_SCHEDULER_add_delayed (
1783 WORKING_QUEUE_INTERVALL,
1784 kce_generate_cb,
1785 ss);
1786 }
1787 else
1788 {
1789 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1790 "We have enough keys.\n");
1791 ss_finished = ss;
1792 ss->sender->kce_task_finished = GNUNET_YES;
1793 }
1794 }
1795
1796
1797
1798}
1799
1800
1801static void
1802kce_generate_rekey_cb (void *cls)
1803{
1804 struct SharedSecret *ss = cls;
1805
1806 ss->sender->kce_task_rekey = NULL;
1807
1808 if (NULL == ss->sender->kce_task)
1809 {
1810
1811 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1812 "Precomputing keys for rekey master %s\n",
1813 GNUNET_h2s (&(ss->master)));
1814
1815 for (int i = 0; i < GENERATE_AT_ONCE; i++)
1816 kce_generate (ss, ++ss->sequence_allowed);
1817
1818 ss->sender->kce_task = GNUNET_SCHEDULER_add_delayed (
1819 WORKING_QUEUE_INTERVALL,
1820 kce_generate_cb,
1821 ss);
1822 ss->sender->kce_task_rekey = NULL;
1823 }
1824 else
1825 {
1826 ss->sender->kce_task_rekey = GNUNET_SCHEDULER_add_delayed (
1827 WORKING_QUEUE_INTERVALL,
1828 kce_generate_rekey_cb,
1829 ss);
1830 }
1831}
1832
1833
1834/**
1835 * We established a shared secret with a sender. We should try to send
1836 * the sender an `struct UDPAck` at the next opportunity to allow the
1837 * sender to use @a ss longer (assuming we did not yet already
1838 * recently).
1839 *
1840 * @param ss shared secret to generate ACKs for
1841 * @param initial The SharedSecret came with initial KX.
1842 */
1843static void
1844consider_ss_ack (struct SharedSecret *ss, int initial)
1845{
1846 struct GNUNET_SCHEDULER_Task *kce_task_rekey;
1847 struct GNUNET_SCHEDULER_Task *kce_task;
1848 int kce_task_finished;
1849
1850 kce_task_rekey = ss->sender->kce_task_rekey;
1851 kce_task_finished = ss->sender->kce_task_finished;
1852 kce_task = ss->sender->kce_task;
1853
1854 GNUNET_assert (NULL != ss->sender);
1855 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1856 "Considering SS UDPAck %s\n",
1857 GNUNET_i2s_full (&ss->sender->target));
1858
1859 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1860 "We have %u acks available.\n",
1861 ss->sender->acks_available);
1862 /* drop ancient KeyCacheEntries */
1863 while ((NULL != ss->kce_head) &&
1864 (MAX_SQN_DELTA <
1865 ss->kce_head->sequence_number - ss->kce_tail->sequence_number))
1866 kce_destroy (ss->kce_tail);
1867
1868
1869 if (GNUNET_NO == initial)
1870 kce_generate (ss, ++ss->sequence_allowed);
1871
1872 /*if (0 == ss->sender->acks_available)
1873 {
1874 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1875 "Generating keys\n");
1876 while (ss->active_kce_count < KCN_TARGET)
1877 kce_generate (ss, ++ss->sequence_allowed);
1878 }*/
1879
1880 if (NULL != kce_task)
1881 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1882 "kce_task is not NULL\n");
1883 if (kce_task_finished)
1884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1885 "kce_task_finished: GNUNET_YES\n");
1886 if (initial)
1887 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1888 "initial: GNUNET_YES\n");
1889
1890 if ( kce_task_finished || (GNUNET_NO == initial))
1891 {
1892 struct UDPAck ack;
1893 struct SharedSecret *ss_tell;
1894
1895 if (GNUNET_NO != initial)
1896 ss_tell = ss_finished;
1897 else
1898 ss_tell = ss;
1899
1900 ack.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK);
1901 ack.header.size = htons (sizeof(ack));
1902 ack.sequence_max = htonl (ss_tell->sequence_allowed);
1903 ack.acks_available = ss->sender->acks_available;
1904 ack.cmac = ss_tell->cmac;
1905 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1906 "Notifying transport of UDPAck %s with initial %u and master %s\n",
1907 GNUNET_i2s_full (&ss_tell->sender->target),
1908 initial,
1909 GNUNET_h2s (&(ss_tell->master)));
1910 GNUNET_TRANSPORT_communicator_notify (ch,
1911 &ss_tell->sender->target,
1912 COMMUNICATOR_ADDRESS_PREFIX,
1913 &ack.header);
1914 if (GNUNET_NO != initial)
1915 {
1916 destroy_all_secrets (ss, GNUNET_YES);
1917 ss->sender->kce_task_finished = GNUNET_NO;
1918 }
1919 }
1920 else if ((NULL == kce_task) && ((KCN_THRESHOLD >
1921 ss->sender->acks_available) ||
1922 (GNUNET_YES == ss->sender->rekeying) ||
1923 (ss->sender->num_secrets > MAX_SECRETS) ))
1924 {
1925
1926 // kce_generate (ss, ++ss->sequence_allowed);
1927 // kce_generate (ss, ++ss->sequence_allowed);
1928 // TODO This task must be per sender!
1929 kce_task = GNUNET_SCHEDULER_add_delayed (WORKING_QUEUE_INTERVALL,
1930 kce_generate_cb,
1931 ss);
1932 kce_task_finished = GNUNET_NO;
1933
1934 }
1935 else if ((NULL == kce_task_rekey) && (GNUNET_YES ==
1936 ss->sender->rekeying) )
1937 {
1938 kce_task_rekey = GNUNET_SCHEDULER_add_delayed (WORKING_QUEUE_INTERVALL,
1939 kce_generate_rekey_cb,
1940 ss);
1941 }
1942}
1943
1944
1945/**
1946 * We received a @a box with matching @a kce. Decrypt and process it.
1947 *
1948 * @param box the data we received
1949 * @param box_len number of bytes in @a box
1950 * @param kce key index to decrypt @a box
1951 */
1952static void
1953decrypt_box (const struct UDPBox *box,
1954 size_t box_len,
1955 struct KeyCacheEntry *kce)
1956{
1957 struct SharedSecret *ss = kce->ss;
1958 char out_buf[box_len - sizeof(*box)];
1959
1960 GNUNET_assert (NULL != ss->sender);
1961 if (GNUNET_OK != try_decrypt (ss,
1962 box->gcm_tag,
1963 kce->sequence_number,
1964 (const char *) &box[1],
1965 sizeof(out_buf),
1966 out_buf))
1967 {
1968 GNUNET_STATISTICS_update (stats,
1969 "# Decryption failures with valid KCE",
1970 1,
1971 GNUNET_NO);
1972 kce_destroy (kce);
1973 return;
1974 }
1975 kce_destroy (kce);
1976 GNUNET_STATISTICS_update (stats,
1977 "# bytes decrypted with BOX",
1978 sizeof(out_buf),
1979 GNUNET_NO);
1980 GNUNET_STATISTICS_update (stats,
1981 "# messages decrypted with BOX",
1982 1,
1983 GNUNET_NO);
1984 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1985 "decrypted UDPBox with kid %s\n",
1986 GNUNET_sh2s (&box->kid));
1987 try_handle_plaintext (ss->sender, out_buf, sizeof(out_buf));
1988 if ((GNUNET_NO == box->rekeying) && (GNUNET_YES == ss->sender->rekeying))
1989 {
1990 ss->sender->rekeying = GNUNET_NO;
1991 ss->sender->ss_rekey = NULL;
1992 // destroy_all_secrets (ss, GNUNET_NO);
1993 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1994 "Receiver stopped rekeying.\n");
1995 }
1996 else if (GNUNET_NO == box->rekeying)
1997 consider_ss_ack (ss, GNUNET_NO);
1998 else
1999 {
2000 ss->sender->rekeying = GNUNET_YES;
2001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2002 "Got Box: Receiver doing rekeying.\n");
2003 }
2004}
2005
2006
2007/**
2008 * We received a @a rekey with matching @a kce. Decrypt and process it.
2009 *
2010 * @param rekey the data we received
2011 * @param rekey_len number of bytes in @a rekey
2012 * @param kce key index to decrypt @a rekey
2013 */
2014static void
2015decrypt_rekey (const struct UDPRekey *rekey,
2016 size_t rekey_len,
2017 struct KeyCacheEntry *kce,
2018 struct SenderAddress *sender)
2019{
2020 struct SharedSecret *ss = kce->ss;
2021 struct SharedSecret *ss_rekey;
2022 char out_buf[rekey_len - sizeof(*rekey)];
2023 struct GNUNET_HashCode *master;
2024
2025
2026 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2027 "decrypt_rekey.\n");
2028
2029 GNUNET_assert (NULL != ss->sender);
2030 if (GNUNET_OK != try_decrypt (ss,
2031 rekey->gcm_tag,
2032 kce->sequence_number,
2033 (const char *) &rekey[1],
2034 sizeof(out_buf),
2035 out_buf))
2036 {
2037 GNUNET_STATISTICS_update (stats,
2038 "# Decryption failures with valid KCE",
2039 1,
2040 GNUNET_NO);
2041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2042 "Decryption with kid %s failed\n",
2043 GNUNET_sh2s (&rekey->kid));
2044 kce_destroy (kce);
2045 return;
2046 }
2047 kce_destroy (kce);
2048 GNUNET_STATISTICS_update (stats,
2049 "# bytes decrypted with Rekey",
2050 sizeof(out_buf),
2051 GNUNET_NO);
2052 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2053 "decrypted UDPRekey with kid %s\n",
2054 GNUNET_sh2s (&rekey->kid));
2055 /*cmac = (struct GNUNET_HashCode *) out_buf;
2056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2057 "Received secret with cmac %s \n",
2058 GNUNET_h2s (&cmac));*/
2059 // ss_rekey = (struct SharedSecret *) out_buf;
2060 master = (struct GNUNET_HashCode *) out_buf;
2061 ss_rekey = GNUNET_new (struct SharedSecret);
2062 ss_rekey->master = *master;
2063 calculate_cmac (ss_rekey);
2064 ss_rekey->sender = sender;
2065 // ss_rekey->sequence_used = 0;
2066 // ss_rekey->sequence_allowed = 0;
2067 /* ss_rekey->active_kce_count = 0; */
2068 /* ss_rekey->prev = NULL; */
2069 /* ss_rekey->next = NULL; */
2070 /* GNUNET_assert (ss_rekey->prev == NULL && sender->ss_head != ss_rekey); */
2071 /* GNUNET_assert (ss_rekey->next == NULL && sender->ss_tail != ss_rekey); */
2072 GNUNET_CONTAINER_DLL_insert (sender->ss_head, sender->ss_tail, ss_rekey);
2073 sender->ss_rekey = ss_rekey;
2074 sender->num_secrets++;
2075 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2076 "Received secret with cmac %s\n",
2077 GNUNET_h2s (&(ss_rekey->cmac)));
2078 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2079 "Received secret with master %s.\n",
2080 GNUNET_h2s (&(ss_rekey->master)));
2081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2082 "We have %u sequence_allowed.\n",
2083 ss_rekey->sequence_allowed);
2084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2085 "We have a sender %p\n",
2086 ss_rekey->sender);
2087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2088 "We have %u acks available.\n",
2089 ss_rekey->sender->acks_available);
2090 consider_ss_ack (ss_rekey, GNUNET_YES);
2091
2092}
2093
2094
2095/**
2096 * Closure for #find_sender_by_address()
2097 */
2098struct SearchContext
2099{
2100 /**
2101 * Address we are looking for.
2102 */
2103 const struct sockaddr *address;
2104
2105 /**
2106 * Number of bytes in @e address.
2107 */
2108 socklen_t address_len;
2109
2110 /**
2111 * Return value to set if we found a match.
2112 */
2113 struct SenderAddress *sender;
2114};
2115
2116
2117/**
2118 * Find existing `struct SenderAddress` by matching addresses.
2119 *
2120 * @param cls a `struct SearchContext`
2121 * @param key ignored, must match already
2122 * @param value a `struct SenderAddress`
2123 * @return #GNUNET_YES if not found (continue to search), #GNUNET_NO if found
2124 */
2125static int
2126find_sender_by_address (void *cls,
2127 const struct GNUNET_PeerIdentity *key,
2128 void *value)
2129{
2130 struct SearchContext *sc = cls;
2131 struct SenderAddress *sender = value;
2132
2133 if ((sender->address_len == sc->address_len) &&
2134 (0 == memcmp (sender->address, sc->address, sender->address_len)))
2135 {
2136 sc->sender = sender;
2137 return GNUNET_NO; /* stop iterating! */
2138 }
2139 return GNUNET_YES;
2140}
2141
2142
2143/**
2144 * Create sender address for @a target. Note that we
2145 * might already have one, so a fresh one is only allocated
2146 * if one does not yet exist for @a address.
2147 *
2148 * @param target peer to generate address for
2149 * @param address target address
2150 * @param address_len number of bytes in @a address
2151 * @return data structure to keep track of key material for
2152 * decrypting data from @a target
2153 */
2154static struct SenderAddress *
2155setup_sender (const struct GNUNET_PeerIdentity *target,
2156 const struct sockaddr *address,
2157 socklen_t address_len)
2158{
2159 struct SenderAddress *sender;
2160 struct SearchContext sc = { .address = address,
2161 .address_len = address_len,
2162 .sender = NULL };
2163
2164 GNUNET_CONTAINER_multipeermap_get_multiple (senders,
2165 target,
2166 &find_sender_by_address,
2167 &sc);
2168 if (NULL != sc.sender)
2169 {
2170 reschedule_sender_timeout (sc.sender);
2171 return sc.sender;
2172 }
2173 sender = GNUNET_new (struct SenderAddress);
2174 sender->target = *target;
2175 sender->address = GNUNET_memdup (address, address_len);
2176 sender->address_len = address_len;
2177 (void) GNUNET_CONTAINER_multipeermap_put (
2178 senders,
2179 &sender->target,
2180 sender,
2181 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2182 GNUNET_STATISTICS_set (stats,
2183 "# senders active",
2184 GNUNET_CONTAINER_multipeermap_size (receivers),
2185 GNUNET_NO);
2186 sender->timeout =
2187 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2188 sender->hn = GNUNET_CONTAINER_heap_insert (senders_heap,
2189 sender,
2190 sender->timeout.abs_value_us);
2191 sender->nt = GNUNET_NT_scanner_get_type (is, address, address_len);
2192 if (NULL == timeout_task)
2193 timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL);
2194 return sender;
2195}
2196
2197
2198/**
2199 * Check signature from @a uc against @a ephemeral.
2200 *
2201 * @param ephermal key that is signed
2202 * @param uc signature of claimant
2203 * @return #GNUNET_OK if signature is valid
2204 */
2205static int
2206verify_confirmation (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
2207 const struct UDPConfirmation *uc)
2208{
2209 struct UdpHandshakeSignature uhs;
2210
2211 uhs.purpose.purpose = htonl (
2212 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE);
2213 uhs.purpose.size = htonl (sizeof(uhs));
2214 uhs.sender = uc->sender;
2215 uhs.receiver = my_identity;
2216 uhs.ephemeral = *ephemeral;
2217 uhs.monotonic_time = uc->monotonic_time;
2218 return GNUNET_CRYPTO_eddsa_verify (
2219 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE,
2220 &uhs,
2221 &uc->sender_sig,
2222 &uc->sender.public_key);
2223}
2224
2225
2226/**
2227 * Converts @a address to the address string format used by this
2228 * communicator in HELLOs.
2229 *
2230 * @param address the address to convert, must be AF_INET or AF_INET6.
2231 * @param address_len number of bytes in @a address
2232 * @return string representation of @a address
2233 */
2234static char *
2235sockaddr_to_udpaddr_string (const struct sockaddr *address,
2236 socklen_t address_len)
2237{
2238 char *ret;
2239
2240 switch (address->sa_family)
2241 {
2242 case AF_INET:
2243 GNUNET_asprintf (&ret,
2244 "%s-%s",
2245 COMMUNICATOR_ADDRESS_PREFIX,
2246 GNUNET_a2s (address, address_len));
2247 break;
2248
2249 case AF_INET6:
2250 GNUNET_asprintf (&ret,
2251 "%s-%s",
2252 COMMUNICATOR_ADDRESS_PREFIX,
2253 GNUNET_a2s (address, address_len));
2254 break;
2255
2256 default:
2257 GNUNET_assert (0);
2258 }
2259 return ret;
2260}
2261
2262
2263/**
2264 * Socket read task.
2265 *
2266 * @param cls NULL
2267 */
2268static void
2269sock_read (void *cls)
2270{
2271 struct sockaddr_storage sa;
2272 struct sockaddr_in *addr_verify;
2273 socklen_t salen = sizeof(sa);
2274 char buf[UINT16_MAX];
2275 ssize_t rcvd;
2276
2277 (void) cls;
2278 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2279 udp_sock,
2280 &sock_read,
2281 NULL);
2282 rcvd = GNUNET_NETWORK_socket_recvfrom (udp_sock,
2283 buf,
2284 sizeof(buf),
2285 (struct sockaddr *) &sa,
2286 &salen);
2287 if (-1 == rcvd)
2288 {
2289 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2290 return;
2291 }
2292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2293 "Read %lu bytes\n", rcvd);
2294
2295 if (rcvd > sizeof(struct UDPRekey))
2296 {
2297 const struct UDPRekey *rekey;
2298 const struct UDPBox *box;
2299 struct KeyCacheEntry *kce;
2300 struct SenderAddress *sender;
2301 int do_decrypt = GNUNET_NO;
2302
2303 rekey = (const struct UDPRekey *) buf;
2304 box = (const struct UDPBox *) buf;
2305 kce = GNUNET_CONTAINER_multishortmap_get (key_cache, &rekey->kid);
2306
2307 if ((GNUNET_YES == box->rekeying) || (GNUNET_NO == box->rekeying))
2308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2309 "UDPRekey has rekeying %u\n",
2310 box->rekeying);
2311 else
2312 do_decrypt = GNUNET_YES;
2313
2314 if ((GNUNET_YES == do_decrypt) && (NULL != kce) && (GNUNET_YES ==
2315 kce->ss->sender->
2316 rekeying))
2317 {
2318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2319 "UDPRekey with kid %s\n",
2320 GNUNET_sh2s (&rekey->kid));
2321 sender = setup_sender (&rekey->sender, (const struct sockaddr *) &sa,
2322 salen);
2323
2324 if (NULL != sender->ss_rekey)
2325 return;
2326
2327 decrypt_rekey (rekey, (size_t) rcvd, kce, sender);
2328 return;
2329 }
2330 }
2331
2332 /* first, see if it is a UDPBox */
2333 if (rcvd > sizeof(struct UDPBox))
2334 {
2335 const struct UDPBox *box;
2336 struct KeyCacheEntry *kce;
2337
2338 box = (const struct UDPBox *) buf;
2339 kce = GNUNET_CONTAINER_multishortmap_get (key_cache, &box->kid);
2340 if (NULL != kce)
2341 {
2342 decrypt_box (box, (size_t) rcvd, kce);
2343 return;
2344 }
2345 }
2346
2347 /* next, check if it is a broadcast */
2348 if (sizeof(struct UDPBroadcast) == rcvd)
2349 {
2350 const struct UDPBroadcast *ub;
2351 struct UdpBroadcastSignature uhs;
2352 struct GNUNET_PeerIdentity sender;
2353
2354 addr_verify = GNUNET_memdup (&sa, salen);
2355 addr_verify->sin_port = 0;
2356 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2357 "received UDPBroadcast from %s\n",
2358 GNUNET_a2s ((const struct sockaddr *) addr_verify, salen));
2359 ub = (const struct UDPBroadcast *) buf;
2360 uhs.purpose.purpose = htonl (
2361 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST);
2362 uhs.purpose.size = htonl (sizeof(uhs));
2363 uhs.sender = ub->sender;
2364 sender = ub->sender;
2365 if (0 == memcmp (&sender, &my_identity, sizeof (struct
2366 GNUNET_PeerIdentity)))
2367 {
2368 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2369 "Received our own broadcast\n");
2370 return;
2371 }
2372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2373 "checking UDPBroadcastSignature for %s\n",
2374 GNUNET_i2s (&sender));
2375 GNUNET_CRYPTO_hash ((struct sockaddr *) addr_verify, salen, &uhs.h_address);
2376 if (GNUNET_OK ==
2377 GNUNET_CRYPTO_eddsa_verify (
2378 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST,
2379 &uhs,
2380 &ub->sender_sig,
2381 &ub->sender.public_key))
2382 {
2383 char *addr_s;
2384 enum GNUNET_NetworkType nt;
2385
2386 addr_s =
2387 sockaddr_to_udpaddr_string ((const struct sockaddr *) &sa, salen);
2388 GNUNET_STATISTICS_update (stats, "# broadcasts received", 1, GNUNET_NO);
2389 /* use our own mechanism to determine network type */
2390 nt =
2391 GNUNET_NT_scanner_get_type (is, (const struct sockaddr *) &sa, salen);
2392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2393 "validating address %s received from UDPBroadcast\n",
2394 GNUNET_i2s (&sender));
2395 GNUNET_TRANSPORT_application_validate (ah, &sender, nt, addr_s);
2396 GNUNET_free (addr_s);
2397 return;
2398 }
2399 else
2400 {
2401 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2402 "VerifyingPeer %s is verifying UDPBroadcast\n",
2403 GNUNET_i2s (&my_identity));
2404 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2405 "Verifying UDPBroadcast from %s failed\n",
2406 GNUNET_i2s (&ub->sender));
2407 }
2408 GNUNET_free (addr_verify);
2409 /* continue with KX, mostly for statistics... */
2410 }
2411
2412
2413 /* finally, test if it is a KX */
2414 if (rcvd < sizeof(struct UDPConfirmation) + sizeof(struct InitialKX))
2415 {
2416 GNUNET_STATISTICS_update (stats,
2417 "# messages dropped (no kid, too small for KX)",
2418 1,
2419 GNUNET_NO);
2420 return;
2421 }
2422 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2423 "Got KX\n");
2424 {
2425 const struct InitialKX *kx;
2426 struct SharedSecret *ss;
2427 char pbuf[rcvd - sizeof(struct InitialKX)];
2428 const struct UDPConfirmation *uc;
2429 struct SenderAddress *sender;
2430
2431 kx = (const struct InitialKX *) buf;
2432 ss = setup_shared_secret_dec (&kx->ephemeral);
2433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2434 "Before DEC\n");
2435
2436 if (GNUNET_OK != try_decrypt (ss,
2437 kx->gcm_tag,
2438 0,
2439 &buf[sizeof(*kx)],
2440 sizeof(pbuf),
2441 pbuf))
2442 {
2443 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2444 "Unable to decrypt tag, dropping...\n");
2445 GNUNET_free (ss);
2446 GNUNET_STATISTICS_update (
2447 stats,
2448 "# messages dropped (no kid, AEAD decryption failed)",
2449 1,
2450 GNUNET_NO);
2451 return;
2452 }
2453 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2454 "Before VERIFY\n");
2455
2456 uc = (const struct UDPConfirmation *) pbuf;
2457 if (GNUNET_OK != verify_confirmation (&kx->ephemeral, uc))
2458 {
2459 GNUNET_break_op (0);
2460 GNUNET_free (ss);
2461 GNUNET_STATISTICS_update (stats,
2462 "# messages dropped (sender signature invalid)",
2463 1,
2464 GNUNET_NO);
2465 return;
2466 }
2467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2468 "Before SETUP_SENDER\n");
2469
2470 calculate_cmac (ss);
2471 sender = setup_sender (&uc->sender, (const struct sockaddr *) &sa, salen);
2472 ss->sender = sender;
2473 GNUNET_CONTAINER_DLL_insert (sender->ss_head, sender->ss_tail, ss);
2474 sender->num_secrets++;
2475 GNUNET_STATISTICS_update (stats, "# Secrets active", 1, GNUNET_NO);
2476 GNUNET_STATISTICS_update (stats,
2477 "# messages decrypted without BOX",
2478 1,
2479 GNUNET_NO);
2480 try_handle_plaintext (sender, &uc[1], sizeof(pbuf) - sizeof(*uc));
2481 if ((GNUNET_NO == kx->rekeying) && (GNUNET_YES == ss->sender->rekeying))
2482 {
2483 ss->sender->rekeying = GNUNET_NO;
2484 sender->ss_rekey = NULL;
2485 // destroy_all_secrets (ss, GNUNET_NO);
2486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2487 "Receiver stopped rekeying.\n");
2488 }
2489 else if (GNUNET_NO == kx->rekeying)
2490 consider_ss_ack (ss, GNUNET_YES);
2491 else
2492 {
2493 ss->sender->rekeying = GNUNET_YES;
2494 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2495 "Got KX: Receiver doing rekeying.\n");
2496 }
2497 /*if (sender->num_secrets > MAX_SECRETS)
2498 secret_destroy (sender->ss_tail);*/
2499 }
2500}
2501
2502
2503/**
2504 * Convert UDP bind specification to a `struct sockaddr *`
2505 *
2506 * @param bindto bind specification to convert
2507 * @param[out] sock_len set to the length of the address
2508 * @return converted bindto specification
2509 */
2510static struct sockaddr *
2511udp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
2512{
2513 struct sockaddr *in;
2514 unsigned int port;
2515 char dummy[2];
2516 char *colon;
2517 char *cp;
2518
2519 if (1 == sscanf (bindto, "%u%1s", &port, dummy))
2520 {
2521 /* interpreting value as just a PORT number */
2522 if (port > UINT16_MAX)
2523 {
2524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2525 "BINDTO specification `%s' invalid: value too large for port\n",
2526 bindto);
2527 return NULL;
2528 }
2529 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
2530 (GNUNET_YES ==
2531 GNUNET_CONFIGURATION_get_value_yesno (cfg,
2532 COMMUNICATOR_CONFIG_SECTION,
2533 "DISABLE_V6")))
2534 {
2535 struct sockaddr_in *i4;
2536
2537 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2538 i4->sin_family = AF_INET;
2539 i4->sin_port = htons ((uint16_t) port);
2540 *sock_len = sizeof(struct sockaddr_in);
2541 in = (struct sockaddr *) i4;
2542 }
2543 else
2544 {
2545 struct sockaddr_in6 *i6;
2546
2547 i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
2548 i6->sin6_family = AF_INET6;
2549 i6->sin6_port = htons ((uint16_t) port);
2550 *sock_len = sizeof(struct sockaddr_in6);
2551 in = (struct sockaddr *) i6;
2552 }
2553 return in;
2554 }
2555 cp = GNUNET_strdup (bindto);
2556 colon = strrchr (cp, ':');
2557 if (NULL != colon)
2558 {
2559 /* interpret value after colon as port */
2560 *colon = '\0';
2561 colon++;
2562 if (1 == sscanf (colon, "%u%1s", &port, dummy))
2563 {
2564 /* interpreting value as just a PORT number */
2565 if (port > UINT16_MAX)
2566 {
2567 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2568 "BINDTO specification `%s' invalid: value too large for port\n",
2569 bindto);
2570 GNUNET_free (cp);
2571 return NULL;
2572 }
2573 }
2574 else
2575 {
2576 GNUNET_log (
2577 GNUNET_ERROR_TYPE_ERROR,
2578 "BINDTO specification `%s' invalid: last ':' not followed by number\n",
2579 bindto);
2580 GNUNET_free (cp);
2581 return NULL;
2582 }
2583 }
2584 else
2585 {
2586 /* interpret missing port as 0, aka pick any free one */
2587 port = 0;
2588 }
2589 {
2590 /* try IPv4 */
2591 struct sockaddr_in v4;
2592 if (1 == inet_pton (AF_INET, cp, &v4.sin_addr))
2593 {
2594 v4.sin_family = AF_INET;
2595 v4.sin_port = htons ((uint16_t) port);
2596#if HAVE_SOCKADDR_IN_SIN_LEN
2597 v4.sin_len = sizeof(struct sockaddr_in);
2598#endif
2599 in = GNUNET_memdup (&v4, sizeof(struct sockaddr_in));
2600 *sock_len = sizeof(struct sockaddr_in);
2601 GNUNET_free (cp);
2602 return in;
2603 }
2604 }
2605 {
2606 /* try IPv6 */
2607 struct sockaddr_in6 v6;
2608 const char *start;
2609
2610 start = cp;
2611 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
2612 {
2613 start++; /* skip over '[' */
2614 cp[strlen (cp) - 1] = '\0'; /* eat ']' */
2615 }
2616 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
2617 {
2618 v6.sin6_family = AF_INET6;
2619 v6.sin6_port = htons ((uint16_t) port);
2620#if HAVE_SOCKADDR_IN_SIN_LEN
2621 v6.sin6_len = sizeof(sizeof(struct sockaddr_in6));
2622#endif
2623 in = GNUNET_memdup (&v6, sizeof(v6));
2624 *sock_len = sizeof(v6);
2625 GNUNET_free (cp);
2626 return in;
2627 }
2628 }
2629 /* #5528 FIXME (feature!): maybe also try getnameinfo()? */
2630 GNUNET_free (cp);
2631 return NULL;
2632}
2633
2634
2635/**
2636 * Pad @a dgram by @a pad_size using @a out_cipher.
2637 *
2638 * @param out_cipher cipher to use
2639 * @param dgram datagram to pad
2640 * @param pad_size number of bytes of padding to append
2641 */
2642static void
2643do_pad (gcry_cipher_hd_t out_cipher, char *dgram, size_t pad_size)
2644{
2645 char pad[pad_size];
2646
2647 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, pad, sizeof(pad));
2648 if (sizeof(pad) > sizeof(struct GNUNET_MessageHeader))
2649 {
2650 struct GNUNET_MessageHeader hdr =
2651 { .size = htons (sizeof(pad)),
2652 .type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD) };
2653
2654 memcpy (pad, &hdr, sizeof(hdr));
2655 }
2656 GNUNET_assert (
2657 0 ==
2658 gcry_cipher_encrypt (out_cipher, dgram, sizeof(pad), pad, sizeof(pad)));
2659}
2660
2661
2662/**
2663 * Signature of functions implementing the sending functionality of a
2664 * message queue.
2665 *
2666 * @param mq the message queue
2667 * @param msg the message to send
2668 * @param impl_state our `struct ReceiverAddress`
2669 */
2670static void
2671mq_send_kx (struct GNUNET_MQ_Handle *mq,
2672 const struct GNUNET_MessageHeader *msg,
2673 void *impl_state)
2674{
2675 struct ReceiverAddress *receiver = impl_state;
2676 uint16_t msize = ntohs (msg->size);
2677 struct UdpHandshakeSignature uhs;
2678 struct UDPConfirmation uc;
2679 struct InitialKX kx;
2680 struct GNUNET_CRYPTO_EcdhePrivateKey epriv;
2681 char dgram[receiver->kx_mtu + sizeof(uc) + sizeof(kx)];
2682 size_t dpos;
2683 gcry_cipher_hd_t out_cipher;
2684 struct SharedSecret *ss;
2685
2686 GNUNET_assert (mq == receiver->kx_mq);
2687 if (msize > receiver->kx_mtu)
2688 {
2689 GNUNET_break (0);
2690 if (GNUNET_YES != receiver->receiver_destroy_called)
2691 receiver_destroy (receiver);
2692 return;
2693 }
2694 reschedule_receiver_timeout (receiver);
2695
2696 /* setup key material */
2697 GNUNET_CRYPTO_ecdhe_key_create (&epriv);
2698
2699 ss = setup_shared_secret_enc (&epriv, receiver, GNUNET_YES);
2700
2701 if (receiver->num_secrets > MAX_SECRETS)
2702 {
2703 destroy_all_secrets (ss, GNUNET_YES);
2704 }
2705
2706 setup_cipher (&ss->master, 0, &out_cipher);
2707 /* compute 'uc' */
2708 uc.sender = my_identity;
2709 uc.monotonic_time =
2710 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
2711 uhs.purpose.purpose = htonl (
2712 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE);
2713 uhs.purpose.size = htonl (sizeof(uhs));
2714 uhs.sender = my_identity;
2715 uhs.receiver = receiver->target;
2716 GNUNET_CRYPTO_ecdhe_key_get_public (&epriv, &uhs.ephemeral);
2717 uhs.monotonic_time = uc.monotonic_time;
2718 GNUNET_CRYPTO_eddsa_sign (my_private_key,
2719 &uhs,
2720 &uc.sender_sig);
2721 /* Leave space for kx */
2722 dpos = sizeof(kx);
2723 /* Append encrypted uc to dgram */
2724 GNUNET_assert (0 == gcry_cipher_encrypt (out_cipher,
2725 &dgram[dpos],
2726 sizeof(uc),
2727 &uc,
2728 sizeof(uc)));
2729 dpos += sizeof(uc);
2730 /* Append encrypted payload to dgram */
2731 GNUNET_assert (
2732 0 == gcry_cipher_encrypt (out_cipher, &dgram[dpos], msize, msg, msize));
2733 dpos += msize;
2734 do_pad (out_cipher, &dgram[dpos], sizeof(dgram) - dpos);
2735 /* Datagram starts with kx */
2736 kx.ephemeral = uhs.ephemeral;
2737 GNUNET_assert (
2738 0 == gcry_cipher_gettag (out_cipher, kx.gcm_tag, sizeof(kx.gcm_tag)));
2739 gcry_cipher_close (out_cipher);
2740 if (GNUNET_NO == receiver->rekeying)
2741 kx.rekeying = GNUNET_NO;
2742 else
2743 kx.rekeying = GNUNET_YES;
2744 memcpy (dgram, &kx, sizeof(kx));
2745 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
2746 dgram,
2747 sizeof(dgram),
2748 receiver->address,
2749 receiver->address_len))
2750 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
2751 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2752 "Sending KX with payload size %u to %s\n",
2753 msize,
2754 GNUNET_a2s (receiver->address,
2755 receiver->address_len));
2756 GNUNET_MQ_impl_send_continue (mq);
2757}
2758
2759
2760static void
2761check_for_rekeying (struct ReceiverAddress *receiver, struct UDPBox *box)
2762{
2763
2764 struct GNUNET_TIME_Relative rt;
2765
2766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2767 "Timeout is %llu\n.",
2768 (unsigned long long) receiver->rekey_timeout.abs_value_us);
2769
2770 if (0 == receiver->rekey_timeout.abs_value_us)
2771 {
2772 receiver->rekey_timeout = GNUNET_TIME_relative_to_absolute (
2773 rekey_interval);
2774 }
2775 else
2776 {
2777 rt = GNUNET_TIME_absolute_get_remaining (receiver->rekey_timeout);
2778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2779 "Relative time is %llu and timeout is %llu\n.",
2780 (unsigned long long) rt.rel_value_us,
2781 (unsigned long long) receiver->rekey_timeout.abs_value_us);
2782
2783 if ((0 == rt.rel_value_us) || (receiver->rekey_send_bytes >
2784 rekey_max_bytes) )
2785 {
2786 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2787 "Bytes send %llu greater than %llu max bytes\n.",
2788 (unsigned long long) receiver->rekey_send_bytes,
2789 rekey_max_bytes);
2790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2791 "Relative time is %llu and timeout is %llu\n.",
2792 (unsigned long long) rt.rel_value_us,
2793 (unsigned long long) receiver->rekey_timeout.abs_value_us);
2794
2795 receiver->rekey_timeout.abs_value_us = 0;
2796 receiver->rekey_send_bytes = 0;
2797 receiver->ss_rekey = NULL;
2798 // destroy_all_secrets (ss, GNUNET_NO);
2799 receiver->rekeying = GNUNET_YES;
2800 receiver->rekey_acks_available = receiver->acks_available;
2801 box->rekeying = GNUNET_YES;
2802 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2803 "Sender started rekeying.\n");
2804 if (GNUNET_YES == box->rekeying)
2805 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2806 "Sending rekeying with kid %s\n",
2807 GNUNET_sh2s (&box->kid));
2808 }
2809 }
2810}
2811
2812
2813static void
2814send_UDPRekey (struct ReceiverAddress *receiver, struct SharedSecret *ss)
2815{
2816 uint8_t is_ss_rekey_sequence_allowed_zero = GNUNET_NO;
2817 uint8_t is_acks_available_below = GNUNET_NO;
2818 uint8_t send_rekey = GNUNET_NO;
2819 uint16_t not_below;
2820 struct GNUNET_CRYPTO_EcdhePrivateKey epriv;
2821 struct UDPRekey *rekey;
2822 size_t dpos;
2823
2824 char rekey_dgram[sizeof(struct UDPRekey) + receiver->d_mtu];
2825
2826 if (NULL != receiver->ss_rekey)
2827 {
2828 not_below = (receiver->rekey_acks_available
2829 - (receiver->rekey_acks_available % 3)) / 3;
2830 is_ss_rekey_sequence_allowed_zero = (0 ==
2831 receiver->ss_rekey->sequence_allowed);
2832 is_acks_available_below = (receiver->acks_available >= not_below);
2833 send_rekey = (0 == (receiver->acks_available - not_below) % not_below) &&
2834 is_acks_available_below && is_ss_rekey_sequence_allowed_zero;
2835 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2836 "send_rekey: %u, %u, %u\n",
2837 send_rekey,
2838 receiver->rekey_acks_available,
2839 receiver->acks_available);
2840 }
2841 else if (NULL == receiver->ss_rekey)
2842 {
2843 /* setup key material */
2844 GNUNET_CRYPTO_ecdhe_key_create (&epriv);
2845 receiver->ss_rekey = setup_shared_secret_enc (&epriv, receiver,
2846 GNUNET_NO);
2847 receiver->ss_rekey->sequence_allowed = 0;
2848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2849 "Setup secret with cmac %s\n",
2850 GNUNET_h2s (&(receiver->ss_rekey->cmac)));
2851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2852 "Setup secret with master %s.\n",
2853 GNUNET_h2s (&(receiver->ss_rekey->master)));
2854 }
2855
2856 if (send_rekey)
2857 {
2858 GNUNET_assert (0 != receiver->number_rekeying_kce);
2859 gcry_cipher_hd_t rekey_out_cipher;
2860
2861 while (NULL != ss && ss->sequence_used >= ss->sequence_allowed)
2862 {
2863 ss = ss->prev;
2864 }
2865
2866 if (NULL != ss)
2867 {
2868 rekey = (struct UDPRekey *) rekey_dgram;
2869 rekey->sender = my_identity;
2870 ss->sequence_used++;
2871 get_kid (&ss->master, ss->sequence_used, &rekey->kid);
2872 receiver->number_rekeying_kce--;
2873 setup_cipher (&ss->master, ss->sequence_used, &rekey_out_cipher);
2874 /* Append encrypted payload to dgram */
2875 dpos = sizeof(struct UDPRekey);
2876
2877 GNUNET_assert (
2878 0 == gcry_cipher_encrypt (rekey_out_cipher, &rekey_dgram[dpos],
2879 sizeof(receiver->ss_rekey->master),
2880 &(receiver->ss_rekey->master),
2881 sizeof(receiver->ss_rekey->master)));
2882 dpos += sizeof(receiver->ss_rekey->master);
2883 /* GNUNET_assert ( */
2884 /* 0 == gcry_cipher_encrypt (rekey_out_cipher, &rekey_dgram[dpos], */
2885 /* /\*sizeof(receiver->ss_rekey->cmac), */
2886 /* &(receiver->ss_rekey->cmac), */
2887 /* sizeof(receiver->ss_rekey->cmac))); */
2888 /* dpos += sizeof(receiver->ss_rekey->cmac);*\/ */
2889 /* sizeof(receiver->ss_rekey), */
2890 /* receiver->ss_rekey, */
2891 /* sizeof(receiver->ss_rekey))); */
2892 /* dpos += sizeof(receiver->ss_rekey); */
2893 do_pad (rekey_out_cipher, &rekey_dgram[dpos], sizeof(rekey_dgram)
2894 - dpos);
2895 GNUNET_assert (0 == gcry_cipher_gettag (rekey_out_cipher,
2896 rekey->gcm_tag,
2897 sizeof(rekey->gcm_tag)));
2898 gcry_cipher_close (rekey_out_cipher);
2899
2900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2901 "Sending rekey with kid %s and master %s\n",
2902 GNUNET_sh2s (&rekey->kid),
2903 GNUNET_h2s (&(receiver->ss_rekey->master)));
2904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2905 "Sending rekey with cmac %s\n",
2906 GNUNET_h2s (&(receiver->ss_rekey->cmac)));
2907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2908 "%u rekey kces left.\n",
2909 receiver->number_rekeying_kce);
2910
2911 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
2912 rekey_dgram,
2913 sizeof(rekey_dgram),
2914 receiver->address,
2915 receiver->address_len))
2916 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
2917
2918 receiver->acks_available--;
2919 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2920 "%u receiver->acks_available 1\n",
2921 receiver->acks_available);
2922 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2923 "Sending UDPRekey to %s\n", GNUNET_a2s (receiver->address,
2924 receiver->
2925 address_len));
2926 }
2927 }
2928}
2929
2930
2931/**
2932 * Signature of functions implementing the sending functionality of a
2933 * message queue.
2934 *
2935 * @param mq the message queue
2936 * @param msg the message to send
2937 * @param impl_state our `struct ReceiverAddress`
2938 */
2939static void
2940mq_send_d (struct GNUNET_MQ_Handle *mq,
2941 const struct GNUNET_MessageHeader *msg,
2942 void *impl_state)
2943{
2944 struct ReceiverAddress *receiver = impl_state;
2945 uint16_t msize = ntohs (msg->size);
2946
2947 GNUNET_assert (mq == receiver->d_mq);
2948 if ((msize > receiver->d_mtu) ||
2949 (0 == receiver->acks_available))
2950 {
2951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2952 "msize: %u, mtu: %lu, acks: %u\n",
2953 msize,
2954 receiver->d_mtu,
2955 receiver->acks_available);
2956
2957 GNUNET_break (0);
2958 if (GNUNET_YES != receiver->receiver_destroy_called)
2959 receiver_destroy (receiver);
2960 return;
2961 }
2962 reschedule_receiver_timeout (receiver);
2963
2964 /* begin "BOX" encryption method, scan for ACKs from tail! */
2965 for (struct SharedSecret *ss = receiver->ss_tail; NULL != ss; ss = ss->prev)
2966 {
2967 if (0 < ss->sequence_used)
2968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2969 "Trying to send UDPBox with shared secrect %s sequence_used %u and ss->sequence_allowed %u\n",
2970 GNUNET_h2s (&ss->master),
2971 ss->sequence_used,
2972 ss->sequence_allowed);
2973 // Uncomment this for alternativ 1 of backchannel functionality
2974 if (ss->sequence_used >= ss->sequence_allowed)
2975 // Until here for alternativ 1
2976 // Uncomment this for alternativ 2 of backchannel functionality
2977 // if (0 == ss->sequence_allowed)
2978 // Until here for alternativ 2
2979 {
2980 continue;
2981 }
2982 char dgram[sizeof(struct UDPBox) + receiver->d_mtu];
2983 struct UDPBox *box;
2984 gcry_cipher_hd_t out_cipher;
2985 size_t dpos;
2986
2987 box = (struct UDPBox *) dgram;
2988 ss->sequence_used++;
2989 get_kid (&ss->master, ss->sequence_used, &box->kid);
2990 setup_cipher (&ss->master, ss->sequence_used, &out_cipher);
2991 /* Append encrypted payload to dgram */
2992 dpos = sizeof(struct UDPBox);
2993 GNUNET_assert (
2994 0 == gcry_cipher_encrypt (out_cipher, &dgram[dpos], msize, msg, msize));
2995 dpos += msize;
2996 do_pad (out_cipher, &dgram[dpos], sizeof(dgram) - dpos);
2997 GNUNET_assert (0 == gcry_cipher_gettag (out_cipher,
2998 box->gcm_tag,
2999 sizeof(box->gcm_tag)));
3000 gcry_cipher_close (out_cipher);
3001
3002 receiver->rekey_send_bytes += sizeof(struct UDPBox) + receiver->d_mtu;
3003
3004 if (GNUNET_NO == receiver->rekeying)
3005 box->rekeying = GNUNET_NO;
3006 else
3007 box->rekeying = GNUNET_YES;
3008
3009 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
3010 dgram,
3011 sizeof(dgram),
3012 receiver->address,
3013 receiver->address_len))
3014 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
3015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3016 "Sending UDPBox with payload size %u, %u acks left\n",
3017 msize,
3018 receiver->acks_available);
3019 GNUNET_MQ_impl_send_continue (mq);
3020 receiver->acks_available--;
3021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3022 "%u receiver->acks_available 2\n",
3023 receiver->acks_available);
3024 check_for_rekeying (receiver, box);
3025 if (0 == receiver->acks_available - receiver->number_rekeying_kce)
3026 {
3027 /* We have no more ACKs */
3028 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3029 "No more acks\n");
3030 if (GNUNET_YES == receiver->rekeying)
3031 {
3032 receiver->rekeying = GNUNET_NO;
3033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3034 "Sender stopped rekeying\n");
3035
3036 if ((NULL != receiver->ss_rekey) && (0 <
3037 receiver->ss_rekey->
3038 sequence_allowed) )
3039 add_acks_rekey (receiver);
3040 }
3041 }
3042 else if ((GNUNET_YES == receiver->rekeying) )
3043 {
3044 send_UDPRekey (receiver, ss);
3045 }
3046
3047 return;
3048 }
3049}
3050
3051
3052/**
3053 * Signature of functions implementing the destruction of a message
3054 * queue. Implementations must not free @a mq, but should take care
3055 * of @a impl_state.
3056 *
3057 * @param mq the message queue to destroy
3058 * @param impl_state our `struct ReceiverAddress`
3059 */
3060static void
3061mq_destroy_d (struct GNUNET_MQ_Handle *mq, void *impl_state)
3062{
3063 struct ReceiverAddress *receiver = impl_state;
3064 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3065 "Default MQ destroyed\n");
3066 if (mq == receiver->d_mq)
3067 {
3068 receiver->d_mq = NULL;
3069 if (GNUNET_YES != receiver->receiver_destroy_called)
3070 receiver_destroy (receiver);
3071 }
3072}
3073
3074
3075/**
3076 * Signature of functions implementing the destruction of a message
3077 * queue. Implementations must not free @a mq, but should take care
3078 * of @a impl_state.
3079 *
3080 * @param mq the message queue to destroy
3081 * @param impl_state our `struct ReceiverAddress`
3082 */
3083static void
3084mq_destroy_kx (struct GNUNET_MQ_Handle *mq, void *impl_state)
3085{
3086 struct ReceiverAddress *receiver = impl_state;
3087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3088 "KX MQ destroyed\n");
3089 if (mq == receiver->kx_mq)
3090 {
3091 receiver->kx_mq = NULL;
3092 if (GNUNET_YES != receiver->receiver_destroy_called)
3093 receiver_destroy (receiver);
3094 }
3095}
3096
3097
3098/**
3099 * Implementation function that cancels the currently sent message.
3100 *
3101 * @param mq message queue
3102 * @param impl_state our `struct RecvierAddress`
3103 */
3104static void
3105mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
3106{
3107 /* Cancellation is impossible with UDP; bail */
3108 GNUNET_assert (0);
3109}
3110
3111
3112/**
3113 * Generic error handler, called with the appropriate
3114 * error code and the same closure specified at the creation of
3115 * the message queue.
3116 * Not every message queue implementation supports an error handler.
3117 *
3118 * @param cls our `struct ReceiverAddress`
3119 * @param error error code
3120 */
3121static void
3122mq_error (void *cls, enum GNUNET_MQ_Error error)
3123{
3124 struct ReceiverAddress *receiver = cls;
3125
3126 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3127 "MQ error in queue to %s: %d\n",
3128 GNUNET_i2s (&receiver->target),
3129 (int) error);
3130 receiver_destroy (receiver);
3131}
3132
3133
3134/**
3135 * Setup the MQ for the @a receiver. If a queue exists,
3136 * the existing one is destroyed. Then the MTU is
3137 * recalculated and a fresh queue is initialized.
3138 *
3139 * @param receiver receiver to setup MQ for
3140 */
3141static void
3142setup_receiver_mq (struct ReceiverAddress *receiver)
3143{
3144 size_t base_mtu;
3145
3146 /*if (NULL != receiver->kx_qh)
3147 {
3148 GNUNET_TRANSPORT_communicator_mq_del (receiver->kx_qh);
3149 receiver->kx_qh = NULL;
3150 }
3151 if (NULL != receiver->d_qh)
3152 {
3153 GNUNET_TRANSPORT_communicator_mq_del (receiver->d_qh);
3154 receiver->d_qh = NULL;
3155 }*/
3156 // GNUNET_assert (NULL == receiver->mq);
3157 switch (receiver->address->sa_family)
3158 {
3159 case AF_INET:
3160 base_mtu = 1480 /* Ethernet MTU, 1500 - Ethernet header - VLAN tag */
3161 - sizeof(struct GNUNET_TUN_IPv4Header) /* 20 */
3162 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
3163 break;
3164
3165 case AF_INET6:
3166 base_mtu = 1280 /* Minimum MTU required by IPv6 */
3167 - sizeof(struct GNUNET_TUN_IPv6Header) /* 40 */
3168 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
3169 break;
3170
3171 default:
3172 GNUNET_assert (0);
3173 break;
3174 }
3175 /* MTU based on full KX messages */
3176 receiver->kx_mtu = base_mtu - sizeof(struct InitialKX) /* 48 */
3177 - sizeof(struct UDPConfirmation); /* 104 */
3178 /* MTU based on BOXed messages */
3179 receiver->d_mtu = base_mtu - sizeof(struct UDPBox);
3180
3181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3182 "Setting up MQs and QHs\n");
3183 /* => Effective MTU for CORE will range from 1080 (IPv6 + KX) to
3184 1404 (IPv4 + Box) bytes, depending on circumstances... */
3185 if (NULL == receiver->kx_mq)
3186 receiver->kx_mq = GNUNET_MQ_queue_for_callbacks (&mq_send_kx,
3187 &mq_destroy_kx,
3188 &mq_cancel,
3189 receiver,
3190 NULL,
3191 &mq_error,
3192 receiver);
3193 if (NULL == receiver->d_mq)
3194 receiver->d_mq = GNUNET_MQ_queue_for_callbacks (&mq_send_d,
3195 &mq_destroy_d,
3196 &mq_cancel,
3197 receiver,
3198 NULL,
3199 &mq_error,
3200 receiver);
3201
3202 receiver->kx_qh =
3203 GNUNET_TRANSPORT_communicator_mq_add (ch,
3204 &receiver->target,
3205 receiver->foreign_addr,
3206 receiver->kx_mtu,
3207 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
3208 0, /* Priority */
3209 receiver->nt,
3210 GNUNET_TRANSPORT_CS_OUTBOUND,
3211 receiver->kx_mq);
3212}
3213
3214
3215/**
3216 * Function called by the transport service to initialize a
3217 * message queue given address information about another peer.
3218 * If and when the communication channel is established, the
3219 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
3220 * to notify the service that the channel is now up. It is
3221 * the responsibility of the communicator to manage sane
3222 * retries and timeouts for any @a peer/@a address combination
3223 * provided by the transport service. Timeouts and retries
3224 * do not need to be signalled to the transport service.
3225 *
3226 * @param cls closure
3227 * @param peer identity of the other peer
3228 * @param address where to send the message, human-readable
3229 * communicator-specific format, 0-terminated, UTF-8
3230 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is
3231 * invalid
3232 */
3233static int
3234mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
3235{
3236 struct ReceiverAddress *receiver;
3237 const char *path;
3238 struct sockaddr *in;
3239 socklen_t in_len;
3240
3241 if (0 != strncmp (address,
3242 COMMUNICATOR_ADDRESS_PREFIX "-",
3243 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
3244 {
3245 GNUNET_break_op (0);
3246 return GNUNET_SYSERR;
3247 }
3248 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
3249 in = udp_address_to_sockaddr (path, &in_len);
3250
3251 receiver = GNUNET_new (struct ReceiverAddress);
3252 receiver->address = in;
3253 receiver->address_len = in_len;
3254 receiver->target = *peer;
3255 receiver->nt = GNUNET_NT_scanner_get_type (is, in, in_len);
3256 (void) GNUNET_CONTAINER_multipeermap_put (
3257 receivers,
3258 &receiver->target,
3259 receiver,
3260 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
3261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3262 "Added %s to receivers\n",
3263 GNUNET_i2s_full (&receiver->target));
3264 receiver->timeout =
3265 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
3266 receiver->hn = GNUNET_CONTAINER_heap_insert (receivers_heap,
3267 receiver,
3268 receiver->timeout.abs_value_us);
3269 GNUNET_STATISTICS_set (stats,
3270 "# receivers active",
3271 GNUNET_CONTAINER_multipeermap_size (receivers),
3272 GNUNET_NO);
3273 receiver->foreign_addr =
3274 sockaddr_to_udpaddr_string (receiver->address, receiver->address_len);
3275 setup_receiver_mq (receiver);
3276 if (NULL == timeout_task)
3277 timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL);
3278 return GNUNET_OK;
3279}
3280
3281
3282/**
3283 * Iterator over all receivers to clean up.
3284 *
3285 * @param cls NULL
3286 * @param target unused
3287 * @param value the queue to destroy
3288 * @return #GNUNET_OK to continue to iterate
3289 */
3290static int
3291get_receiver_delete_it (void *cls,
3292 const struct GNUNET_PeerIdentity *target,
3293 void *value)
3294{
3295 struct ReceiverAddress *receiver = value;
3296
3297 (void) cls;
3298 (void) target;
3299 receiver_destroy (receiver);
3300 return GNUNET_OK;
3301}
3302
3303
3304/**
3305 * Iterator over all senders to clean up.
3306 *
3307 * @param cls NULL
3308 * @param target unused
3309 * @param value the queue to destroy
3310 * @return #GNUNET_OK to continue to iterate
3311 */
3312static int
3313get_sender_delete_it (void *cls,
3314 const struct GNUNET_PeerIdentity *target,
3315 void *value)
3316{
3317 struct SenderAddress *sender = value;
3318
3319 (void) cls;
3320 (void) target;
3321
3322 if (NULL != sender->kce_task_rekey)
3323 {
3324 GNUNET_SCHEDULER_cancel (sender->kce_task_rekey);
3325 sender->kce_task_rekey = NULL;
3326 }
3327 if (NULL != sender->kce_task)
3328 {
3329 GNUNET_SCHEDULER_cancel (sender->kce_task);
3330 sender->kce_task = NULL;
3331 }
3332
3333 sender_destroy (sender);
3334 return GNUNET_OK;
3335}
3336
3337
3338/**
3339 * Shutdown the UNIX communicator.
3340 *
3341 * @param cls NULL (always)
3342 */
3343static void
3344do_shutdown (void *cls)
3345{
3346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3347 "do_shutdown\n");
3348 if (NULL != nat)
3349 {
3350 GNUNET_NAT_unregister (nat);
3351 nat = NULL;
3352 }
3353 while (NULL != bi_head)
3354 bi_destroy (bi_head);
3355 if (NULL != broadcast_task)
3356 {
3357 GNUNET_SCHEDULER_cancel (broadcast_task);
3358 broadcast_task = NULL;
3359 }
3360 if (NULL != timeout_task)
3361 {
3362 GNUNET_SCHEDULER_cancel (timeout_task);
3363 timeout_task = NULL;
3364 }
3365 if (NULL != read_task)
3366 {
3367 GNUNET_SCHEDULER_cancel (read_task);
3368 read_task = NULL;
3369 }
3370 if (NULL != udp_sock)
3371 {
3372 GNUNET_break (GNUNET_OK ==
3373 GNUNET_NETWORK_socket_close (udp_sock));
3374 udp_sock = NULL;
3375 }
3376 GNUNET_CONTAINER_multipeermap_iterate (receivers,
3377 &get_receiver_delete_it,
3378 NULL);
3379 GNUNET_CONTAINER_multipeermap_destroy (receivers);
3380 GNUNET_CONTAINER_multipeermap_iterate (senders,
3381 &get_sender_delete_it,
3382 NULL);
3383 GNUNET_CONTAINER_multipeermap_destroy (senders);
3384 GNUNET_CONTAINER_multishortmap_destroy (key_cache);
3385 GNUNET_CONTAINER_heap_destroy (senders_heap);
3386 GNUNET_CONTAINER_heap_destroy (receivers_heap);
3387 if (NULL != timeout_task)
3388 {
3389 GNUNET_SCHEDULER_cancel (timeout_task);
3390 timeout_task = NULL;
3391 }
3392 if (NULL != ch)
3393 {
3394 GNUNET_TRANSPORT_communicator_disconnect (ch);
3395 ch = NULL;
3396 }
3397 if (NULL != ah)
3398 {
3399 GNUNET_TRANSPORT_application_done (ah);
3400 ah = NULL;
3401 }
3402 if (NULL != stats)
3403 {
3404 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
3405 stats = NULL;
3406 }
3407 if (NULL != my_private_key)
3408 {
3409 GNUNET_free (my_private_key);
3410 my_private_key = NULL;
3411 }
3412 if (NULL != is)
3413 {
3414 GNUNET_NT_scanner_done (is);
3415 is = NULL;
3416 }
3417 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3418 "do_shutdown finished\n");
3419}
3420
3421
3422/**
3423 * Function called when the transport service has received a
3424 * backchannel message for this communicator (!) via a different return
3425 * path. Should be an acknowledgement.
3426 *
3427 * @param cls closure, NULL
3428 * @param sender which peer sent the notification
3429 * @param msg payload
3430 */
3431static void
3432enc_notify_cb (void *cls,
3433 const struct GNUNET_PeerIdentity *sender,
3434 const struct GNUNET_MessageHeader *msg)
3435{
3436 const struct UDPAck *ack;
3437
3438 (void) cls;
3439 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3440 "Storing UDPAck received from backchannel from %s\n",
3441 GNUNET_i2s_full (sender));
3442 if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK) ||
3443 (ntohs (msg->size) != sizeof(struct UDPAck)))
3444 {
3445 GNUNET_break_op (0);
3446 return;
3447 }
3448 ack = (const struct UDPAck *) msg;
3449 GNUNET_CONTAINER_multipeermap_get_multiple (receivers,
3450 sender,
3451 &handle_ack,
3452 (void *) ack);
3453}
3454
3455
3456/**
3457 * Signature of the callback passed to #GNUNET_NAT_register() for
3458 * a function to call whenever our set of 'valid' addresses changes.
3459 *
3460 * @param cls closure
3461 * @param app_ctx[in,out] location where the app can store stuff
3462 * on add and retrieve it on remove
3463 * @param add_remove #GNUNET_YES to add a new public IP address,
3464 * #GNUNET_NO to remove a previous (now invalid) one
3465 * @param ac address class the address belongs to
3466 * @param addr either the previous or the new public IP address
3467 * @param addrlen actual length of the @a addr
3468 */
3469static void
3470nat_address_cb (void *cls,
3471 void **app_ctx,
3472 int add_remove,
3473 enum GNUNET_NAT_AddressClass ac,
3474 const struct sockaddr *addr,
3475 socklen_t addrlen)
3476{
3477 char *my_addr;
3478 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
3479
3480 if (GNUNET_YES == add_remove)
3481 {
3482 enum GNUNET_NetworkType nt;
3483
3484 GNUNET_asprintf (&my_addr,
3485 "%s-%s",
3486 COMMUNICATOR_ADDRESS_PREFIX,
3487 GNUNET_a2s (addr, addrlen));
3488 nt = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3489 ai =
3490 GNUNET_TRANSPORT_communicator_address_add (ch,
3491 my_addr,
3492 nt,
3493 GNUNET_TIME_UNIT_FOREVER_REL);
3494 GNUNET_free (my_addr);
3495 *app_ctx = ai;
3496 }
3497 else
3498 {
3499 ai = *app_ctx;
3500 GNUNET_TRANSPORT_communicator_address_remove (ai);
3501 *app_ctx = NULL;
3502 }
3503}
3504
3505
3506/**
3507 * Broadcast our presence on one of our interfaces.
3508 *
3509 * @param cls a `struct BroadcastInterface`
3510 */
3511static void
3512ifc_broadcast (void *cls)
3513{
3514 struct BroadcastInterface *bi = cls;
3515 struct GNUNET_TIME_Relative delay;
3516
3517 delay = BROADCAST_FREQUENCY;
3518 delay.rel_value_us =
3519 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, delay.rel_value_us);
3520 bi->broadcast_task =
3521 GNUNET_SCHEDULER_add_delayed (delay, &ifc_broadcast, bi);
3522
3523 switch (bi->sa->sa_family)
3524 {
3525 case AF_INET: {
3526 static int yes = 1;
3527 static int no = 0;
3528 ssize_t sent;
3529
3530 if (GNUNET_OK !=
3531 GNUNET_NETWORK_socket_setsockopt (udp_sock,
3532 SOL_SOCKET,
3533 SO_BROADCAST,
3534 &yes,
3535 sizeof(int)))
3536 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3537 "setsockopt");
3538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3539 "creating UDPBroadcast from %s\n",
3540 GNUNET_i2s (&(bi->bcm.sender)));
3541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3542 "sending UDPBroadcast to add %s\n",
3543 GNUNET_a2s (bi->ba, bi->salen));
3544 sent = GNUNET_NETWORK_socket_sendto (udp_sock,
3545 &bi->bcm,
3546 sizeof(bi->bcm),
3547 bi->ba,
3548 bi->salen);
3549 if (-1 == sent)
3550 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3551 "sendto");
3552 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
3553 SOL_SOCKET,
3554 SO_BROADCAST,
3555 &no,
3556 sizeof(int)))
3557 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3558 "setsockopt");
3559 break;
3560 }
3561
3562 case AF_INET6: {
3563 ssize_t sent;
3564 struct sockaddr_in6 dst;
3565
3566 dst.sin6_family = AF_INET6;
3567 dst.sin6_port = htons (my_port);
3568 dst.sin6_addr = bi->mcreq.ipv6mr_multiaddr;
3569 dst.sin6_scope_id = ((struct sockaddr_in6 *) bi->ba)->sin6_scope_id;
3570
3571 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3572 "sending UDPBroadcast\n");
3573 sent = GNUNET_NETWORK_socket_sendto (udp_sock,
3574 &bi->bcm,
3575 sizeof(bi->bcm),
3576 (const struct sockaddr *) &dst,
3577 sizeof(dst));
3578 if (-1 == sent)
3579 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
3580 break;
3581 }
3582
3583 default:
3584 GNUNET_break (0);
3585 break;
3586 }
3587}
3588
3589
3590/**
3591 * Callback function invoked for each interface found.
3592 * Activates/deactivates broadcast interfaces.
3593 *
3594 * @param cls NULL
3595 * @param name name of the interface (can be NULL for unknown)
3596 * @param isDefault is this presumably the default interface
3597 * @param addr address of this interface (can be NULL for unknown or unassigned)
3598 * @param broadcast_addr the broadcast address (can be NULL for unknown or
3599 * unassigned)
3600 * @param netmask the network mask (can be NULL for unknown or unassigned)
3601 * @param addrlen length of the address
3602 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
3603 */
3604static int
3605iface_proc (void *cls,
3606 const char *name,
3607 int isDefault,
3608 const struct sockaddr *addr,
3609 const struct sockaddr *broadcast_addr,
3610 const struct sockaddr *netmask,
3611 socklen_t addrlen)
3612{
3613 struct BroadcastInterface *bi;
3614 enum GNUNET_NetworkType network;
3615 struct UdpBroadcastSignature ubs;
3616
3617 (void) cls;
3618 (void) netmask;
3619 if (NULL == addr)
3620 return GNUNET_YES; /* need to know our address! */
3621 network = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3622 if (GNUNET_NT_LOOPBACK == network)
3623 {
3624 /* Broadcasting on loopback does not make sense */
3625 return GNUNET_YES;
3626 }
3627 for (bi = bi_head; NULL != bi; bi = bi->next)
3628 {
3629 if ((bi->salen == addrlen) && (0 == memcmp (addr, bi->sa, addrlen)))
3630 {
3631 bi->found = GNUNET_YES;
3632 return GNUNET_OK;
3633 }
3634 }
3635
3636 if ((AF_INET6 == addr->sa_family) && (NULL == broadcast_addr))
3637 return GNUNET_OK; /* broadcast_addr is required for IPv6! */
3638 if ((AF_INET6 == addr->sa_family) && (GNUNET_YES != have_v6_socket))
3639 return GNUNET_OK; /* not using IPv6 */
3640
3641 bi = GNUNET_new (struct BroadcastInterface);
3642 bi->sa = GNUNET_memdup (addr,
3643 addrlen);
3644 if ( (NULL != broadcast_addr) &&
3645 (addrlen == sizeof (struct sockaddr_in)) )
3646 {
3647 struct sockaddr_in *ba;
3648
3649 ba = GNUNET_memdup (broadcast_addr,
3650 addrlen);
3651 ba->sin_port = htons (2086); /* always GNUnet port, ignore configuration! */
3652 bi->ba = (struct sockaddr *) ba;
3653 }
3654 bi->salen = addrlen;
3655 bi->found = GNUNET_YES;
3656 bi->bcm.sender = my_identity;
3657 ubs.purpose.purpose = htonl (
3658 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST);
3659 ubs.purpose.size = htonl (sizeof(ubs));
3660 ubs.sender = my_identity;
3661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3662 "creating UDPBroadcastSignature for %s\n",
3663 GNUNET_a2s (addr, addrlen));
3664 GNUNET_CRYPTO_hash (addr, addrlen, &ubs.h_address);
3665 GNUNET_CRYPTO_eddsa_sign (my_private_key,
3666 &ubs,
3667 &bi->bcm.sender_sig);
3668 if (NULL != bi->ba)
3669 {
3670 bi->broadcast_task = GNUNET_SCHEDULER_add_now (&ifc_broadcast, bi);
3671 GNUNET_CONTAINER_DLL_insert (bi_head, bi_tail, bi);
3672 }
3673 if ((AF_INET6 == addr->sa_family) && (NULL != broadcast_addr))
3674 {
3675 /* Create IPv6 multicast request */
3676 const struct sockaddr_in6 *s6 =
3677 (const struct sockaddr_in6 *) broadcast_addr;
3678
3679 GNUNET_assert (
3680 1 == inet_pton (AF_INET6, "FF05::13B", &bi->mcreq.ipv6mr_multiaddr));
3681
3682 /* http://tools.ietf.org/html/rfc2553#section-5.2:
3683 *
3684 * IPV6_JOIN_GROUP
3685 *
3686 * Join a multicast group on a specified local interface. If the
3687 * interface index is specified as 0, the kernel chooses the local
3688 * interface. For example, some kernels look up the multicast
3689 * group in the normal IPv6 routing table and using the resulting
3690 * interface; we do this for each interface, so no need to use
3691 * zero (anymore...).
3692 */bi->mcreq.ipv6mr_interface = s6->sin6_scope_id;
3693
3694 /* Join the multicast group */
3695 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
3696 IPPROTO_IPV6,
3697 IPV6_JOIN_GROUP,
3698 &bi->mcreq,
3699 sizeof(bi->mcreq)))
3700 {
3701 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
3702 }
3703 }
3704 return GNUNET_OK;
3705}
3706
3707
3708/**
3709 * Scan interfaces to broadcast our presence on the LAN.
3710 *
3711 * @param cls NULL, unused
3712 */
3713static void
3714do_broadcast (void *cls)
3715{
3716 struct BroadcastInterface *bin;
3717
3718 (void) cls;
3719 for (struct BroadcastInterface *bi = bi_head; NULL != bi; bi = bi->next)
3720 bi->found = GNUNET_NO;
3721 GNUNET_OS_network_interfaces_list (&iface_proc, NULL);
3722 for (struct BroadcastInterface *bi = bi_head; NULL != bi; bi = bin)
3723 {
3724 bin = bi->next;
3725 if (GNUNET_NO == bi->found)
3726 bi_destroy (bi);
3727 }
3728 broadcast_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY,
3729 &do_broadcast,
3730 NULL);
3731}
3732
3733
3734/**
3735 * Setup communicator and launch network interactions.
3736 *
3737 * @param cls NULL (always)
3738 * @param args remaining command-line arguments
3739 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
3740 * @param c configuration
3741 */
3742static void
3743run (void *cls,
3744 char *const *args,
3745 const char *cfgfile,
3746 const struct GNUNET_CONFIGURATION_Handle *c)
3747{
3748 char *bindto;
3749 struct sockaddr *in;
3750 socklen_t in_len;
3751 struct sockaddr_storage in_sto;
3752 socklen_t sto_len;
3753
3754 (void) cls;
3755 cfg = c;
3756 if (GNUNET_OK !=
3757 GNUNET_CONFIGURATION_get_value_string (cfg,
3758 COMMUNICATOR_CONFIG_SECTION,
3759 "BINDTO",
3760 &bindto))
3761 {
3762 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3763 COMMUNICATOR_CONFIG_SECTION,
3764 "BINDTO");
3765 return;
3766 }
3767
3768 if (GNUNET_OK !=
3769 GNUNET_CONFIGURATION_get_value_time (cfg,
3770 COMMUNICATOR_CONFIG_SECTION,
3771 "REKEY_INTERVAL",
3772 &rekey_interval))
3773 rekey_interval = DEFAULT_REKEY_TIME_INTERVAL;
3774
3775 if (GNUNET_OK !=
3776 GNUNET_CONFIGURATION_get_value_size (cfg,
3777 COMMUNICATOR_CONFIG_SECTION,
3778 "REKEY_MAX_BYTES",
3779 &rekey_max_bytes))
3780 rekey_max_bytes = DEFAULT_REKEY_MAX_BYTES;
3781
3782 in = udp_address_to_sockaddr (bindto, &in_len);
3783 if (NULL == in)
3784 {
3785 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3786 "Failed to setup UDP socket address with path `%s'\n",
3787 bindto);
3788 GNUNET_free (bindto);
3789 return;
3790 }
3791 udp_sock =
3792 GNUNET_NETWORK_socket_create (in->sa_family,
3793 SOCK_DGRAM,
3794 IPPROTO_UDP);
3795 if (NULL == udp_sock)
3796 {
3797 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
3798 GNUNET_free (in);
3799 GNUNET_free (bindto);
3800 return;
3801 }
3802 if (AF_INET6 == in->sa_family)
3803 have_v6_socket = GNUNET_YES;
3804 if (GNUNET_OK !=
3805 GNUNET_NETWORK_socket_bind (udp_sock,
3806 in,
3807 in_len))
3808 {
3809 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
3810 "bind",
3811 bindto);
3812 GNUNET_NETWORK_socket_close (udp_sock);
3813 udp_sock = NULL;
3814 GNUNET_free (in);
3815 GNUNET_free (bindto);
3816 return;
3817 }
3818
3819 /* We might have bound to port 0, allowing the OS to figure it out;
3820 thus, get the real IN-address from the socket */
3821 sto_len = sizeof(in_sto);
3822 if (0 != getsockname (GNUNET_NETWORK_get_fd (udp_sock),
3823 (struct sockaddr *) &in_sto,
3824 &sto_len))
3825 {
3826 memcpy (&in_sto, in, in_len);
3827 sto_len = in_len;
3828 }
3829 GNUNET_free (in);
3830 GNUNET_free (bindto);
3831 in = (struct sockaddr *) &in_sto;
3832 in_len = sto_len;
3833 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
3834 "transport",
3835 "Bound to `%s'\n",
3836 GNUNET_a2s ((const struct sockaddr *) &in_sto,
3837 sto_len));
3838 switch (in->sa_family)
3839 {
3840 case AF_INET:
3841 my_port = ntohs (((struct sockaddr_in *) in)->sin_port);
3842 break;
3843
3844 case AF_INET6:
3845 my_port = ntohs (((struct sockaddr_in6 *) in)->sin6_port);
3846 break;
3847
3848 default:
3849 GNUNET_break (0);
3850 my_port = 0;
3851 }
3852 stats = GNUNET_STATISTICS_create ("C-UDP", cfg);
3853 senders = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
3854 receivers = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
3855 senders_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3856 receivers_heap =
3857 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3858 key_cache = GNUNET_CONTAINER_multishortmap_create (1024, GNUNET_YES);
3859 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
3860 is = GNUNET_NT_scanner_init ();
3861 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
3862 if (NULL == my_private_key)
3863 {
3864 GNUNET_log (
3865 GNUNET_ERROR_TYPE_ERROR,
3866 _ (
3867 "Transport service is lacking key configuration settings. Exiting.\n"));
3868 GNUNET_SCHEDULER_shutdown ();
3869 return;
3870 }
3871 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
3872 /* start reading */
3873 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3874 udp_sock,
3875 &sock_read,
3876 NULL);
3877 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
3878 COMMUNICATOR_CONFIG_SECTION,
3879 COMMUNICATOR_ADDRESS_PREFIX,
3880 GNUNET_TRANSPORT_CC_UNRELIABLE,
3881 &mq_init,
3882 NULL,
3883 &enc_notify_cb,
3884 NULL);
3885 if (NULL == ch)
3886 {
3887 GNUNET_break (0);
3888 GNUNET_SCHEDULER_shutdown ();
3889 return;
3890 }
3891 ah = GNUNET_TRANSPORT_application_init (cfg);
3892 if (NULL == ah)
3893 {
3894 GNUNET_break (0);
3895 GNUNET_SCHEDULER_shutdown ();
3896 return;
3897 }
3898 /* start broadcasting */
3899 if (GNUNET_YES !=
3900 GNUNET_CONFIGURATION_get_value_yesno (cfg,
3901 COMMUNICATOR_CONFIG_SECTION,
3902 "DISABLE_BROADCAST"))
3903 {
3904 broadcast_task = GNUNET_SCHEDULER_add_now (&do_broadcast, NULL);
3905 }
3906 nat = GNUNET_NAT_register (cfg,
3907 COMMUNICATOR_CONFIG_SECTION,
3908 IPPROTO_UDP,
3909 1 /* one address */,
3910 (const struct sockaddr **) &in,
3911 &in_len,
3912 &nat_address_cb,
3913 NULL /* FIXME: support reversal: #5529 */,
3914 NULL /* closure */);
3915}
3916
3917
3918/**
3919 * The main function for the UNIX communicator.
3920 *
3921 * @param argc number of arguments from the command line
3922 * @param argv command line arguments
3923 * @return 0 ok, 1 on error
3924 */
3925int
3926main (int argc, char *const *argv)
3927{
3928 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
3929 GNUNET_GETOPT_OPTION_END
3930 };
3931 int ret;
3932
3933 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
3934 "transport",
3935 "Starting udp communicator\n");
3936 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
3937 return 2;
3938
3939 ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
3940 argv,
3941 "gnunet-communicator-udp",
3942 _ ("GNUnet UDP communicator"),
3943 options,
3944 &run,
3945 NULL))
3946 ? 0
3947 : 1;
3948 GNUNET_free_nz ((void *) argv);
3949 return ret;
3950}
3951
3952
3953/* end of gnunet-communicator-udp.c */
diff --git a/src/transport/gnunet-communicator-unix.c b/src/transport/gnunet-communicator-unix.c
deleted file mode 100644
index d7e18f87a..000000000
--- a/src/transport/gnunet-communicator-unix.c
+++ /dev/null
@@ -1,1167 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2010-2014, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/gnunet-communicator-unix.c
23 * @brief Transport plugin using unix domain sockets (!)
24 * Clearly, can only be used locally on Unix/Linux hosts...
25 * ONLY INTENDED FOR TESTING!!!
26 * @author Christian Grothoff
27 * @author Nathan Evans
28 */
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_protocols.h"
32#include "gnunet_constants.h"
33#include "gnunet_nt_lib.h"
34#include "gnunet_statistics_service.h"
35#include "gnunet_transport_communication_service.h"
36
37/**
38 * How many messages do we keep at most in the queue to the
39 * transport service before we start to drop (default,
40 * can be changed via the configuration file).
41 * Should be _below_ the level of the communicator API, as
42 * otherwise we may read messages just to have them dropped
43 * by the communicator API.
44 */
45#define DEFAULT_MAX_QUEUE_LENGTH 8000
46
47/**
48 * Address prefix used by the communicator.
49 */
50#define COMMUNICATOR_ADDRESS_PREFIX "unix"
51
52/**
53 * Configuration section used by the communicator.
54 */
55#define COMMUNICATOR_CONFIG_SECTION "communicator-unix"
56
57/**
58 * Our MTU.
59 */
60#ifndef DARWIN
61#define UNIX_MTU UINT16_MAX
62#else
63#define UNIX_MTU 2048
64#endif
65
66GNUNET_NETWORK_STRUCT_BEGIN
67
68/**
69 * UNIX Message-Packet header.
70 */
71struct UNIXMessage
72{
73 /**
74 * Message header.
75 */
76 struct GNUNET_MessageHeader header;
77
78 /**
79 * What is the identity of the sender (GNUNET_hash of public key)
80 */
81 struct GNUNET_PeerIdentity sender;
82};
83
84GNUNET_NETWORK_STRUCT_END
85
86
87/**
88 * Handle for a queue.
89 */
90struct Queue
91{
92 /**
93 * Queues with pending messages (!) are kept in a DLL.
94 */
95 struct Queue *next;
96
97 /**
98 * Queues with pending messages (!) are kept in a DLL.
99 */
100 struct Queue *prev;
101
102 /**
103 * To whom are we talking to.
104 */
105 struct GNUNET_PeerIdentity target;
106
107 /**
108 * Address of the other peer.
109 */
110 struct sockaddr_un *address;
111
112 /**
113 * Length of the address.
114 */
115 socklen_t address_len;
116
117 /**
118 * Message currently scheduled for transmission, non-NULL if and only
119 * if this queue is in the #queue_head DLL.
120 */
121 struct UNIXMessage *msg;
122
123 /**
124 * Message queue we are providing for the #ch.
125 */
126 struct GNUNET_MQ_Handle *mq;
127
128 /**
129 * handle for this queue with the #ch.
130 */
131 struct GNUNET_TRANSPORT_QueueHandle *qh;
132
133 /**
134 * Number of bytes we currently have in our write queue.
135 */
136 unsigned long long bytes_in_queue;
137
138 /**
139 * Timeout for this queue.
140 */
141 struct GNUNET_TIME_Absolute timeout;
142
143 /**
144 * Queue timeout task.
145 */
146 struct GNUNET_SCHEDULER_Task *timeout_task;
147};
148
149/**
150 * My Peer Identity
151 */
152static struct GNUNET_PeerIdentity my_identity;
153
154/**
155 * ID of read task
156 */
157static struct GNUNET_SCHEDULER_Task *read_task;
158
159/**
160 * ID of write task
161 */
162static struct GNUNET_SCHEDULER_Task *write_task;
163
164/**
165 * Number of messages we currently have in our queues towards the transport service.
166 */
167static unsigned long long delivering_messages;
168
169/**
170 * Maximum queue length before we stop reading towards the transport service.
171 */
172static unsigned long long max_queue_length;
173
174/**
175 * For logging statistics.
176 */
177static struct GNUNET_STATISTICS_Handle *stats;
178
179/**
180 * Our environment.
181 */
182static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
183
184/**
185 * Queues (map from peer identity to `struct Queue`)
186 */
187static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
188
189/**
190 * Head of queue of messages to transmit.
191 */
192static struct Queue *queue_head;
193
194/**
195 * Tail of queue of messages to transmit.
196 */
197static struct Queue *queue_tail;
198
199/**
200 * socket that we transmit all data with
201 */
202static struct GNUNET_NETWORK_Handle *unix_sock;
203
204/**
205 * Handle to the operation that publishes our address.
206 */
207static struct GNUNET_TRANSPORT_AddressIdentifier *ai;
208
209
210/**
211 * Functions with this signature are called whenever we need
212 * to close a queue due to a disconnect or failure to
213 * establish a connection.
214 *
215 * @param queue queue to close down
216 */
217static void
218queue_destroy (struct Queue *queue)
219{
220 struct GNUNET_MQ_Handle *mq;
221
222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
223 "Disconnecting queue for peer `%s'\n",
224 GNUNET_i2s (&queue->target));
225 if (0 != queue->bytes_in_queue)
226 {
227 GNUNET_CONTAINER_DLL_remove (queue_head, queue_tail, queue);
228 queue->bytes_in_queue = 0;
229 }
230 if (NULL != (mq = queue->mq))
231 {
232 queue->mq = NULL;
233 GNUNET_MQ_destroy (mq);
234 }
235 GNUNET_assert (
236 GNUNET_YES ==
237 GNUNET_CONTAINER_multipeermap_remove (queue_map, &queue->target, queue));
238 GNUNET_STATISTICS_set (stats,
239 "# queues active",
240 GNUNET_CONTAINER_multipeermap_size (queue_map),
241 GNUNET_NO);
242 if (NULL != queue->timeout_task)
243 {
244 GNUNET_SCHEDULER_cancel (queue->timeout_task);
245 queue->timeout_task = NULL;
246 }
247 GNUNET_free (queue->address);
248 GNUNET_free (queue);
249}
250
251
252/**
253 * Queue was idle for too long, so disconnect it
254 *
255 * @param cls the `struct Queue *` to disconnect
256 */
257static void
258queue_timeout (void *cls)
259{
260 struct Queue *queue = cls;
261 struct GNUNET_TIME_Relative left;
262
263 queue->timeout_task = NULL;
264 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
265 if (0 != left.rel_value_us)
266 {
267 /* not actually our turn yet, but let's at least update
268 the monitor, it may think we're about to die ... */
269 queue->timeout_task =
270 GNUNET_SCHEDULER_add_delayed (left, &queue_timeout, queue);
271 return;
272 }
273 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
274 "Queue %p was idle for %s, disconnecting\n",
275 queue,
276 GNUNET_STRINGS_relative_time_to_string (
277 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
278 GNUNET_YES));
279 queue_destroy (queue);
280}
281
282
283/**
284 * Increment queue timeout due to activity. We do not immediately
285 * notify the monitor here as that might generate excessive
286 * signalling.
287 *
288 * @param queue queue for which the timeout should be rescheduled
289 */
290static void
291reschedule_queue_timeout (struct Queue *queue)
292{
293 GNUNET_assert (NULL != queue->timeout_task);
294 queue->timeout =
295 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
296}
297
298
299/**
300 * Convert unix path to a `struct sockaddr_un *`
301 *
302 * @param unixpath path to convert
303 * @param[out] sock_len set to the length of the address
304 * @param is_abstract is this an abstract @a unixpath
305 * @return converted unix path
306 */
307static struct sockaddr_un *
308unix_address_to_sockaddr (const char *unixpath, socklen_t *sock_len)
309{
310 struct sockaddr_un *un;
311 size_t slen;
312
313 GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
314 un = GNUNET_new (struct sockaddr_un);
315 un->sun_family = AF_UNIX;
316 slen = strlen (unixpath);
317 if (slen >= sizeof(un->sun_path))
318 slen = sizeof(un->sun_path) - 1;
319 GNUNET_memcpy (un->sun_path, unixpath, slen);
320 un->sun_path[slen] = '\0';
321 slen = sizeof(struct sockaddr_un);
322#if HAVE_SOCKADDR_UN_SUN_LEN
323 un->sun_len = (u_char) slen;
324#endif
325 (*sock_len) = slen;
326 if ('@' == un->sun_path[0])
327 un->sun_path[0] = '\0';
328 return un;
329}
330
331
332/**
333 * Closure to #lookup_queue_it().
334 */
335struct LookupCtx
336{
337 /**
338 * Location to store the queue, if found.
339 */
340 struct Queue *res;
341
342 /**
343 * Address we are looking for.
344 */
345 const struct sockaddr_un *un;
346
347 /**
348 * Number of bytes in @a un
349 */
350 socklen_t un_len;
351};
352
353
354/**
355 * Function called to find a queue by address.
356 *
357 * @param cls the `struct LookupCtx *`
358 * @param key peer we are looking for (unused)
359 * @param value a queue
360 * @return #GNUNET_YES if not found (continue looking), #GNUNET_NO on success
361 */
362static int
363lookup_queue_it (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
364{
365 struct LookupCtx *lctx = cls;
366 struct Queue *queue = value;
367
368 if ((queue->address_len == lctx->un_len) &&
369 (0 == memcmp (lctx->un, queue->address, queue->address_len)))
370 {
371 lctx->res = queue;
372 return GNUNET_NO;
373 }
374 return GNUNET_YES;
375}
376
377
378/**
379 * Find an existing queue by address.
380 *
381 * @param plugin the plugin
382 * @param address the address to find
383 * @return NULL if queue was not found
384 */
385static struct Queue *
386lookup_queue (const struct GNUNET_PeerIdentity *peer,
387 const struct sockaddr_un *un,
388 socklen_t un_len)
389{
390 struct LookupCtx lctx;
391
392 lctx.un = un;
393 lctx.un_len = un_len;
394 lctx.res = NULL;
395 GNUNET_CONTAINER_multipeermap_get_multiple (queue_map,
396 peer,
397 &lookup_queue_it,
398 &lctx);
399 return lctx.res;
400}
401
402
403/**
404 * We have been notified that our socket is ready to write.
405 * Then reschedule this function to be called again once more is available.
406 *
407 * @param cls NULL
408 */
409static void
410select_write_cb (void *cls)
411{
412 struct Queue *queue = queue_tail;
413 const struct GNUNET_MessageHeader *msg = &queue->msg->header;
414 size_t msg_size = ntohs (msg->size);
415 ssize_t sent;
416
417 /* take queue of the ready list */
418 write_task = NULL;
419resend:
420 /* Send the data */
421 sent = GNUNET_NETWORK_socket_sendto (unix_sock,
422 msg,
423 msg_size,
424 (const struct sockaddr *) queue->address,
425 queue->address_len);
426 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
427 "UNIX transmitted message to %s (%d/%u: %s)\n",
428 GNUNET_i2s (&queue->target),
429 (int) sent,
430 (unsigned int) msg_size,
431 (sent < 0) ? strerror (errno) : "ok");
432 if (-1 != sent)
433 {
434 GNUNET_CONTAINER_DLL_remove (queue_head, queue_tail, queue);
435 if (NULL != queue_head)
436 write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
437 unix_sock,
438 &select_write_cb,
439 NULL);
440
441 /* send 'msg' */
442 GNUNET_free (queue->msg);
443 queue->msg = NULL;
444 GNUNET_MQ_impl_send_continue (queue->mq);
445 GNUNET_STATISTICS_update (stats,
446 "# bytes sent",
447 (long long) sent,
448 GNUNET_NO);
449 reschedule_queue_timeout (queue);
450 return; /* all good */
451 }
452 GNUNET_STATISTICS_update (stats,
453 "# network transmission failures",
454 1,
455 GNUNET_NO);
456 write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
457 unix_sock,
458 &select_write_cb,
459 NULL);
460 switch (errno)
461 {
462 case EAGAIN:
463 case ENOBUFS:
464 /* We should retry later... */
465 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
466 return;
467
468 case EMSGSIZE: {
469 socklen_t size = 0;
470 socklen_t len = sizeof(size);
471
472 GNUNET_NETWORK_socket_getsockopt (unix_sock,
473 SOL_SOCKET,
474 SO_SNDBUF,
475 &size,
476 &len);
477 if (size > ntohs (msg->size))
478 {
479 /* Buffer is bigger than message: error, no retry
480 * This should never happen!*/
481 GNUNET_break (0);
482 return;
483 }
484 GNUNET_log (
485 GNUNET_ERROR_TYPE_WARNING,
486 "Trying to increase socket buffer size from %u to %u for message size %u\n",
487 (unsigned int) size,
488 (unsigned int) ((msg_size / 1000) + 2) * 1000,
489 (unsigned int) msg_size);
490 size = ((msg_size / 1000) + 2) * 1000;
491 if (GNUNET_OK == GNUNET_NETWORK_socket_setsockopt (unix_sock,
492 SOL_SOCKET,
493 SO_SNDBUF,
494 &size,
495 sizeof(size)))
496 goto resend; /* Increased buffer size, retry sending */
497 /* Ok, then just try very modest increase */
498 size = msg_size;
499 if (GNUNET_OK == GNUNET_NETWORK_socket_setsockopt (unix_sock,
500 SOL_SOCKET,
501 SO_SNDBUF,
502 &size,
503 sizeof(size)))
504 goto resend; /* Increased buffer size, retry sending */
505 /* Could not increase buffer size: error, no retry */
506 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
507 return;
508 }
509
510 default:
511 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "send");
512 return;
513 }
514}
515
516
517/**
518 * Signature of functions implementing the sending functionality of a
519 * message queue.
520 *
521 * @param mq the message queue
522 * @param msg the message to send
523 * @param impl_state our `struct Queue`
524 */
525static void
526mq_send (struct GNUNET_MQ_Handle *mq,
527 const struct GNUNET_MessageHeader *msg,
528 void *impl_state)
529{
530 struct Queue *queue = impl_state;
531 size_t msize = ntohs (msg->size);
532
533 GNUNET_assert (mq == queue->mq);
534 GNUNET_assert (NULL == queue->msg);
535 // Convert to UNIXMessage
536 queue->msg = GNUNET_malloc (msize + sizeof (struct UNIXMessage));
537 queue->msg->header.size = htons (msize + sizeof (struct UNIXMessage));
538 queue->msg->sender = my_identity;
539 memcpy (&queue->msg[1], msg, msize);
540 GNUNET_CONTAINER_DLL_insert (queue_head, queue_tail, queue);
541 GNUNET_assert (NULL != unix_sock);
542 if (NULL == write_task)
543 write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
544 unix_sock,
545 &select_write_cb,
546 NULL);
547}
548
549
550/**
551 * Signature of functions implementing the destruction of a message
552 * queue. Implementations must not free @a mq, but should take care
553 * of @a impl_state.
554 *
555 * @param mq the message queue to destroy
556 * @param impl_state our `struct Queue`
557 */
558static void
559mq_destroy (struct GNUNET_MQ_Handle *mq, void *impl_state)
560{
561 struct Queue *queue = impl_state;
562
563 if (mq == queue->mq)
564 {
565 queue->mq = NULL;
566 queue_destroy (queue);
567 }
568}
569
570
571/**
572 * Implementation function that cancels the currently sent message.
573 *
574 * @param mq message queue
575 * @param impl_state our `struct Queue`
576 */
577static void
578mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
579{
580 struct Queue *queue = impl_state;
581
582 GNUNET_assert (NULL != queue->msg);
583 queue->msg = NULL;
584 GNUNET_CONTAINER_DLL_remove (queue_head, queue_tail, queue);
585 GNUNET_assert (NULL != write_task);
586 if (NULL == queue_head)
587 {
588 GNUNET_SCHEDULER_cancel (write_task);
589 write_task = NULL;
590 }
591}
592
593
594/**
595 * Generic error handler, called with the appropriate
596 * error code and the same closure specified at the creation of
597 * the message queue.
598 * Not every message queue implementation supports an error handler.
599 *
600 * @param cls our `struct Queue`
601 * @param error error code
602 */
603static void
604mq_error (void *cls, enum GNUNET_MQ_Error error)
605{
606 struct Queue *queue = cls;
607
608 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
609 "UNIX MQ error in queue to %s: %d\n",
610 GNUNET_i2s (&queue->target),
611 (int) error);
612 queue_destroy (queue);
613}
614
615
616/**
617 * Creates a new outbound queue the transport service will use to send
618 * data to another peer.
619 *
620 * @param peer the target peer
621 * @param cs inbound or outbound queue
622 * @param un the address
623 * @param un_len number of bytes in @a un
624 * @return the queue or NULL of max connections exceeded
625 */
626static struct Queue *
627setup_queue (const struct GNUNET_PeerIdentity *target,
628 enum GNUNET_TRANSPORT_ConnectionStatus cs,
629 const struct sockaddr_un *un,
630 socklen_t un_len)
631{
632 struct Queue *queue;
633
634 queue = GNUNET_new (struct Queue);
635 queue->target = *target;
636 queue->address = GNUNET_memdup (un, un_len);
637 queue->address_len = un_len;
638 (void) GNUNET_CONTAINER_multipeermap_put (
639 queue_map,
640 &queue->target,
641 queue,
642 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
643 GNUNET_STATISTICS_set (stats,
644 "# queues active",
645 GNUNET_CONTAINER_multipeermap_size (queue_map),
646 GNUNET_NO);
647 queue->timeout =
648 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
649 queue->timeout_task =
650 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
651 &queue_timeout,
652 queue);
653 queue->mq = GNUNET_MQ_queue_for_callbacks (&mq_send,
654 &mq_destroy,
655 &mq_cancel,
656 queue,
657 NULL,
658 &mq_error,
659 queue);
660 {
661 char *foreign_addr;
662
663 if ('\0' == un->sun_path[0])
664 GNUNET_asprintf (&foreign_addr,
665 "%s-@%s",
666 COMMUNICATOR_ADDRESS_PREFIX,
667 &un->sun_path[1]);
668 else
669 GNUNET_asprintf (&foreign_addr,
670 "%s-%s",
671 COMMUNICATOR_ADDRESS_PREFIX,
672 un->sun_path);
673 queue->qh = GNUNET_TRANSPORT_communicator_mq_add (ch,
674 &queue->target,
675 foreign_addr,
676 UNIX_MTU - sizeof (struct
677 UNIXMessage),
678 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
679 0,
680 GNUNET_NT_LOOPBACK,
681 cs,
682 queue->mq);
683 GNUNET_free (foreign_addr);
684 }
685 return queue;
686}
687
688
689/**
690 * We have been notified that our socket has something to read. Do the
691 * read and reschedule this function to be called again once more is
692 * available.
693 *
694 * @param cls NULL
695 */
696static void
697select_read_cb (void *cls);
698
699
700/**
701 * Function called when message was successfully passed to
702 * transport service. Continue read activity.
703 *
704 * @param cls NULL
705 * @param success #GNUNET_OK on success
706 */
707static void
708receive_complete_cb (void *cls, int success)
709{
710 (void) cls;
711 delivering_messages--;
712 if (GNUNET_OK != success)
713 GNUNET_STATISTICS_update (stats,
714 "# transport transmission failures",
715 1,
716 GNUNET_NO);
717 if ((NULL == read_task) && (delivering_messages < max_queue_length) &&
718 (NULL != unix_sock))
719 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
720 unix_sock,
721 &select_read_cb,
722 NULL);
723}
724
725
726/**
727 * We have been notified that our socket has something to read. Do the
728 * read and reschedule this function to be called again once more is
729 * available.
730 *
731 * @param cls NULL
732 */
733static void
734select_read_cb (void *cls)
735{
736 char buf[65536] GNUNET_ALIGN;
737 struct Queue *queue;
738 const struct UNIXMessage *msg;
739 struct sockaddr_un un;
740 socklen_t addrlen;
741 ssize_t ret;
742 uint16_t msize;
743
744 GNUNET_assert (NULL != unix_sock);
745 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
746 unix_sock,
747 &select_read_cb,
748 NULL);
749 addrlen = sizeof(un);
750 memset (&un, 0, sizeof(un));
751 ret = GNUNET_NETWORK_socket_recvfrom (unix_sock,
752 buf,
753 sizeof(buf),
754 (struct sockaddr *) &un,
755 &addrlen);
756 if ((-1 == ret) && ((EAGAIN == errno) || (ENOBUFS == errno)))
757 return;
758 if (-1 == ret)
759 {
760 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
761 return;
762 }
763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
764 "Read %d bytes from socket %s\n",
765 (int) ret,
766 un.sun_path);
767 GNUNET_assert (AF_UNIX == (un.sun_family));
768 msg = (struct UNIXMessage *) buf;
769 msize = ntohs (msg->header.size);
770 if ((msize < sizeof(struct UNIXMessage)) || (msize > ret))
771 {
772 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
773 "Wrong message size: %d bytes\n",
774 msize);
775 GNUNET_break_op (0);
776 return;
777 }
778 queue = lookup_queue (&msg->sender, &un, addrlen);
779 if (NULL == queue)
780 queue =
781 setup_queue (&msg->sender, GNUNET_TRANSPORT_CS_INBOUND, &un, addrlen);
782 else
783 reschedule_queue_timeout (queue);
784 if (NULL == queue)
785 {
786 GNUNET_log (
787 GNUNET_ERROR_TYPE_ERROR,
788 _ (
789 "Maximum number of UNIX connections exceeded, dropping incoming message\n"));
790 return;
791 }
792
793 {
794 uint16_t tsize = msize - sizeof(struct UNIXMessage);
795
796 const struct GNUNET_MessageHeader *currhdr;
797 struct GNUNET_MessageHeader al_hdr;
798
799 currhdr = (const struct GNUNET_MessageHeader *) &msg[1];
800 /* ensure aligned access */
801 memcpy (&al_hdr, currhdr, sizeof(al_hdr));
802 if ((tsize < sizeof(struct GNUNET_MessageHeader)) ||
803 (tsize != ntohs (al_hdr.size)))
804 {
805 GNUNET_break_op (0);
806 return;
807 }
808 ret = GNUNET_TRANSPORT_communicator_receive (ch,
809 &msg->sender,
810 currhdr,
811 GNUNET_TIME_UNIT_FOREVER_REL,
812 &receive_complete_cb,
813 NULL);
814 if (GNUNET_SYSERR == ret)
815 {
816 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
817 "Transport not up!\n");
818 return; /* transport not up */
819 }
820 if (GNUNET_NO == ret)
821 {
822 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
823 "Error sending message to transport\n");
824 return;
825 }
826 delivering_messages++;
827 }
828 if (delivering_messages >= max_queue_length)
829 {
830 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
831 "Back pressure %llu\n", delivering_messages);
832
833 /* we should try to apply 'back pressure' */
834 GNUNET_SCHEDULER_cancel (read_task);
835 read_task = NULL;
836 }
837}
838
839
840/**
841 * Function called by the transport service to initialize a
842 * message queue given address information about another peer.
843 * If and when the communication channel is established, the
844 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
845 * to notify the service that the channel is now up. It is
846 * the responsibility of the communicator to manage sane
847 * retries and timeouts for any @a peer/@a address combination
848 * provided by the transport service. Timeouts and retries
849 * do not need to be signalled to the transport service.
850 *
851 * @param cls closure
852 * @param peer identity of the other peer
853 * @param address where to send the message, human-readable
854 * communicator-specific format, 0-terminated, UTF-8
855 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is invalid
856 */
857static int
858mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
859{
860 struct Queue *queue;
861 const char *path;
862 struct sockaddr_un *un;
863 socklen_t un_len;
864
865 (void) cls;
866 if (0 != strncmp (address,
867 COMMUNICATOR_ADDRESS_PREFIX "-",
868 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
869 {
870 GNUNET_break_op (0);
871 return GNUNET_SYSERR;
872 }
873 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
874 un = unix_address_to_sockaddr (path, &un_len);
875 queue = lookup_queue (peer, un, un_len);
876 if (NULL != queue)
877 {
878 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
879 "Address `%s' for %s ignored, queue exists\n",
880 path,
881 GNUNET_i2s (peer));
882 GNUNET_free (un);
883 return GNUNET_OK;
884 }
885 queue = setup_queue (peer, GNUNET_TRANSPORT_CS_OUTBOUND, un, un_len);
886 GNUNET_free (un);
887 if (NULL == queue)
888 {
889 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
890 "Failed to setup queue to %s at `%s'\n",
891 GNUNET_i2s (peer),
892 path);
893 return GNUNET_NO;
894 }
895 return GNUNET_OK;
896}
897
898
899/**
900 * Iterator over all message queues to clean up.
901 *
902 * @param cls NULL
903 * @param target unused
904 * @param value the queue to destroy
905 * @return #GNUNET_OK to continue to iterate
906 */
907static int
908get_queue_delete_it (void *cls,
909 const struct GNUNET_PeerIdentity *target,
910 void *value)
911{
912 struct Queue *queue = value;
913
914 (void) cls;
915 (void) target;
916 queue_destroy (queue);
917 return GNUNET_OK;
918}
919
920
921/**
922 * Shutdown the UNIX communicator.
923 *
924 * @param cls NULL (always)
925 */
926static void
927do_shutdown (void *cls)
928{
929 if (NULL != read_task)
930 {
931 GNUNET_SCHEDULER_cancel (read_task);
932 read_task = NULL;
933 }
934 if (NULL != write_task)
935 {
936 GNUNET_SCHEDULER_cancel (write_task);
937 write_task = NULL;
938 }
939 if (NULL != unix_sock)
940 {
941 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (unix_sock));
942 unix_sock = NULL;
943 }
944 GNUNET_CONTAINER_multipeermap_iterate (queue_map, &get_queue_delete_it, NULL);
945 GNUNET_CONTAINER_multipeermap_destroy (queue_map);
946 if (NULL != ai)
947 {
948 GNUNET_TRANSPORT_communicator_address_remove (ai);
949 ai = NULL;
950 }
951 if (NULL != ch)
952 {
953 GNUNET_TRANSPORT_communicator_disconnect (ch);
954 ch = NULL;
955 }
956 if (NULL != stats)
957 {
958 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
959 stats = NULL;
960 }
961}
962
963
964/**
965 * Function called when the transport service has received an
966 * acknowledgement for this communicator (!) via a different return
967 * path.
968 *
969 * Not applicable for UNIX.
970 *
971 * @param cls closure
972 * @param sender which peer sent the notification
973 * @param msg payload
974 */
975static void
976enc_notify_cb (void *cls,
977 const struct GNUNET_PeerIdentity *sender,
978 const struct GNUNET_MessageHeader *msg)
979{
980 (void) cls;
981 (void) sender;
982 (void) msg;
983 GNUNET_break_op (0);
984}
985
986
987/**
988 * Setup communicator and launch network interactions.
989 *
990 * @param cls NULL (always)
991 * @param args remaining command-line arguments
992 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
993 * @param cfg configuration
994 */
995static void
996run (void *cls,
997 char *const *args,
998 const char *cfgfile,
999 const struct GNUNET_CONFIGURATION_Handle *cfg)
1000{
1001 char *unix_socket_path;
1002 struct sockaddr_un *un;
1003 socklen_t un_len;
1004 char *my_addr;
1005 struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
1006
1007 (void) cls;
1008 delivering_messages = 0;
1009
1010 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1011 if (NULL == my_private_key)
1012 {
1013 GNUNET_log (
1014 GNUNET_ERROR_TYPE_ERROR,
1015 _ (
1016 "UNIX communicator is lacking key configuration settings. Exiting.\n"));
1017 GNUNET_SCHEDULER_shutdown ();
1018 return;
1019 }
1020 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
1021
1022 if (GNUNET_OK !=
1023 GNUNET_CONFIGURATION_get_value_filename (cfg,
1024 COMMUNICATOR_CONFIG_SECTION,
1025 "UNIXPATH",
1026 &unix_socket_path))
1027 {
1028 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1029 COMMUNICATOR_CONFIG_SECTION,
1030 "UNIXPATH");
1031 return;
1032 }
1033 if (GNUNET_OK !=
1034 GNUNET_CONFIGURATION_get_value_number (cfg,
1035 COMMUNICATOR_CONFIG_SECTION,
1036 "MAX_QUEUE_LENGTH",
1037 &max_queue_length))
1038 max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
1039
1040 un = unix_address_to_sockaddr (unix_socket_path, &un_len);
1041 if (NULL == un)
1042 {
1043 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1044 "Failed to setup UNIX domain socket address with path `%s'\n",
1045 unix_socket_path);
1046 GNUNET_free (unix_socket_path);
1047 return;
1048 }
1049 unix_sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
1050 if (NULL == unix_sock)
1051 {
1052 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1053 GNUNET_free (un);
1054 GNUNET_free (unix_socket_path);
1055 return;
1056 }
1057 if (('\0' != un->sun_path[0]) &&
1058 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (un->sun_path)))
1059 {
1060 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1061 _ ("Cannot create path to `%s'\n"),
1062 un->sun_path);
1063 GNUNET_NETWORK_socket_close (unix_sock);
1064 unix_sock = NULL;
1065 GNUNET_free (un);
1066 GNUNET_free (unix_socket_path);
1067 return;
1068 }
1069 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (unix_sock,
1070 (const struct sockaddr *) un,
1071 un_len))
1072 {
1073 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "bind", un->sun_path);
1074 GNUNET_NETWORK_socket_close (unix_sock);
1075 unix_sock = NULL;
1076 GNUNET_free (un);
1077 GNUNET_free (unix_socket_path);
1078 return;
1079 }
1080 GNUNET_free (un);
1081 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", unix_socket_path);
1082 stats = GNUNET_STATISTICS_create ("C-UNIX", cfg);
1083 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1084 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1085 unix_sock,
1086 &select_read_cb,
1087 NULL);
1088 queue_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1089 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
1090 COMMUNICATOR_CONFIG_SECTION,
1091 COMMUNICATOR_ADDRESS_PREFIX,
1092 GNUNET_TRANSPORT_CC_RELIABLE,
1093 &mq_init,
1094 NULL,
1095 &enc_notify_cb,
1096 NULL);
1097 if (NULL == ch)
1098 {
1099 GNUNET_break (0);
1100 GNUNET_SCHEDULER_shutdown ();
1101 GNUNET_free (unix_socket_path);
1102 return;
1103 }
1104 GNUNET_asprintf (&my_addr,
1105 "%s-%s",
1106 COMMUNICATOR_ADDRESS_PREFIX,
1107 unix_socket_path);
1108 GNUNET_free (unix_socket_path);
1109 ai = GNUNET_TRANSPORT_communicator_address_add (ch,
1110 my_addr,
1111 GNUNET_NT_LOOPBACK,
1112 GNUNET_TIME_UNIT_FOREVER_REL);
1113 GNUNET_free (my_addr);
1114}
1115
1116
1117/**
1118 * The main function for the UNIX communicator.
1119 *
1120 * @param argc number of arguments from the command line
1121 * @param argv command line arguments
1122 * @return 0 ok, 1 on error
1123 */
1124int
1125main (int argc, char *const *argv)
1126{
1127 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1128 GNUNET_GETOPT_OPTION_END
1129 };
1130 int ret;
1131
1132 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1133 return 2;
1134
1135 ret = (GNUNET_OK ==
1136 GNUNET_PROGRAM_run (argc,
1137 argv,
1138 "gnunet-communicator-unix",
1139 _ ("GNUnet UNIX domain socket communicator"),
1140 options,
1141 &run,
1142 NULL))
1143 ? 0
1144 : 1;
1145 GNUNET_free_nz ((void *) argv);
1146 return ret;
1147}
1148
1149
1150#if defined(__linux__) && defined(__GLIBC__)
1151#include <malloc.h>
1152
1153/**
1154 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1155 */
1156void __attribute__ ((constructor))
1157GNUNET_ARM_memory_init ()
1158{
1159 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1160 mallopt (M_TOP_PAD, 1 * 1024);
1161 malloc_trim (0);
1162}
1163
1164
1165#endif
1166
1167/* end of gnunet-communicator-unix.c */
diff --git a/src/transport/gnunet-helper-transport-bluetooth.c b/src/transport/gnunet-helper-transport-bluetooth.c
deleted file mode 100644
index 019f3914f..000000000
--- a/src/transport/gnunet-helper-transport-bluetooth.c
+++ /dev/null
@@ -1,2285 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 GNUnet e.V.
4 Copyright (C) 2007, 2008, Andy Green <andy@warmcat.com>
5 Copyright (C) 2009 Thomas d'Otreppe
6
7 GNUnet is free software: you can redistribute it and/or modify it
8 under the terms of the GNU Affero General Public License as published
9 by the Free Software Foundation, either version 3 of the License,
10 or (at your option) any later version.
11
12 GNUnet is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 SPDX-License-Identifier: AGPL3.0-or-later
21 */
22#include "gnunet_config.h"
23
24#include <bluetooth/bluetooth.h>
25#include <bluetooth/hci.h>
26#include <bluetooth/hci_lib.h>
27#include <bluetooth/rfcomm.h>
28#include <bluetooth/sdp.h>
29#include <bluetooth/sdp_lib.h>
30#include <errno.h>
31#include <linux/if.h>
32#include <stdio.h>
33#include <stdlib.h>
34#include <sys/ioctl.h>
35#include <sys/param.h>
36#include <sys/socket.h>
37#include <sys/stat.h>
38#include <sys/types.h>
39#include <unistd.h>
40
41#include "plugin_transport_wlan.h"
42#include "gnunet_protocols.h"
43
44
45/**
46 * Maximum number of ports assignable for RFCOMMM protocol.
47 */
48#define MAX_PORTS 30
49
50/**
51 * Maximum size of a message allowed in either direction
52 * (used for our receive and sent buffers).
53 */
54#define MAXLINE 4096
55
56
57/**
58 * Maximum number of loops without inquiring for new devices.
59 */
60#define MAX_LOOPS 5
61
62/**
63 * In bluez library, the maximum name length of a device is 8
64 */
65#define BLUEZ_DEVNAME_SIZE 8
66
67/**
68 * struct for storing the information of the hardware. There is only
69 * one of these.
70 */
71struct HardwareInfos
72{
73 /**
74 * Name of the interface, not necessarily 0-terminated (!).
75 */
76 char iface[IFNAMSIZ];
77
78 /**
79 * file descriptor for the rfcomm socket
80 */
81 int fd_rfcomm;
82
83 /**
84 * MAC address of our own bluetooth interface.
85 */
86 struct GNUNET_TRANSPORT_WLAN_MacAddress pl_mac;
87
88 /**
89 * SDP session
90 */
91 sdp_session_t *session;
92};
93
94/**
95 * IO buffer used for buffering data in transit (to wireless or to stdout).
96 */
97struct SendBuffer
98{
99 /**
100 * How many bytes of data are stored in 'buf' for transmission right now?
101 * Data always starts at offset 0 and extends to 'size'.
102 */
103 size_t size;
104
105 /**
106 * How many bytes that were stored in 'buf' did we already write to the
107 * destination? Always smaller than 'size'.
108 */
109 size_t pos;
110
111 /**
112 * Buffered data; twice the maximum allowed message size as we add some
113 * headers.
114 */
115 char buf[MAXLINE * 2];
116};
117
118#ifdef __linux__
119/**
120 * Devices buffer used to keep a list with all the discoverable devices in
121 * order to send them HELLO messages one by one when it receive a broadcast message.
122 */
123struct BroadcastMessages
124{
125 /* List with the discoverable devices' addresses */
126 bdaddr_t devices[MAX_PORTS];
127
128 /* List with the open sockets */
129 int fds[MAX_PORTS];
130
131
132 /* The number of the devices */
133 int size;
134
135 /* The current position */
136 int pos;
137
138 /* The device id */
139 int dev_id;
140};
141
142/**
143 * Address used to identify the broadcast messages.
144 */
145static struct GNUNET_TRANSPORT_WLAN_MacAddress broadcast_address = { { 255, 255,
146 255, 255,
147 255,
148 255 } };
149
150/**
151 * Buffer with the discoverable devices.
152 */
153static struct BroadcastMessages neighbours;
154
155static int searching_devices_count = 0;
156#endif
157
158/**
159 * Buffer for data read from stdin to be transmitted to the bluetooth device
160 */
161static struct SendBuffer write_pout;
162
163/**
164 * Buffer for data read from the bluetooth device to be transmitted to stdout.
165 */
166static struct SendBuffer write_std;
167
168
169/* ****** this are the same functions as the ones used in gnunet-helper-transport-wlan.c ****** */
170
171/**
172 * To what multiple do we align messages? 8 byte should suffice for everyone
173 * for now.
174 */
175#define ALIGN_FACTOR 8
176
177/**
178 * Smallest supported message.
179 */
180#define MIN_BUFFER_SIZE sizeof(struct GNUNET_MessageHeader)
181
182
183/**
184 * Functions with this signature are called whenever a
185 * complete message is received by the tokenizer.
186 *
187 * @param cls closure
188 * @param message the actual message
189 */
190typedef void (*MessageTokenizerCallback) (void *cls,
191 const struct
192 GNUNET_MessageHeader *
193 message);
194
195/**
196 * Handle to a message stream tokenizer.
197 */
198struct MessageStreamTokenizer
199{
200 /**
201 * Function to call on completed messages.
202 */
203 MessageTokenizerCallback cb;
204
205 /**
206 * Closure for cb.
207 */
208 void *cb_cls;
209
210 /**
211 * Size of the buffer (starting at 'hdr').
212 */
213 size_t curr_buf;
214
215 /**
216 * How many bytes in buffer have we already processed?
217 */
218 size_t off;
219
220 /**
221 * How many bytes in buffer are valid right now?
222 */
223 size_t pos;
224
225 /**
226 * Beginning of the buffer. Typed like this to force alignment.
227 */
228 struct GNUNET_MessageHeader *hdr;
229};
230
231
232/**
233 * Create a message stream tokenizer.
234 *
235 * @param cb function to call on completed messages
236 * @param cb_cls closure for cb
237 * @return handle to tokenizer
238 */
239static struct MessageStreamTokenizer *
240mst_create (MessageTokenizerCallback cb,
241 void *cb_cls)
242{
243 struct MessageStreamTokenizer *ret;
244
245 ret = malloc (sizeof(struct MessageStreamTokenizer));
246 if (NULL == ret)
247 {
248 fprintf (stderr, "Failed to allocate buffer for tokenizer\n");
249 exit (1);
250 }
251 ret->hdr = malloc (MIN_BUFFER_SIZE);
252 if (NULL == ret->hdr)
253 {
254 fprintf (stderr, "Failed to allocate buffer for alignment\n");
255 exit (1);
256 }
257 ret->curr_buf = MIN_BUFFER_SIZE;
258 ret->cb = cb;
259 ret->cb_cls = cb_cls;
260 ret->pos = 0;
261
262 return ret;
263}
264
265
266/**
267 * Add incoming data to the receive buffer and call the
268 * callback for all complete messages.
269 *
270 * @param mst tokenizer to use
271 * @param buf input data to add
272 * @param size number of bytes in buf
273 * @return GNUNET_OK if we are done processing (need more data)
274 * GNUNET_SYSERR if the data stream is corrupt
275 */
276static int
277mst_receive (struct MessageStreamTokenizer *mst,
278 const char *buf, size_t size)
279{
280 const struct GNUNET_MessageHeader *hdr;
281 size_t delta;
282 uint16_t want;
283 char *ibuf;
284 int need_align;
285 unsigned long offset;
286 int ret;
287
288 ret = GNUNET_OK;
289 ibuf = (char *) mst->hdr;
290 while (mst->pos > 0)
291 {
292do_align:
293 if (mst->pos < mst->off)
294 {
295 // fprintf (stderr, "We processed too many bytes!\n");
296 return GNUNET_SYSERR;
297 }
298 if ((mst->curr_buf - mst->off < sizeof(struct GNUNET_MessageHeader)) ||
299 (0 != (mst->off % ALIGN_FACTOR)))
300 {
301 /* need to align or need more space */
302 mst->pos -= mst->off;
303 memmove (ibuf, &ibuf[mst->off], mst->pos);
304 mst->off = 0;
305 }
306 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
307 {
308 delta =
309 GNUNET_MIN (sizeof(struct GNUNET_MessageHeader)
310 - (mst->pos - mst->off), size);
311 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
312 mst->pos += delta;
313 buf += delta;
314 size -= delta;
315 }
316 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
317 {
318 // FIXME should I reset ??
319 // mst->off = 0;
320 // mst->pos = 0;
321 return GNUNET_OK;
322 }
323 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
324 want = ntohs (hdr->size);
325 if (want < sizeof(struct GNUNET_MessageHeader))
326 {
327 fprintf (stderr,
328 "Received invalid message from stdin\n");
329 return GNUNET_SYSERR;
330 }
331 if ((mst->curr_buf - mst->off < want) &&
332 (mst->off > 0))
333 {
334 /* need more space */
335 mst->pos -= mst->off;
336 memmove (ibuf, &ibuf[mst->off], mst->pos);
337 mst->off = 0;
338 }
339 if (want > mst->curr_buf)
340 {
341 if (mst->off != 0)
342 {
343 fprintf (stderr, "Error! We should proceeded 0 bytes\n");
344 return GNUNET_SYSERR;
345 }
346 mst->hdr = realloc (mst->hdr, want);
347 if (NULL == mst->hdr)
348 {
349 fprintf (stderr, "Failed to allocate buffer for alignment\n");
350 exit (1);
351 }
352 ibuf = (char *) mst->hdr;
353 mst->curr_buf = want;
354 }
355 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
356 if (mst->pos - mst->off < want)
357 {
358 delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
359 if (mst->pos + delta > mst->curr_buf)
360 {
361 fprintf (stderr, "The size of the buffer will be exceeded!\n");
362 return GNUNET_SYSERR;
363 }
364 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
365 mst->pos += delta;
366 buf += delta;
367 size -= delta;
368 }
369 if (mst->pos - mst->off < want)
370 {
371 // FIXME should I use this?
372 // mst->off = 0;
373 // mst->pos = 0;
374 return GNUNET_OK;
375 }
376 mst->cb (mst->cb_cls, hdr);
377 mst->off += want;
378 if (mst->off == mst->pos)
379 {
380 /* reset to beginning of buffer, it's free right now! */
381 mst->off = 0;
382 mst->pos = 0;
383 }
384 }
385 if (0 != mst->pos)
386 {
387 fprintf (stderr,
388 "There should some valid bytes in the buffer on this stage\n");
389 return GNUNET_SYSERR;
390 }
391 while (size > 0)
392 {
393 if (size < sizeof(struct GNUNET_MessageHeader))
394 break;
395 offset = (unsigned long) buf;
396 need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO;
397 if (GNUNET_NO == need_align)
398 {
399 /* can try to do zero-copy and process directly from original buffer */
400 hdr = (const struct GNUNET_MessageHeader *) buf;
401 want = ntohs (hdr->size);
402 if (want < sizeof(struct GNUNET_MessageHeader))
403 {
404 fprintf (stderr,
405 "Received invalid message from stdin\n");
406 // exit (1);
407 mst->off = 0;
408 return GNUNET_SYSERR;
409 }
410 if (size < want)
411 break; /* or not, buffer incomplete, so copy to private buffer... */
412 mst->cb (mst->cb_cls, hdr);
413 buf += want;
414 size -= want;
415 }
416 else
417 {
418 /* need to copy to private buffer to align;
419 * yes, we go a bit more spaghetti than usual here */
420 goto do_align;
421 }
422 }
423 if (size > 0)
424 {
425 if (size + mst->pos > mst->curr_buf)
426 {
427 mst->hdr = realloc (mst->hdr, size + mst->pos);
428 if (NULL == mst->hdr)
429 {
430 fprintf (stderr, "Failed to allocate buffer for alignment\n");
431 exit (1);
432 }
433 ibuf = (char *) mst->hdr;
434 mst->curr_buf = size + mst->pos;
435 }
436 if (mst->pos + size > mst->curr_buf)
437 {
438 fprintf (stderr,
439 "Assertion failed\n");
440 exit (1);
441 }
442 GNUNET_memcpy (&ibuf[mst->pos], buf, size);
443 mst->pos += size;
444 }
445 return ret;
446}
447
448
449/**
450 * Destroys a tokenizer.
451 *
452 * @param mst tokenizer to destroy
453 */
454static void
455mst_destroy (struct MessageStreamTokenizer *mst)
456{
457 free (mst->hdr);
458 free (mst);
459}
460
461
462/**
463 * Calculate crc32, the start of the calculation
464 *
465 * @param buf buffer to calc the crc
466 * @param len len of the buffer
467 * @return crc sum
468 */
469static unsigned long
470calc_crc_osdep (const unsigned char *buf, size_t len)
471{
472 static const unsigned long int crc_tbl_osdep[256] = {
473 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
474 0xE963A535, 0x9E6495A3,
475 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
476 0xE7B82D07, 0x90BF1D91,
477 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB,
478 0xF4D4B551, 0x83D385C7,
479 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
480 0xFA0F3D63, 0x8D080DF5,
481 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447,
482 0xD20D85FD, 0xA50AB56B,
483 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
484 0xDCD60DCF, 0xABD13D59,
485 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
486 0xCFBA9599, 0xB8BDA50F,
487 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11,
488 0xC1611DAB, 0xB6662D3D,
489 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
490 0x9FBFE4A5, 0xE8B8D433,
491 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
492 0x91646C97, 0xE6635C01,
493 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B,
494 0x8208F4C1, 0xF50FC457,
495 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49,
496 0x8CD37CF3, 0xFBD44C65,
497 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
498 0xA4D1C46D, 0xD3D6F4FB,
499 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
500 0xAA0A4C5F, 0xDD0D7CC9,
501 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
502 0xB966D409, 0xCE61E49F,
503 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
504 0xB7BD5C3B, 0xC0BA6CAD,
505 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF,
506 0x04DB2615, 0x73DC1683,
507 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
508 0x0A00AE27, 0x7D079EB1,
509 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
510 0x196C3671, 0x6E6B06E7,
511 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9,
512 0x17B7BE43, 0x60B08ED5,
513 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767,
514 0x3FB506DD, 0x48B2364B,
515 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
516 0x316E8EEF, 0x4669BE79,
517 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
518 0x220216B9, 0x5505262F,
519 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
520 0x2CD99E8B, 0x5BDEAE1D,
521 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
522 0x72076785, 0x05005713,
523 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
524 0x7CDCEFB7, 0x0BDBDF21,
525 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B,
526 0x6FB077E1, 0x18B74777,
527 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
528 0x616BFFD3, 0x166CCF45,
529 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
530 0x4969474D, 0x3E6E77DB,
531 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
532 0x47B2CF7F, 0x30B5FFE9,
533 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
534 0x54DE5729, 0x23D967BF,
535 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1,
536 0x5A05DF1B, 0x2D02EF8D
537 };
538
539 unsigned long crc = 0xFFFFFFFF;
540
541 for (; len > 0; len--, buf++)
542 crc = crc_tbl_osdep[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
543 return(~crc);
544}
545
546
547/**
548 * Calculate and check crc of the bluetooth packet
549 *
550 * @param buf buffer of the packet, with len + 4 bytes of data,
551 * the last 4 bytes being the checksum
552 * @param len length of the payload in data
553 * @return 0 on success (checksum matches), 1 on error
554 */
555static int
556check_crc_buf_osdep (const unsigned char *buf, size_t len)
557{
558 unsigned long crc;
559
560 crc = calc_crc_osdep (buf, len);
561 buf += len;
562 if ((((crc) & 0xFF) == buf[0]) && (((crc >> 8) & 0xFF) == buf[1]) &&
563 ( ((crc >> 16) & 0xFF) == buf[2]) && ( ((crc >> 24) & 0xFF) == buf[3]) )
564 return 0;
565 return 1;
566}
567
568
569/* ************** end of clone ***************** */
570#ifdef __linux__
571/**
572 * Function for assigning a port number
573 *
574 * @param socket the socket used to bind
575 * @param addr pointer to the rfcomm address
576 * @return 0 on success
577 */
578static int
579bind_socket (int socket, struct sockaddr_rc *addr)
580{
581 int port, status;
582
583 /* Bind every possible port (from 0 to 30) and stop when binding doesn't fail */
584 // FIXME : it should start from port 1, but on my computer it doesn't work :)
585 for (port = 3; port <= 30; port++)
586 {
587 addr->rc_channel = port;
588 status = bind (socket, (struct sockaddr *) addr, sizeof(struct
589 sockaddr_rc));
590 if (status == 0)
591 return 0;
592 }
593
594 return -1;
595}
596
597
598#endif
599
600/**
601 * Function used for creating the service record and registering it.
602 *
603 * @param dev pointer to the device struct
604 * @param rc_channel the rfcomm channel
605 * @return 0 on success
606 */
607static int
608register_service (struct HardwareInfos *dev, int rc_channel)
609{
610 /**
611 * 1. initializations
612 * 2. set the service ID, class, profile information
613 * 3. make the service record publicly browsable
614 * 4. register the RFCOMM channel
615 * 5. set the name, provider and description
616 * 6. register the service record to the local SDP server
617 * 7. cleanup
618 */uint8_t svc_uuid_int[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
619 dev->pl_mac.mac[5], dev->pl_mac.mac[4],
620 dev->pl_mac.mac[3],
621 dev->pl_mac.mac[2], dev->pl_mac.mac[1],
622 dev->pl_mac.mac[0] };
623 const char *service_dsc = "Bluetooth plugin services";
624 const char *service_prov = "GNUnet provider";
625 uuid_t root_uuid, rfcomm_uuid, svc_uuid;
626 sdp_list_t *root_list = 0, *rfcomm_list = 0, *proto_list = 0,
627 *access_proto_list = 0, *svc_list = 0;
628 sdp_record_t *record = 0;
629 sdp_data_t *channel = 0;
630
631 record = sdp_record_alloc ();
632
633 /* Set the general service ID */
634 sdp_uuid128_create (&svc_uuid, &svc_uuid_int);
635 svc_list = sdp_list_append (0, &svc_uuid);
636 sdp_set_service_classes (record, svc_list);
637 sdp_set_service_id (record, svc_uuid);
638
639 /* Make the service record publicly browsable */
640 sdp_uuid16_create (&root_uuid, PUBLIC_BROWSE_GROUP);
641 root_list = sdp_list_append (0, &root_uuid);
642 sdp_set_browse_groups (record, root_list);
643
644 /* Register the RFCOMM channel */
645 sdp_uuid16_create (&rfcomm_uuid, RFCOMM_UUID);
646 channel = sdp_data_alloc (SDP_UINT8, &rc_channel);
647 rfcomm_list = sdp_list_append (0, &rfcomm_uuid);
648 sdp_list_append (rfcomm_list, channel);
649 proto_list = sdp_list_append (0, rfcomm_list);
650
651 /* Set protocol information */
652 access_proto_list = sdp_list_append (0, proto_list);
653 sdp_set_access_protos (record, access_proto_list);
654
655 /* Set the name, provider, and description */
656 sdp_set_info_attr (record, dev->iface, service_prov, service_dsc);
657
658 /* Connect to the local SDP server */
659 dev->session = sdp_connect (BDADDR_ANY, BDADDR_LOCAL, SDP_RETRY_IF_BUSY);
660
661 if (! dev->session)
662 {
663 fprintf (stderr,
664 "Failed to connect to the SDP server on interface `%.*s': %s\n",
665 IFNAMSIZ, dev->iface, strerror (errno));
666 // FIXME exit?
667 return 1;
668 }
669
670 /* Register the service record */
671 if (sdp_record_register (dev->session, record, 0) < 0)
672 {
673 fprintf (stderr,
674 "Failed to register a service record on interface `%.*s': %s\n",
675 IFNAMSIZ, dev->iface, strerror (errno));
676 // FIXME exit?
677 return 1;
678 }
679
680 /* Cleanup */
681 sdp_data_free (channel);
682 sdp_list_free (root_list, 0);
683 sdp_list_free (rfcomm_list, 0);
684 sdp_list_free (proto_list, 0);
685 sdp_list_free (access_proto_list, 0);
686 sdp_list_free (svc_list, 0);
687 sdp_record_free (record);
688
689 return 0;
690}
691
692
693/**
694 * Function used for searching and browsing for a service. This will return the
695 * port number on which the service is running.
696 *
697 * @param dev pointer to the device struct
698 * @param dest target address
699 * @return channel
700 */
701static int
702get_channel (struct HardwareInfos *dev, bdaddr_t dest)
703{
704 /**
705 * 1. detect all nearby devices
706 * 2. for each device:
707 * 2.1. connect to the SDP server running
708 * 2.2. get a list of service records with the specific UUID
709 * 2.3. for each service record get a list of the protocol sequences and get
710 * the port number
711 */uint8_t svc_uuid_int[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
712 dest.b[5], dest.b[4], dest.b[3],
713 dest.b[2], dest.b[1], dest.b[0] };
714 sdp_session_t *session = 0;
715 sdp_list_t *search_list = 0, *attrid_list = 0, *response_list = 0, *it = 0;
716 uuid_t svc_uuid;
717 uint32_t range = 0x0000ffff;
718 int channel = -1;
719
720 /* Connect to the local SDP server */
721 session = sdp_connect (BDADDR_ANY, &dest, 0);
722 if (! session)
723 {
724 fprintf (stderr,
725 "Failed to connect to the SDP server on interface `%.*s': %s\n",
726 IFNAMSIZ, dev->iface, strerror (errno));
727 return -1;
728 }
729
730 sdp_uuid128_create (&svc_uuid, &svc_uuid_int);
731 search_list = sdp_list_append (0, &svc_uuid);
732 attrid_list = sdp_list_append (0, &range);
733
734 if (sdp_service_search_attr_req (session, search_list,
735 SDP_ATTR_REQ_RANGE, attrid_list,
736 &response_list) == 0)
737 {
738 for (it = response_list; it; it = it->next)
739 {
740 sdp_record_t *record = (sdp_record_t *) it->data;
741 sdp_list_t *proto_list = 0;
742 if (sdp_get_access_protos (record, &proto_list) == 0)
743 {
744 channel = sdp_get_proto_port (proto_list, RFCOMM_UUID);
745 sdp_list_free (proto_list, 0);
746 }
747 sdp_record_free (record);
748 }
749 }
750
751 sdp_list_free (search_list, 0);
752 sdp_list_free (attrid_list, 0);
753 sdp_list_free (response_list, 0);
754
755 sdp_close (session);
756
757 if (-1 == channel)
758 fprintf (stderr,
759 "Failed to find the listening channel for interface `%.*s': %s\n",
760 IFNAMSIZ,
761 dev->iface,
762 strerror (errno));
763
764 return channel;
765}
766
767
768/**
769 * Read from the socket and put the result into the buffer for transmission to 'stdout'.
770 *
771 * @param sock file descriptor for reading
772 * @param buf buffer to read to; first bytes will be the 'struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame',
773 * followed by the actual payload
774 * @param buf_size size of the buffer
775 * @param ri where to write radiotap_rx info
776 * @return number of bytes written to 'buf'
777 */
778static ssize_t
779read_from_the_socket (void *sock,
780 unsigned char *buf, size_t buf_size,
781 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *ri)
782{
783 unsigned char tmpbuf[buf_size];
784 ssize_t count;
785 count = read (*((int *) sock), tmpbuf, buf_size);
786
787 if (0 > count)
788 {
789 if (EAGAIN == errno)
790 return 0;
791
792 fprintf (stderr, "Failed to read from the HCI socket: %s\n", strerror (
793 errno));
794
795 return -1;
796 }
797
798 #ifdef __linux__
799 /* Get the channel used */
800 int len;
801 struct sockaddr_rc rc_addr = { 0 };
802
803 memset (&rc_addr, 0, sizeof(rc_addr));
804 len = sizeof(rc_addr);
805 if (0 > getsockname (*((int *) sock), (struct sockaddr *) &rc_addr,
806 (socklen_t *) &len))
807 {
808 fprintf (stderr, "getsockname() call failed : %s\n", strerror (errno));
809 return -1;
810 }
811
812 memset (ri, 0, sizeof(*ri));
813 ri->ri_channel = rc_addr.rc_channel;
814 #endif
815
816 /* Detect CRC32 at the end */
817 if (0 == check_crc_buf_osdep (tmpbuf, count - sizeof(uint32_t)))
818 {
819 count -= sizeof(uint32_t);
820 }
821
822 GNUNET_memcpy (buf, tmpbuf, count);
823
824 return count;
825}
826
827
828/**
829 * Open the bluetooth interface for reading/writing
830 *
831 * @param dev pointer to the device struct
832 * @return 0 on success, non-zero on error
833 */
834static int
835open_device (struct HardwareInfos *dev)
836{
837 int i, dev_id = -1, fd_hci;
838 struct
839 {
840 struct hci_dev_list_req list;
841 struct hci_dev_req dev[HCI_MAX_DEV];
842 } request; // used for detecting the local devices
843 struct sockaddr_rc rc_addr = { 0 }; // used for binding
844
845 /* Initialize the neighbour structure */
846 neighbours.dev_id = -1;
847 for (i = 0; i < MAX_PORTS; i++)
848 neighbours.fds[i] = -1;
849
850 /* Open a HCI socket */
851 fd_hci = socket (AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
852
853 if (fd_hci < 0)
854 {
855 fprintf (stderr,
856 "Failed to create HCI socket: %s\n",
857 strerror (errno));
858 return -1;
859 }
860
861 memset (&request, 0, sizeof(request));
862 request.list.dev_num = HCI_MAX_DEV;
863
864 if (ioctl (fd_hci, HCIGETDEVLIST, (void *) &request) < 0)
865 {
866 fprintf (stderr,
867 "ioctl(HCIGETDEVLIST) on interface `%.*s' failed: %s\n",
868 IFNAMSIZ,
869 dev->iface,
870 strerror (errno));
871 (void) close (fd_hci);
872 return 1;
873 }
874
875 /* Search for a device with dev->iface name */
876 for (i = 0; i < request.list.dev_num; i++)
877 {
878 struct hci_dev_info dev_info;
879
880 memset (&dev_info, 0, sizeof(struct hci_dev_info));
881 dev_info.dev_id = request.dev[i].dev_id;
882 strncpy (dev_info.name, dev->iface, BLUEZ_DEVNAME_SIZE);
883
884 if (ioctl (fd_hci, HCIGETDEVINFO, (void *) &dev_info))
885 {
886 fprintf (stderr,
887 "ioctl(HCIGETDEVINFO) on interface `%.*s' failed: %s\n",
888 IFNAMSIZ,
889 dev->iface,
890 strerror (errno));
891 (void) close (fd_hci);
892 return 1;
893 }
894
895 if (strncmp (dev_info.name, dev->iface, BLUEZ_DEVNAME_SIZE) == 0)
896 {
897 dev_id = dev_info.dev_id; // the device was found
898 /**
899 * Copy the MAC address to the device structure
900 */
901 GNUNET_memcpy (&dev->pl_mac, &dev_info.bdaddr, sizeof(bdaddr_t));
902
903 /* Check if the interface is up */
904 if (hci_test_bit (HCI_UP, (void *) &dev_info.flags) == 0)
905 {
906 /* Bring the interface up */
907 if (ioctl (fd_hci, HCIDEVUP, dev_info.dev_id))
908 {
909 fprintf (stderr,
910 "ioctl(HCIDEVUP) on interface `%.*s' failed: %s\n",
911 IFNAMSIZ,
912 dev->iface,
913 strerror (errno));
914 (void) close (fd_hci);
915 return 1;
916 }
917 }
918
919 /* Check if the device is discoverable */
920 if ((hci_test_bit (HCI_PSCAN, (void *) &dev_info.flags) == 0) ||
921 (hci_test_bit (HCI_ISCAN, (void *) &dev_info.flags) == 0) )
922 {
923 /* Set interface Page Scan and Inqury Scan ON */
924 struct hci_dev_req dev_req;
925
926 memset (&dev_req, 0, sizeof(dev_req));
927 dev_req.dev_id = dev_info.dev_id;
928 dev_req.dev_opt = SCAN_PAGE | SCAN_INQUIRY;
929
930 if (ioctl (fd_hci, HCISETSCAN, (unsigned long) &dev_req))
931 {
932 fprintf (stderr,
933 "ioctl(HCISETSCAN) on interface `%.*s' failed: %s\n",
934 IFNAMSIZ,
935 dev->iface,
936 strerror (errno));
937 (void) close (fd_hci);
938 return 1;
939 }
940 }
941 break;
942 }
943 }
944
945 /* Check if the interface was not found */
946 if (-1 == dev_id)
947 {
948 fprintf (stderr,
949 "The interface %s was not found\n",
950 dev->iface);
951 (void) close (fd_hci);
952 return 1;
953 }
954
955 /* Close the hci socket */
956 (void) close (fd_hci);
957
958
959 /* Bind the rfcomm socket to the interface */
960 memset (&rc_addr, 0, sizeof(rc_addr));
961 rc_addr.rc_family = AF_BLUETOOTH;
962 rc_addr.rc_bdaddr = *BDADDR_ANY;
963
964 if (bind_socket (dev->fd_rfcomm, &rc_addr) != 0)
965 {
966 fprintf (stderr,
967 "Failed to bind interface `%.*s': %s\n",
968 IFNAMSIZ,
969 dev->iface,
970 strerror (errno));
971 return 1;
972 }
973
974 /* Register a SDP service */
975 if (register_service (dev, rc_addr.rc_channel) != 0)
976 {
977 fprintf (stderr,
978 "Failed to register a service on interface `%.*s': %s\n",
979 IFNAMSIZ,
980 dev->iface, strerror (errno));
981 return 1;
982 }
983
984 /* Switch socket in listening mode */
985 if (listen (dev->fd_rfcomm, 5) == -1) // FIXME: probably we need a bigger number
986 {
987 fprintf (stderr, "Failed to listen on socket for interface `%.*s': %s\n",
988 IFNAMSIZ,
989 dev->iface, strerror (errno));
990 return 1;
991 }
992
993 return 0;
994}
995
996
997/**
998 * Set the header to sane values to make attacks more difficult
999 *
1000 * @param taIeeeHeader pointer to the header of the packet
1001 * @param dev pointer to the Hardware_Infos struct
1002 *
1003 **** copy from gnunet-helper-transport-wlan.c ****
1004 */
1005static void
1006mac_set (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1007 const struct HardwareInfos *dev)
1008{
1009 taIeeeHeader->frame_control = htons (IEEE80211_FC0_TYPE_DATA);
1010 taIeeeHeader->addr3 = mac_bssid_gnunet;
1011 taIeeeHeader->addr2 = dev->pl_mac;
1012}
1013
1014
1015#ifdef __linux__
1016/**
1017 * Test if the given interface name really corresponds to a bluetooth
1018 * device.
1019 *
1020 * @param iface name of the interface
1021 * @return 0 on success, 1 on error
1022 **** similar with the one from gnunet-helper-transport-wlan.c ****
1023 */
1024static int
1025test_bluetooth_interface (const char *iface)
1026{
1027 char strbuf[512];
1028 struct stat sbuf;
1029 int ret;
1030
1031 ret = snprintf (strbuf, sizeof(strbuf),
1032 "/sys/class/bluetooth/%s/subsystem",
1033 iface);
1034 if ((ret < 0) || (ret >= sizeof(strbuf)) || (0 != stat (strbuf, &sbuf)))
1035 {
1036 fprintf (stderr,
1037 "Did not find 802.15.1 interface `%s'. Exiting.\n",
1038 iface);
1039 exit (1);
1040 }
1041 return 0;
1042}
1043
1044
1045#endif
1046
1047/**
1048 * Test incoming packets mac for being our own.
1049 *
1050 * @param taIeeeHeader buffer of the packet
1051 * @param dev the Hardware_Infos struct
1052 * @return 0 if mac belongs to us, 1 if mac is for another target
1053 *
1054 **** same as the one from gnunet-helper-transport-wlan.c ****
1055 */
1056static int
1057mac_test (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1058 const struct HardwareInfos *dev)
1059{
1060 static struct GNUNET_TRANSPORT_WLAN_MacAddress all_zeros;
1061
1062 if ((0 == memcmp (&taIeeeHeader->addr3, &all_zeros, MAC_ADDR_SIZE)) ||
1063 (0 == memcmp (&taIeeeHeader->addr1, &all_zeros, MAC_ADDR_SIZE)))
1064 return 0; /* some drivers set no Macs, then assume it is all for us! */
1065
1066 if (0 != memcmp (&taIeeeHeader->addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE))
1067 return 1; /* not a GNUnet ad-hoc package */
1068 if ((0 == memcmp (&taIeeeHeader->addr1, &dev->pl_mac, MAC_ADDR_SIZE)) ||
1069 (0 == memcmp (&taIeeeHeader->addr1, &bc_all_mac, MAC_ADDR_SIZE)))
1070 return 0; /* for us, or broadcast */
1071 return 1; /* not for us */
1072}
1073
1074
1075/**
1076 * Process data from the stdin. Takes the message, forces the sender MAC to be correct
1077 * and puts it into our buffer for transmission to the receiver.
1078 *
1079 * @param cls pointer to the device struct ('struct HardwareInfos*')
1080 * @param hdr pointer to the start of the packet
1081 *
1082 **** same as the one from gnunet-helper-transport-wlan.c ****
1083 */
1084static void
1085stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr)
1086{
1087 struct HardwareInfos *dev = cls;
1088 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header;
1089 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *blueheader;
1090 size_t sendsize;
1091
1092 sendsize = ntohs (hdr->size);
1093 if ((sendsize <
1094 sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)) ||
1095 (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)))
1096 {
1097 fprintf (stderr, "Received malformed message\n");
1098 exit (1);
1099 }
1100 sendsize -= (sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)
1101 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
1102 if (MAXLINE < sendsize)
1103 {
1104 fprintf (stderr, "Packet too big for buffer\n");
1105 exit (1);
1106 }
1107 header = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
1108 GNUNET_memcpy (&write_pout.buf, &header->frame, sendsize);
1109 blueheader = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf;
1110
1111 /* payload contains MAC address, but we don't trust it, so we'll
1112 * overwrite it with OUR MAC address to prevent mischief */
1113 mac_set (blueheader, dev);
1114 GNUNET_memcpy (&blueheader->addr1, &header->frame.addr1,
1115 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress));
1116 write_pout.size = sendsize;
1117}
1118
1119
1120#ifdef __linux__
1121/**
1122 * Broadcast a HELLO message for peer discovery
1123 *
1124 * @param dev pointer to the device struct
1125 * @param dev pointer to the socket which was added to the set
1126 * @return 0 on success
1127 */
1128static int
1129send_broadcast (struct HardwareInfos *dev, int *sendsocket)
1130{
1131 int new_device = 0;
1132 int loops = 0;
1133
1134search_for_devices:
1135 if (((neighbours.size == neighbours.pos) && (new_device == 1)) ||
1136 (neighbours.size == 0) )
1137 {
1138inquiry_devices: // skip the conditions and force a inquiry for new devices
1139 {
1140 /**
1141 * It means that I sent HELLO messages to all the devices from the list and I should search
1142 * for new ones or that this is the first time when I do a search.
1143 */
1144 inquiry_info *devices = NULL;
1145 int i, responses, max_responses = MAX_PORTS;
1146
1147 /* sanity checks */
1148 if (neighbours.size >= MAX_PORTS)
1149 {
1150 fprintf (stderr,
1151 "%.*s reached the top limit for the discovarable devices\n",
1152 IFNAMSIZ,
1153 dev->iface);
1154 return 2;
1155 }
1156
1157 /* Get the device id */
1158 if (neighbours.dev_id == -1)
1159 {
1160 char addr[19] = { 0 }; // the device MAC address
1161
1162 ba2str ((bdaddr_t *) &dev->pl_mac, addr);
1163 neighbours.dev_id = hci_devid (addr);
1164 if (neighbours.dev_id < 0)
1165 {
1166 fprintf (stderr,
1167 "Failed to get the device id for interface %.*s : %s\n",
1168 IFNAMSIZ,
1169 dev->iface, strerror (errno));
1170 return 1;
1171 }
1172 }
1173
1174 devices = malloc (max_responses * sizeof(inquiry_info));
1175 if (devices == NULL)
1176 {
1177 fprintf (stderr,
1178 "Failed to allocate memory for inquiry info list on interface %.*s\n",
1179 IFNAMSIZ,
1180 dev->iface);
1181 return 1;
1182 }
1183
1184 responses = hci_inquiry (neighbours.dev_id, 8, max_responses, NULL,
1185 &devices, IREQ_CACHE_FLUSH);
1186 if (responses < 0)
1187 {
1188 fprintf (stderr, "Failed to inquiry on interface %.*s\n", IFNAMSIZ,
1189 dev->iface);
1190 return 1;
1191 }
1192
1193 fprintf (stderr, "LOG : Found %d devices\n", responses); // FIXME delete it after debugging stage
1194
1195 if (responses == 0)
1196 {
1197 fprintf (stderr, "LOG : No devices discoverable\n");
1198 return 1;
1199 }
1200
1201 for (i = 0; i < responses; i++)
1202 {
1203 int j;
1204 int found = 0;
1205
1206 /* sanity check */
1207 if (i >= MAX_PORTS)
1208 {
1209 fprintf (stderr,
1210 "%.*s reached the top limit for the discoverable devices (after inquiry)\n",
1211 IFNAMSIZ,
1212 dev->iface);
1213 return 2;
1214 }
1215
1216 /* Search if the address already exists on the list */
1217 for (j = 0; j < neighbours.size; j++)
1218 {
1219 if (memcmp (&(devices + i)->bdaddr, &(neighbours.devices[j]),
1220 sizeof(bdaddr_t)) == 0)
1221 {
1222 found = 1;
1223 fprintf (stderr, "LOG : the device already exists on the list\n"); // FIXME debugging message
1224 break;
1225 }
1226 }
1227
1228 if (found == 0)
1229 {
1230 char addr[19] = { 0 };
1231
1232 ba2str (&(devices + i)->bdaddr, addr);
1233 fprintf (stderr, "LOG : %s was added to the list\n", addr); // FIXME debugging message
1234 GNUNET_memcpy (&(neighbours.devices[neighbours.size++]), &(devices
1235 + i)->
1236 bdaddr, sizeof(bdaddr_t));
1237 }
1238 }
1239
1240 free (devices);
1241 }
1242 }
1243
1244 int connection_successful = 0;
1245 struct sockaddr_rc addr_rc = { 0 };
1246 int errno_copy = 0;
1247 addr_rc.rc_family = AF_BLUETOOTH;
1248
1249 /* Try to connect to a new device from the list */
1250 while (neighbours.pos < neighbours.size)
1251 {
1252 /* Check if we are already connected to this device */
1253 if (neighbours.fds[neighbours.pos] == -1)
1254 {
1255 memset (&addr_rc.rc_bdaddr, 0, sizeof(addr_rc.rc_bdaddr));
1256 GNUNET_memcpy (&addr_rc.rc_bdaddr, &(neighbours.devices[neighbours.pos]),
1257 sizeof(addr_rc.rc_bdaddr));
1258
1259 addr_rc.rc_channel = get_channel (dev, addr_rc.rc_bdaddr);
1260
1261 *sendsocket = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
1262 if ((-1 < *sendsocket) &&
1263 (0 == connect (*sendsocket,
1264 (struct sockaddr *) &addr_rc,
1265 sizeof(addr_rc))))
1266 {
1267 neighbours.fds[neighbours.pos++] = *sendsocket;
1268 connection_successful = 1;
1269 char addr[19] = { 0 };
1270 ba2str (&(neighbours.devices[neighbours.pos - 1]), addr);
1271 fprintf (stderr, "LOG : Connected to %s\n", addr);
1272 break;
1273 }
1274 else
1275 {
1276 char addr[19] = { 0 };
1277 errno_copy = errno; // Save a copy for later
1278
1279 if (-1 != *sendsocket)
1280 {
1281 (void) close (*sendsocket);
1282 *sendsocket = -1;
1283 }
1284 ba2str (&(neighbours.devices[neighbours.pos]), addr);
1285 fprintf (stderr,
1286 "LOG : Couldn't connect on device %s, error : %s\n",
1287 addr,
1288 strerror (errno));
1289 if (errno != ECONNREFUSED) // FIXME be sure that this works
1290 {
1291 fprintf (stderr, "LOG : Removes %d device from the list\n",
1292 neighbours.pos);
1293 /* Remove the device from the list */
1294 GNUNET_memcpy (&neighbours.devices[neighbours.pos],
1295 &neighbours.devices[neighbours.size - 1],
1296 sizeof(bdaddr_t));
1297 memset (&neighbours.devices[neighbours.size - 1], 0,
1298 sizeof(bdaddr_t));
1299 neighbours.fds[neighbours.pos] = neighbours.fds[neighbours.size - 1];
1300 neighbours.fds[neighbours.size - 1] = -1;
1301 neighbours.size -= 1;
1302 }
1303
1304 neighbours.pos += 1;
1305
1306 if (neighbours.pos >= neighbours.size)
1307 neighbours.pos = 0;
1308
1309 loops += 1;
1310
1311 if (loops == MAX_LOOPS) // don't get stuck trying to connect to one device
1312 return 1;
1313 }
1314 }
1315 else
1316 {
1317 fprintf (stderr, "LOG : Search for a new device\n"); // FIXME debugging message
1318 neighbours.pos += 1;
1319 }
1320 }
1321
1322 /* Cycle on the list */
1323 if (neighbours.pos == neighbours.size)
1324 {
1325 neighbours.pos = 0;
1326 searching_devices_count += 1;
1327
1328 if (searching_devices_count == MAX_LOOPS)
1329 {
1330 fprintf (stderr, "LOG : Force to inquiry for new devices\n");
1331 searching_devices_count = 0;
1332 goto inquiry_devices;
1333 }
1334 }
1335 /* If a new device wasn't found, search an old one */
1336 if (connection_successful == 0)
1337 {
1338 int loop_check = neighbours.pos;
1339 while (neighbours.fds[neighbours.pos] == -1)
1340 {
1341 if (neighbours.pos == neighbours.size)
1342 neighbours.pos = 0;
1343
1344 if (neighbours.pos == loop_check)
1345 {
1346 if (errno_copy == ECONNREFUSED)
1347 {
1348 fprintf (stderr, "LOG : No device found. Go back and search again\n"); // FIXME debugging message
1349 new_device = 1;
1350 loops += 1;
1351 goto search_for_devices;
1352 }
1353 else
1354 {
1355 return 1; // Skip the broadcast message
1356 }
1357 }
1358
1359 neighbours.pos += 1;
1360 }
1361
1362 *sendsocket = neighbours.fds[neighbours.pos++];
1363 }
1364
1365 return 0;
1366}
1367
1368
1369#endif
1370
1371/**
1372 * Main function of the helper. This code accesses a bluetooth interface
1373 * forwards traffic in both directions between the bluetooth interface and
1374 * stdin/stdout of this process. Error messages are written to stderr.
1375 *
1376 * @param argc number of arguments, must be 2
1377 * @param argv arguments only argument is the name of the interface (e.g. 'hci0')
1378 * @return 0 on success (never happens, as we don't return unless aborted), 1 on error
1379 *
1380 **** similar to gnunet-helper-transport-wlan.c ****
1381 */
1382int
1383main (int argc, char *argv[])
1384{
1385#ifdef __linux__
1386 struct HardwareInfos dev;
1387 char readbuf[MAXLINE];
1388 int maxfd;
1389 fd_set rfds;
1390 fd_set wfds;
1391 int stdin_open;
1392 struct MessageStreamTokenizer *stdin_mst;
1393 int raw_eno, i;
1394 int crt_rfds = 0, rfds_list[MAX_PORTS];
1395 int broadcast, sendsocket;
1396
1397 /* Assert privs so we can modify the firewall rules! */
1398 {
1399#ifdef HAVE_SETRESUID
1400 uid_t uid = getuid ();
1401
1402 if (0 != setresuid (uid, 0, 0))
1403 {
1404 fprintf (stderr,
1405 "Failed to setresuid to root: %s\n",
1406 strerror (errno));
1407 return 254;
1408 }
1409#else
1410 if (0 != seteuid (0))
1411 {
1412 fprintf (stderr,
1413 "Failed to seteuid back to root: %s\n", strerror (errno));
1414 return 254;
1415 }
1416#endif
1417 }
1418
1419 /* Make use of SGID capabilities on POSIX */
1420 memset (&dev, 0, sizeof(dev));
1421 dev.fd_rfcomm = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
1422 raw_eno = errno; /* remember for later */
1423
1424 /* Now that we've dropped root rights, we can do error checking */
1425 if (2 != argc)
1426 {
1427 fprintf (stderr,
1428 "You must specify the name of the interface as the first \
1429 and only argument to this program.\n");
1430 if (-1 != dev.fd_rfcomm)
1431 (void) close (dev.fd_rfcomm);
1432 return 1;
1433 }
1434
1435 if (-1 == dev.fd_rfcomm)
1436 {
1437 fprintf (stderr, "Failed to create a RFCOMM socket: %s\n", strerror (
1438 raw_eno));
1439 return 1;
1440 }
1441 if (dev.fd_rfcomm >= FD_SETSIZE)
1442 {
1443 fprintf (stderr, "File descriptor too large for select (%d > %d)\n",
1444 dev.fd_rfcomm, FD_SETSIZE);
1445 (void) close (dev.fd_rfcomm);
1446 return 1;
1447 }
1448 if (0 != test_bluetooth_interface (argv[1]))
1449 {
1450 (void) close (dev.fd_rfcomm);
1451 return 1;
1452 }
1453 strncpy (dev.iface, argv[1], IFNAMSIZ);
1454 if (0 != open_device (&dev))
1455 {
1456 (void) close (dev.fd_rfcomm);
1457 return 1;
1458 }
1459
1460 /* Drop privs */
1461 {
1462 uid_t uid = getuid ();
1463 #ifdef HAVE_SETRESUID
1464 if (0 != setresuid (uid, uid, uid))
1465 {
1466 fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
1467 if (-1 != dev.fd_rfcomm)
1468 (void) close (dev.fd_rfcomm);
1469 return 1;
1470 }
1471 #else
1472 if (0 != (setuid (uid) | seteuid (uid)))
1473 {
1474 fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
1475 if (-1 != dev.fd_rfcomm)
1476 (void) close (dev.fd_rfcomm);
1477 return 1;
1478 }
1479 #endif
1480 }
1481
1482 /* Send MAC address of the bluetooth interface to STDOUT first */
1483 {
1484 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
1485
1486 macmsg.hdr.size = htons (sizeof(macmsg));
1487 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
1488 GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
1489 GNUNET_TRANSPORT_WLAN_MacAddress));
1490 GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
1491 write_std.size = sizeof(macmsg);
1492 }
1493
1494
1495 stdin_mst = mst_create (&stdin_send_hw, &dev);
1496 stdin_open = 1;
1497
1498 /**
1499 * TODO : I should make the time out of a mac endpoint smaller and check if the rate
1500 * from get_wlan_header (plugin_transport_bluetooth.c) is correct.
1501 */
1502 while (1)
1503 {
1504 maxfd = -1;
1505 broadcast = 0;
1506 sendsocket = -1;
1507
1508 FD_ZERO (&rfds);
1509 if ((0 == write_pout.size) && (1 == stdin_open))
1510 {
1511 FD_SET (STDIN_FILENO, &rfds);
1512 maxfd = MAX (maxfd, STDIN_FILENO);
1513 }
1514 if (0 == write_std.size)
1515 {
1516 FD_SET (dev.fd_rfcomm, &rfds);
1517 maxfd = MAX (maxfd, dev.fd_rfcomm);
1518 }
1519
1520 for (i = 0; i < crt_rfds; i++) // it can receive messages from multiple devices
1521 {
1522 FD_SET (rfds_list[i], &rfds);
1523 maxfd = MAX (maxfd, rfds_list[i]);
1524 }
1525 FD_ZERO (&wfds);
1526 if (0 < write_std.size)
1527 {
1528 FD_SET (STDOUT_FILENO, &wfds);
1529 maxfd = MAX (maxfd, STDOUT_FILENO);
1530 }
1531 if (0 < write_pout.size) // it can send messages only to one device per loop
1532 {
1533 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *frame;
1534 /* Get the destination address */
1535 frame = (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) write_pout.buf;
1536
1537 if (memcmp (&frame->addr1, &dev.pl_mac,
1538 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
1539 {
1540 broadcast = 1;
1541 memset (&write_pout, 0, sizeof(write_pout)); // clear the buffer
1542 }
1543 else if (memcmp (&frame->addr1, &broadcast_address,
1544 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
1545 {
1546 fprintf (stderr, "LOG : %s has a broadcast message (pos %d, size %d)\n",
1547 dev.iface, neighbours.pos, neighbours.size); // FIXME: debugging message
1548
1549 if (send_broadcast (&dev, &sendsocket) != 0) // if the searching wasn't successful don't get stuck on the select stage
1550 {
1551 broadcast = 1;
1552 memset (&write_pout, 0, sizeof(write_pout)); // remove the message
1553 fprintf (stderr,
1554 "LOG : Skipping the broadcast message (pos %d, size %d)\n",
1555 neighbours.pos, neighbours.size);
1556 }
1557 else
1558 {
1559 FD_SET (sendsocket, &wfds);
1560 maxfd = MAX (maxfd, sendsocket);
1561 }
1562 }
1563 else
1564 {
1565 int found = 0;
1566 int pos = 0;
1567 /* Search if the address already exists on the list */
1568 for (i = 0; i < neighbours.size; i++)
1569 {
1570 if (memcmp (&frame->addr1, &(neighbours.devices[i]),
1571 sizeof(bdaddr_t)) == 0)
1572 {
1573 pos = i;
1574 if (neighbours.fds[i] != -1)
1575 {
1576 found = 1; // save the position where it was found
1577 FD_SET (neighbours.fds[i], &wfds);
1578 maxfd = MAX (maxfd, neighbours.fds[i]);
1579 sendsocket = neighbours.fds[i];
1580 fprintf (stderr, "LOG: the address was found in the list\n");
1581 break;
1582 }
1583 }
1584 }
1585 if (found == 0)
1586 {
1587 int status;
1588 struct sockaddr_rc addr = { 0 };
1589
1590 fprintf (stderr,
1591 "LOG : %s has a new message for %.2X:%.2X:%.2X:%.2X:%.2X:%.2X which isn't on the broadcast list\n",
1592 dev.iface,
1593 frame->addr1.mac[5], frame->addr1.mac[4],
1594 frame->addr1.mac[3],
1595 frame->addr1.mac[2], frame->addr1.mac[1],
1596 frame->addr1.mac[0]); // FIXME: debugging message
1597
1598 sendsocket = socket (AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
1599
1600 if (sendsocket < 0)
1601 {
1602 fprintf (stderr,
1603 "Failed to create a RFCOMM socket (sending stage): %s\n",
1604 strerror (errno));
1605 return -1;
1606 }
1607
1608 GNUNET_memcpy (&addr.rc_bdaddr, &frame->addr1, sizeof(bdaddr_t));
1609 addr.rc_family = AF_BLUETOOTH;
1610 addr.rc_channel = get_channel (&dev, addr.rc_bdaddr);
1611
1612 int tries = 0;
1613connect_retry:
1614 status = connect (sendsocket, (struct sockaddr *) &addr,
1615 sizeof(addr));
1616 if ((0 != status) && (errno != EAGAIN) )
1617 {
1618 if ((errno == ECONNREFUSED) && (tries < 2) )
1619 {
1620 fprintf (stderr, "LOG : %.*s failed to connect. Trying again!\n",
1621 IFNAMSIZ, dev.iface);
1622 tries++;
1623 goto connect_retry;
1624 }
1625 else if (errno == EBADF)
1626 {
1627 fprintf (stderr, "LOG : %s failed to connect : %s. Skip it!\n",
1628 dev.iface, strerror (errno));
1629 memset (&write_pout, 0, sizeof(write_pout));
1630 broadcast = 1;
1631 }
1632 else
1633 {
1634 fprintf (stderr,
1635 "LOG : %s failed to connect : %s. Try again later!\n",
1636 dev.iface,
1637 strerror (errno));
1638 memset (&write_pout, 0, sizeof(write_pout));
1639 broadcast = 1;
1640 }
1641 }
1642 else
1643 {
1644 FD_SET (sendsocket, &wfds);
1645 maxfd = MAX (maxfd, sendsocket);
1646 fprintf (stderr, "LOG : Connection successful\n");
1647 if (pos != 0) // save the socket
1648 {
1649 neighbours.fds[pos] = sendsocket;
1650 }
1651 else
1652 {
1653 /* Add the new device to the discovered devices list */
1654 if (neighbours.size < MAX_PORTS)
1655 {
1656 neighbours.fds[neighbours.size] = sendsocket;
1657 GNUNET_memcpy (&(neighbours.devices[neighbours.size++]),
1658 &addr.rc_bdaddr, sizeof(bdaddr_t));
1659 }
1660 else
1661 {
1662 fprintf (stderr,
1663 "The top limit for the discovarable devices' list was reached\n");
1664 }
1665 }
1666 }
1667 }
1668 }
1669 }
1670
1671 if (broadcast == 0)
1672 {
1673 /* Select a fd which is ready for action :) */
1674 {
1675 int retval = select (maxfd + 1, &rfds, &wfds, NULL, NULL);
1676 if ((-1 == retval) && (EINTR == errno))
1677 continue;
1678 if ((0 > retval) && (errno != EBADF) ) // we handle BADF errors later
1679 {
1680 fprintf (stderr, "select failed: %s\n", strerror (errno));
1681 break;
1682 }
1683 }
1684 if (FD_ISSET (STDOUT_FILENO, &wfds))
1685 {
1686 ssize_t ret =
1687 write (STDOUT_FILENO, write_std.buf + write_std.pos,
1688 write_std.size - write_std.pos);
1689 if (0 > ret)
1690 {
1691 fprintf (stderr, "Failed to write to STDOUT: %s\n", strerror (errno));
1692 break;
1693 }
1694 write_std.pos += ret;
1695 if (write_std.pos == write_std.size)
1696 {
1697 write_std.pos = 0;
1698 write_std.size = 0;
1699 }
1700 fprintf (stderr, "LOG : %s sends a message to STDOUT\n", dev.iface); // FIXME: debugging message
1701 }
1702 if (-1 != sendsocket)
1703 {
1704 if (FD_ISSET (sendsocket, &wfds))
1705 {
1706 ssize_t ret = write (sendsocket,
1707 write_pout.buf + write_std.pos,
1708 write_pout.size - write_pout.pos);
1709 if (0 > ret) // FIXME should I first check the error type?
1710 {
1711 fprintf (stderr,
1712 "Failed to write to bluetooth device: %s. Closing the socket!\n",
1713 strerror (errno));
1714 for (i = 0; i < neighbours.size; i++)
1715 {
1716 if (neighbours.fds[i] == sendsocket)
1717 {
1718 (void) close (sendsocket);
1719 neighbours.fds[i] = -1;
1720 break;
1721 }
1722 }
1723 /* Remove the message */
1724 memset (&write_pout.buf + write_std.pos, 0, (write_pout.size
1725 - write_pout.pos));
1726 write_pout.pos = 0;
1727 write_pout.size = 0;
1728 }
1729 else
1730 {
1731 write_pout.pos += ret;
1732 if ((write_pout.pos != write_pout.size) && (0 != ret))
1733 {
1734 /* We should not get partial sends with packet-oriented devices... */
1735 fprintf (stderr, "Write error, partial send: %u/%u\n",
1736 (unsigned int) write_pout.pos,
1737 (unsigned int) write_pout.size);
1738 break;
1739 }
1740
1741 if (write_pout.pos == write_pout.size)
1742 {
1743 write_pout.pos = 0;
1744 write_pout.size = 0;
1745 }
1746 fprintf (stderr, "LOG : %s sends a message to a DEVICE\n",
1747 dev.iface); // FIXME: debugging message
1748 }
1749 }
1750 }
1751 for (i = 0; i <= maxfd; i++)
1752 {
1753 if (FD_ISSET (i, &rfds))
1754 {
1755 if (i == STDIN_FILENO)
1756 {
1757 ssize_t ret =
1758 read (i, readbuf, sizeof(readbuf));
1759 if (0 > ret)
1760 {
1761 fprintf (stderr,
1762 "Read error from STDIN: %s\n",
1763 strerror (errno));
1764 break;
1765 }
1766 if (0 == ret)
1767 {
1768 /* stop reading... */
1769 stdin_open = 0;
1770 }
1771 else
1772 {
1773 mst_receive (stdin_mst, readbuf, ret);
1774 fprintf (stderr, "LOG : %s receives a message from STDIN\n",
1775 dev.iface); // FIXME: debugging message
1776 }
1777 }
1778 else if (i == dev.fd_rfcomm)
1779 {
1780 int readsocket;
1781 struct sockaddr_rc addr = { 0 };
1782 unsigned int opt = sizeof(addr);
1783
1784 readsocket = accept (dev.fd_rfcomm, (struct sockaddr *) &addr,
1785 &opt);
1786 fprintf (stderr, "LOG : %s accepts a message\n", dev.iface); // FIXME: debugging message
1787 if (readsocket == -1)
1788 {
1789 fprintf (stderr,
1790 "Failed to accept a connection on interface: %.*s\n",
1791 IFNAMSIZ,
1792 strerror (errno));
1793 break;
1794 }
1795 else
1796 {
1797 FD_SET (readsocket, &rfds);
1798 maxfd = MAX (maxfd, readsocket);
1799
1800 if (crt_rfds < MAX_PORTS)
1801 rfds_list[crt_rfds++] = readsocket;
1802 else
1803 {
1804 fprintf (stderr,
1805 "The limit for the read file descriptors list was \
1806 reached\n");
1807 break;
1808 }
1809 }
1810 }
1811 else
1812 {
1813 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
1814 ssize_t ret;
1815 fprintf (stderr, "LOG : %s reads something from the socket\n",
1816 dev.iface); // FIXME : debugging message
1817 rrm = (struct
1818 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
1819 ret =
1820 read_from_the_socket ((void *) &i, (unsigned char *) &rrm->frame,
1821 sizeof(write_std.buf)
1822 - sizeof(struct
1823 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
1824 + sizeof(struct
1825 GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
1826 rrm);
1827 if (0 >= ret)
1828 {
1829 int j;
1830 FD_CLR (i, &rfds);
1831 close (i);
1832 /* Remove the socket from the list */
1833 for (j = 0; j < crt_rfds; j++)
1834 {
1835 if (rfds_list[j] == i)
1836 {
1837 rfds_list[j] ^= rfds_list[crt_rfds - 1];
1838 rfds_list[crt_rfds - 1] ^= rfds_list[j];
1839 rfds_list[j] ^= rfds_list[crt_rfds - 1];
1840 crt_rfds -= 1;
1841 break;
1842 }
1843 }
1844
1845 fprintf (stderr, "Read error from raw socket: %s\n", strerror (
1846 errno));
1847 break;
1848 }
1849 if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
1850 {
1851 write_std.size = ret
1852 + sizeof(struct
1853 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
1854 - sizeof(struct
1855 GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
1856 rrm->header.size = htons (write_std.size);
1857 rrm->header.type = htons (
1858 GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
1859 }
1860 }
1861 }
1862 }
1863 }
1864 }
1865 /* Error handling, try to clean up a bit at least */
1866 mst_destroy (stdin_mst);
1867 stdin_mst = NULL;
1868 sdp_close (dev.session);
1869 (void) close (dev.fd_rfcomm);
1870 if (-1 != sendsocket)
1871 (void) close (sendsocket);
1872
1873 for (i = 0; i < crt_rfds; i++)
1874 (void) close (rfds_list[i]);
1875
1876 for (i = 0; i < neighbours.size; i++)
1877 (void) close (neighbours.fds[i]);
1878 #else
1879 struct HardwareInfos dev;
1880 struct GNUNET_NETWORK_Handle *sendsocket;
1881 struct GNUNET_NETWORK_FDSet *rfds;
1882 struct GNUNET_NETWORK_FDSet *wfds;
1883 struct GNUNET_NETWORK_Handle *rfds_list[MAX_PORTS];
1884 char readbuf[MAXLINE] = { 0 };
1885 SOCKADDR_BTH acc_addr = { 0 };
1886 int addr_len = sizeof(SOCKADDR_BTH);
1887 int broadcast, i, stdin_open, crt_rfds = 0;
1888 HANDLE stdin_handle = GetStdHandle (STD_INPUT_HANDLE);
1889 HANDLE stdout_handle = GetStdHandle (STD_OUTPUT_HANDLE);
1890 struct MessageStreamTokenizer *stdin_mst;
1891
1892 /* check the handles */
1893 if (stdin_handle == INVALID_HANDLE_VALUE)
1894 {
1895 fprintf (stderr, "Failed to get the stdin handle\n");
1896 ExitProcess (2);
1897 }
1898
1899 if (stdout_handle == INVALID_HANDLE_VALUE)
1900 {
1901 fprintf (stderr, "Failed to get the stdout handle\n");
1902 ExitProcess (2);
1903 }
1904
1905 /* initialize windows sockets */
1906 initialize_windows_sockets ();
1907
1908 // /* test bluetooth socket family support */ --> it return false because the GNUNET_NETWORK_test_pf should also receive the type of socket (BTHPROTO_RFCOMM)
1909 // if (GNUNET_NETWORK_test_pf (AF_BTH) != GNUNET_OK)
1910 // {
1911 // fprintf (stderr, "AF_BTH family is not supported\n");
1912 // ExitProcess (2);
1913 // }
1914
1915 /* create the socket */
1916 dev.handle = GNUNET_NETWORK_socket_create (AF_BTH, SOCK_STREAM,
1917 BTHPROTO_RFCOMM);
1918 if (dev.handle == NULL)
1919 {
1920 fprintf (stderr, "Failed to create RFCOMM socket: ");
1921 print_last_error ();
1922 ExitProcess (2);
1923 }
1924
1925
1926 if (open_device (&dev) == -1)
1927 {
1928 fprintf (stderr, "Failed to open the device\n");
1929 print_last_error ();
1930 if (GNUNET_NETWORK_socket_close (dev.handle) != GNUNET_OK)
1931 {
1932 fprintf (stderr, "Failed to close the socket!\n");
1933 print_last_error ();
1934 }
1935 ExitProcess (2);
1936 }
1937
1938 if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (dev.handle, 1))
1939 {
1940 fprintf (stderr, "Failed to change the socket mode\n");
1941 ExitProcess (2);
1942 }
1943
1944 memset (&write_std, 0, sizeof(write_std));
1945 memset (&write_pout, 0, sizeof(write_pout));
1946 stdin_open = 1;
1947
1948 rfds = GNUNET_NETWORK_fdset_create ();
1949 wfds = GNUNET_NETWORK_fdset_create ();
1950
1951 /* Send MAC address of the bluetooth interface to STDOUT first */
1952 {
1953 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
1954
1955 macmsg.hdr.size = htons (sizeof(macmsg));
1956 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
1957 GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
1958 GNUNET_TRANSPORT_WLAN_MacAddress_Copy));
1959 GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
1960 write_std.size = sizeof(macmsg);
1961 }
1962
1963
1964 stdin_mst = mst_create (&stdin_send_hw, &dev);
1965 stdin_open = 1;
1966
1967 int pos = 0;
1968 int stdin_pos = -1;
1969 int stdout_pos = -1;
1970 while (1)
1971 {
1972 broadcast = 0;
1973 pos = 0;
1974 stdin_pos = -1;
1975 stdout_pos = -1;
1976 sendsocket = NULL; // FIXME ???memleaks
1977
1978 GNUNET_NETWORK_fdset_zero (rfds);
1979 if ((0 == write_pout.size) && (1 == stdin_open))
1980 {
1981 stdin_pos = pos;
1982 pos += 1;
1983 GNUNET_NETWORK_fdset_handle_set (rfds, (struct
1984 GNUNET_DISK_FileHandle*) &
1985 stdin_handle);
1986 }
1987
1988 if (0 == write_std.size)
1989 {
1990 pos += 1;
1991 GNUNET_NETWORK_fdset_set (rfds, dev.handle);
1992 }
1993
1994 for (i = 0; i < crt_rfds; i++)
1995 {
1996 pos += 1;
1997 GNUNET_NETWORK_fdset_set (rfds, rfds_list[i]);
1998 }
1999
2000 GNUNET_NETWORK_fdset_zero (wfds);
2001 if (0 < write_std.size)
2002 {
2003 stdout_pos = pos;
2004 GNUNET_NETWORK_fdset_handle_set (wfds, (struct
2005 GNUNET_DISK_FileHandle*) &
2006 stdout_handle);
2007 // printf ("%s\n", write_std.buf);
2008 // memset (write_std.buf, 0, write_std.size);
2009 // write_std.size = 0;
2010 }
2011
2012 if (0 < write_pout.size)
2013 {
2014 if (strcmp (argv[1], "ff:ff:ff:ff:ff:ff") == 0)
2015 {
2016 fprintf (stderr, "LOG: BROADCAST! Skipping the message\n");
2017 // skip the message
2018 broadcast = 1;
2019 memset (write_pout.buf, 0, write_pout.size);
2020 write_pout.size = 0;
2021 }
2022 else
2023 {
2024 SOCKADDR_BTH addr;
2025 fprintf (stderr, "LOG : has a new message for %s\n", argv[1]);
2026 sendsocket = GNUNET_NETWORK_socket_create (AF_BTH, SOCK_STREAM,
2027 BTHPROTO_RFCOMM);
2028
2029 if (sendsocket == NULL)
2030 {
2031 fprintf (stderr, "Failed to create RFCOMM socket: \n");
2032 print_last_error ();
2033 ExitProcess (2);
2034 }
2035
2036 memset (&addr, 0, sizeof(addr));
2037 // addr.addressFamily = AF_BTH;
2038 if (SOCKET_ERROR ==
2039 WSAStringToAddress (argv[1], AF_BTH, NULL, (LPSOCKADDR) &addr,
2040 &addr_len))
2041 {
2042 fprintf (stderr, "Failed to translate the address: ");
2043 print_last_error ();
2044 ExitProcess (2);
2045 }
2046 addr.port = get_channel (argv[1]);
2047 if (addr.port == -1)
2048 {
2049 fprintf (stderr,
2050 "Couldn't find the sdp service for the address: %s\n",
2051 argv[1]);
2052 memset (write_pout.buf, 0, write_pout.size);
2053 write_pout.size = 0;
2054 broadcast = 1; // skipping the select part
2055 }
2056 else
2057 {
2058 if (GNUNET_OK != GNUNET_NETWORK_socket_connect (sendsocket,
2059 (LPSOCKADDR) &addr,
2060 addr_len))
2061 {
2062 fprintf (stderr, "Failed to connect: ");
2063 print_last_error ();
2064 ExitProcess (2);
2065 }
2066
2067 if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (sendsocket, 1))
2068 {
2069 fprintf (stderr, "Failed to change the socket mode\n");
2070 ExitProcess (2);
2071 }
2072
2073 GNUNET_NETWORK_fdset_set (wfds, sendsocket);
2074 }
2075 }
2076 }
2077
2078 if (broadcast == 0)
2079 {
2080 int retval = GNUNET_NETWORK_socket_select (rfds, wfds, NULL,
2081 GNUNET_TIME_relative_get_forever_ ());
2082 if (retval < 0)
2083 {
2084 fprintf (stderr, "Select error\n");
2085 ExitProcess (2);
2086 }
2087 // if (GNUNET_NETWORK_fdset_isset (wfds, (struct GNUNET_NETWORK_Handle*)&stdout_handle))
2088 if (retval == stdout_pos)
2089 {
2090 fprintf (stderr, "LOG : sends a message to STDOUT\n"); // FIXME: debugging message
2091 // ssize_t ret;
2092 // ret = GNUNET_NETWORK_socket_send ((struct GNUNET_NETWORK_Handle *)&stdout_handle, write_std.buf + write_std.pos, write_std.size - write_std.pos);
2093 // ret = write (STDOUT_FILENO, write_std.buf + write_std.pos, write_std.size - write_std.pos);
2094 DWORD ret;
2095 if (FALSE == WriteFile (stdout_handle, write_std.buf + write_std.pos,
2096 write_std.size - write_std.pos, &ret, NULL))
2097 {
2098 fprintf (stderr, "Failed to write to STDOUT: ");
2099 print_last_error ();
2100 break;
2101 }
2102
2103 if (ret <= 0)
2104 {
2105 fprintf (stderr, "Failed to write to STDOUT\n");
2106 ExitProcess (2);
2107 }
2108
2109 write_std.pos += ret;
2110 if (write_std.pos == write_std.size)
2111 {
2112 write_std.pos = 0;
2113 write_std.size = 0;
2114 }
2115 }
2116 if (sendsocket != NULL)
2117 {
2118 if (GNUNET_NETWORK_fdset_isset (wfds, sendsocket))
2119 {
2120 ssize_t ret;
2121 ret = GNUNET_NETWORK_socket_send (sendsocket, write_pout.buf
2122 + write_pout.pos,
2123 write_pout.size - write_pout.pos);
2124
2125 if (GNUNET_SYSERR == ret)
2126 {
2127 fprintf (stderr,
2128 "Failed to send to the socket. Closing the socket. Error: \n");
2129 print_last_error ();
2130 if (GNUNET_NETWORK_socket_close (sendsocket) != GNUNET_OK)
2131 {
2132 fprintf (stderr, "Failed to close the sendsocket!\n");
2133 print_last_error ();
2134 }
2135 ExitProcess (2);
2136 }
2137 else
2138 {
2139 write_pout.pos += ret;
2140 if ((write_pout.pos != write_pout.size) && (0 != ret))
2141 {
2142 /* we should not get partial sends with packet-oriented devices... */
2143 fprintf (stderr, "Write error, partial send: %u/%u\n",
2144 (unsigned int) write_pout.pos,
2145 (unsigned int) write_pout.size);
2146 break;
2147 }
2148
2149 if (write_pout.pos == write_pout.size)
2150 {
2151 write_pout.pos = 0;
2152 write_pout.size = 0;
2153 }
2154 fprintf (stderr, "LOG : sends a message to a DEVICE\n"); // FIXME: debugging message
2155 }
2156 }
2157 }
2158
2159 // if (GNUNET_NETWORK_fdset_isset (rfds, (struct GNUNET_NETWORK_Handle*)&stdin_handle))
2160 if (retval == stdin_pos)
2161 {
2162 // ssize_t ret;
2163 // ret = GNUNET_NETWORK_socket_recv ((struct GNUNET_NETWORK_Handle *)&stdin_handle, readbuf, sizeof (write_pout.buf));
2164 // ret = read (STDIN_FILENO, readbuf, sizeof (readbuf));
2165 DWORD ret;
2166 if (FALSE == ReadFile (stdin_handle, readbuf, sizeof(readbuf), &ret,
2167 NULL)) /* do nothing asynchronous */
2168 {
2169 fprintf (stderr, "Read error from STDIN: ");
2170 print_last_error ();
2171 break;
2172 }
2173 if (0 == ret)
2174 {
2175 /* stop reading... */
2176 stdin_open = 0;
2177 }
2178 else
2179 {
2180 mst_receive (stdin_mst, readbuf, ret);
2181 fprintf (stderr, "LOG : receives a message from STDIN\n"); // FIXME: debugging message
2182 }
2183 }
2184 else if (GNUNET_NETWORK_fdset_isset (rfds, dev.handle))
2185 {
2186 fprintf (stderr, "LOG: accepting connection\n");
2187 struct GNUNET_NETWORK_Handle *readsocket;
2188 readsocket = GNUNET_NETWORK_socket_accept (dev.handle,
2189 (LPSOCKADDR) &acc_addr,
2190 &addr_len);
2191 if (readsocket == NULL)
2192 {
2193 fprintf (stderr, "Accept error %d: ", GetLastError ());
2194 print_last_error ();
2195 ExitProcess (2);
2196 }
2197 else
2198 {
2199 if (GNUNET_OK != GNUNET_NETWORK_socket_set_blocking (readsocket, 1))
2200 {
2201 fprintf (stderr, "Failed to change the socket mode\n");
2202 ExitProcess (2);
2203 }
2204 GNUNET_NETWORK_fdset_set (rfds, readsocket);
2205
2206 if (crt_rfds < MAX_PORTS)
2207 rfds_list[crt_rfds++] = readsocket;
2208 else
2209 {
2210 fprintf (stderr,
2211 "The limit for the read file descriptors list was reached\n");
2212 break;
2213 }
2214 }
2215 }
2216 else
2217 for (i = 0; i < crt_rfds; i++)
2218 {
2219 if (GNUNET_NETWORK_fdset_isset (rfds, rfds_list[i]))
2220 {
2221 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
2222 ssize_t ret;
2223 fprintf (stderr, "LOG: reading something from the socket\n"); // FIXME : debugging message
2224 rrm = (struct
2225 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
2226 ret = read_from_the_socket (rfds_list[i], (unsigned
2227 char *) &rrm->frame,
2228 sizeof(write_std.buf)
2229 - sizeof(struct
2230 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2231 + sizeof(struct
2232 GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
2233 rrm);
2234 if (0 >= ret)
2235 {
2236 // TODO remove the socket from the list
2237 if (GNUNET_NETWORK_socket_close (rfds_list[i]) != GNUNET_OK)
2238 {
2239 fprintf (stderr, "Failed to close the sendsocket!\n");
2240 print_last_error ();
2241 }
2242
2243 fprintf (stderr, "Read error from raw socket: ");
2244 print_last_error ();
2245 break;
2246 }
2247 if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
2248 {
2249 write_std.size = ret
2250 + sizeof(struct
2251 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2252 - sizeof(struct
2253 GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
2254 rrm->header.size = htons (write_std.size);
2255 rrm->header.type = htons (
2256 GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
2257 }
2258 break;
2259 }
2260 }
2261 }
2262 }
2263
2264 mst_destroy (stdin_mst);
2265 stdin_mst = NULL;
2266
2267 if (GNUNET_NETWORK_socket_close (dev.handle) != GNUNET_OK)
2268 {
2269 fprintf (stderr, "Failed to close the socket!\n");
2270 print_last_error ();
2271 }
2272
2273 for (i = 0; i < crt_rfds; i++)
2274 {
2275 if (GNUNET_NETWORK_socket_close (rfds_list[i]) != GNUNET_OK)
2276 {
2277 fprintf (stderr, "Failed to close the socket!\n");
2278 print_last_error ();
2279 }
2280 }
2281
2282 WSACleanup ();
2283 #endif
2284 return 1; /* we never exit 'normally' */
2285}
diff --git a/src/transport/gnunet-helper-transport-wlan-dummy.c b/src/transport/gnunet-helper-transport-wlan-dummy.c
deleted file mode 100644
index ab77f5c68..000000000
--- a/src/transport/gnunet-helper-transport-wlan-dummy.c
+++ /dev/null
@@ -1,520 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/gnunet-helper-transport-wlan-dummy.c
22 * @brief helper for the testcases for plugin_transport_wlan.c
23 * @author David Brodski
24 */
25#include "platform.h"
26#include "gnunet_protocols.h"
27#include "gnunet_util_lib.h"
28#include "plugin_transport_wlan.h"
29
30/**
31 * Name of the fifo to use for IPC with the other dummy process.
32 */
33#define FIFO_FILE1 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_in"
34
35/**
36 * Name of the fifo to use for IPC with the other dummy process.
37 */
38#define FIFO_FILE2 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_out"
39
40/**
41 * Maximum size of a message allowed in either direction
42 * (used for our receive and sent buffers).
43 */
44#define MAXLINE 4096
45
46
47/**
48 * IO buffer used for buffering data in transit.
49 */
50struct SendBuffer
51{
52 /**
53 * How many bytes that were stored in 'buf' did we already write to the
54 * destination? Always smaller than 'size'.
55 */
56 size_t pos;
57
58 /**
59 * How many bytes of data are stored in 'buf' for transmission right now?
60 * Data always starts at offset 0 and extends to 'size'.
61 */
62 size_t size;
63
64 /**
65 * Buffered data; twice the maximum allowed message size as we add some
66 * headers.
67 */
68 char buf[MAXLINE * 2];
69};
70
71
72/**
73 * Flag set to 1 if we are to terminate, otherwise 0.
74 */
75static int closeprog;
76
77
78/**
79 * We're being killed, clean up.
80 *
81 * @param sig killing signal
82 */
83static void
84sigfunc (int sig)
85{
86 closeprog = 1;
87 (void) unlink (FIFO_FILE1);
88 (void) unlink (FIFO_FILE2);
89}
90
91
92/**
93 * Create control message for plugin
94 *
95 * @param buffer pointer to buffer for the message
96 * @param mac pointer to the mac address
97 * @return number of bytes written
98 */
99static int
100send_mac_to_plugin (char *buffer, struct GNUNET_TRANSPORT_WLAN_MacAddress *mac)
101{
102 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
103
104 GNUNET_memcpy (&macmsg.mac,
105 (char *) mac,
106 sizeof(struct GNUNET_TRANSPORT_WLAN_MacAddress));
107 macmsg.hdr.size =
108 htons (sizeof(struct GNUNET_TRANSPORT_WLAN_HelperControlMessage));
109 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
110 GNUNET_memcpy (buffer,
111 &macmsg,
112 sizeof(struct GNUNET_TRANSPORT_WLAN_HelperControlMessage));
113 return sizeof(struct GNUNET_TRANSPORT_WLAN_HelperControlMessage);
114}
115
116
117/**
118 * We got a message from the FIFO, check it, convert the message
119 * type to the output forward and copy it to the buffer for stdout.
120 *
121 * @param cls the 'struct SendBuffer' to copy the converted message to
122 * @param hdr inbound message from the FIFO
123 * @return #GNUNET_OK on success,
124 * #GNUNET_NO to stop further processing (no error)
125 * #GNUNET_SYSERR to stop further processing with error
126 */
127static int
128stdin_send (void *cls, const struct GNUNET_MessageHeader *hdr)
129{
130 struct SendBuffer *write_pout = cls;
131 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *in;
132 size_t payload_size;
133 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage newheader;
134 uint16_t sendsize;
135
136 sendsize = ntohs (hdr->size);
137 in = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
138 if ((GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)) ||
139 (sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage) > sendsize))
140 {
141 fprintf (stderr, "%s", "Received malformed message\n");
142 exit (1);
143 }
144 payload_size =
145 sendsize - sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage);
146 if ((payload_size
147 + sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
148 + write_pout->size) > MAXLINE * 2)
149 {
150 fprintf (stderr, "%s", "Packet too big for buffer\n");
151 exit (1);
152 }
153 memset (&newheader, 0, sizeof(newheader));
154 newheader.header.size = htons (payload_size + sizeof(newheader));
155 newheader.header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
156 newheader.frame = in->frame;
157 GNUNET_memcpy (write_pout->buf + write_pout->size,
158 &newheader,
159 sizeof(newheader));
160 write_pout->size += sizeof(newheader);
161 GNUNET_memcpy (write_pout->buf + write_pout->size, &in[1], payload_size);
162 write_pout->size += payload_size;
163 return GNUNET_OK;
164}
165
166
167/**
168 * We read a full message from stdin. Copy it to our send buffer.
169 *
170 * @param cls the 'struct SendBuffer' to copy to
171 * @param hdr the message we received to copy to the buffer
172 * @return #GNUNET_OK on success,
173 * #GNUNET_NO to stop further processing (no error)
174 * #GNUNET_SYSERR to stop further processing with error
175 */
176static int
177file_in_send (void *cls, const struct GNUNET_MessageHeader *hdr)
178{
179 struct SendBuffer *write_std = cls;
180 uint16_t sendsize;
181
182 sendsize = ntohs (hdr->size);
183 if ((sendsize + write_std->size) > MAXLINE * 2)
184 {
185 fprintf (stderr, "%s", "Packet too big for buffer\n");
186 exit (1);
187 }
188 GNUNET_memcpy (write_std->buf + write_std->size, hdr, sendsize);
189 write_std->size += sendsize;
190 return GNUNET_OK;
191}
192
193
194/**
195 * Main function of a program that pretends to be a WLAN card.
196 *
197 * @param argc should be 2
198 * @param argv either '1' or '2', depending on which of the two cards this dummy is to emulate
199 * @return 1 on error, 0 if terminated normally via signal
200 */
201int
202main (int argc, char *argv[])
203{
204 struct stat st;
205 int erg;
206 FILE *fpin = NULL;
207 FILE *fpout = NULL;
208 int fdpin;
209 int fdpout;
210 char readbuf[MAXLINE];
211 int readsize;
212 struct SendBuffer write_std;
213 struct SendBuffer write_pout;
214 int ret;
215 int maxfd;
216 fd_set rfds;
217 fd_set wfds;
218 struct timeval tv;
219 int retval;
220 struct GNUNET_MessageStreamTokenizer *stdin_mst = NULL;
221 struct GNUNET_MessageStreamTokenizer *file_in_mst = NULL;
222 struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr;
223 int first;
224
225 if ((2 != argc) ||
226 ((0 != strcmp (argv[1], "1")) && (0 != strcmp (argv[1], "2"))))
227 {
228 fprintf (
229 stderr,
230 "%s",
231 "This program must be started with the operating mode (1 or 2) as the only argument.\n");
232 return 1;
233 }
234
235 /* make the fifos if needed */
236 umask (0);
237 if ((GNUNET_OK != GNUNET_DISK_directory_create_for_file (FIFO_FILE1)) ||
238 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (FIFO_FILE2)))
239 {
240 fprintf (stderr, "Failed to create directory for file `%s'\n", FIFO_FILE1);
241 return 1;
242 }
243 if (0 == strcmp (argv[1], "1"))
244 {
245 if (0 != stat (FIFO_FILE1, &st))
246 {
247 erg = mkfifo (FIFO_FILE1, 0666);
248 if ((0 != erg) && (EEXIST != errno))
249 fprintf (stderr,
250 "Error in mkfifo(%s): %s\n",
251 FIFO_FILE1,
252 strerror (errno));
253 }
254 }
255 else
256 {
257 if (0 != stat (FIFO_FILE2, &st))
258 {
259 GNUNET_break (0 == (erg = mkfifo (FIFO_FILE2, 0666)));
260 if ((0 != erg) && (EEXIST != errno))
261 fprintf (stderr,
262 "Error in mkfifo(%s): %s\n",
263 FIFO_FILE2,
264 strerror (errno));
265 }
266 }
267
268 if (0 == strcmp (argv[1], "1"))
269 {
270 first = 1;
271 fpin = fopen (FIFO_FILE1, "r");
272 if (NULL == fpin)
273 {
274 fprintf (stderr,
275 "fopen of read FIFO_FILE1 failed: %s\n",
276 strerror (errno));
277 goto end;
278 }
279 if (NULL == (fpout = fopen (FIFO_FILE2, "w")))
280 {
281 GNUNET_break (0 == mkfifo (FIFO_FILE2, 0666));
282 fpout = fopen (FIFO_FILE2, "w");
283 }
284 if (NULL == fpout)
285 {
286 fprintf (stderr,
287 "fopen of write FIFO_FILE2 failed: %s\n",
288 strerror (errno));
289 goto end;
290 }
291 }
292 else
293 {
294 first = 0;
295 if (NULL == (fpout = fopen (FIFO_FILE1, "w")))
296 {
297 GNUNET_break (0 == mkfifo (FIFO_FILE1, 0666));
298 fpout = fopen (FIFO_FILE1, "w");
299 }
300 if (NULL == fpout)
301 {
302 fprintf (stderr,
303 "fopen of write FIFO_FILE1 failed: %s\n",
304 strerror (errno));
305 goto end;
306 }
307 fpin = fopen (FIFO_FILE2, "r");
308 if (NULL == fpin)
309 {
310 fprintf (stderr,
311 "fopen of read FIFO_FILE2 failed: %s\n",
312 strerror (errno));
313 goto end;
314 }
315 }
316
317 fdpin = fileno (fpin);
318 GNUNET_assert (fpin >= 0);
319 if (fdpin >= FD_SETSIZE)
320 {
321 fprintf (stderr,
322 "File fdpin number too large (%d > %u)\n",
323 fdpin,
324 (unsigned int) FD_SETSIZE);
325 goto end;
326 }
327
328 fdpout = fileno (fpout);
329 GNUNET_assert (fdpout >= 0);
330
331 if (fdpout >= FD_SETSIZE)
332 {
333 fprintf (stderr,
334 "File fdpout number too large (%d > %u)\n",
335 fdpout,
336 (unsigned int) FD_SETSIZE);
337 goto end;
338 }
339
340 signal (SIGINT, &sigfunc);
341 signal (SIGTERM, &sigfunc);
342 signal (GNUNET_TERM_SIG, &sigfunc);
343
344 write_std.size = 0;
345 write_std.pos = 0;
346 write_pout.size = 0;
347 write_pout.pos = 0;
348 stdin_mst = GNUNET_MST_create (&stdin_send, &write_pout);
349 file_in_mst = GNUNET_MST_create (&file_in_send, &write_std);
350
351 /* Send 'random' mac address */
352 macaddr.mac[0] = 0x13;
353 macaddr.mac[1] = 0x22;
354 macaddr.mac[2] = 0x33;
355 macaddr.mac[3] = 0x44;
356 macaddr.mac[4] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 256);
357 macaddr.mac[5] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 256);
358 write_std.size = send_mac_to_plugin (write_std.buf, &macaddr);
359
360 while (0 == closeprog)
361 {
362 maxfd = -1;
363 tv.tv_sec = 5;
364 tv.tv_usec = 0;
365
366 FD_ZERO (&rfds);
367 FD_ZERO (&wfds);
368 /* if output queue is empty, read */
369 if (0 == write_pout.size)
370 {
371 FD_SET (STDIN_FILENO, &rfds);
372 maxfd = MAX (STDIN_FILENO, maxfd);
373 }
374 if (0 == write_std.size)
375 {
376 FD_SET (fdpin, &rfds);
377 maxfd = MAX (fdpin, maxfd);
378 }
379
380 /* if there is something to write, try to write */
381 if (0 < write_std.size)
382 {
383 FD_SET (STDOUT_FILENO, &wfds);
384 maxfd = MAX (maxfd, STDOUT_FILENO);
385 }
386 if (0 < write_pout.size)
387 {
388 FD_SET (fdpout, &wfds);
389 maxfd = MAX (maxfd, fdpout);
390 }
391
392 retval = select (maxfd + 1, &rfds, &wfds, NULL, &tv);
393 if ((-1 == retval) && (EINTR == errno))
394 continue;
395 if (0 > retval)
396 {
397 fprintf (stderr, "select failed: %s\n", strerror (errno));
398 closeprog = 1;
399 break;
400 }
401
402 if (FD_ISSET (STDOUT_FILENO, &wfds))
403 {
404 ret = write (STDOUT_FILENO,
405 write_std.buf + write_std.pos,
406 write_std.size - write_std.pos);
407 if (0 > ret)
408 {
409 closeprog = 1;
410 fprintf (stderr,
411 "Write ERROR to STDOUT_FILENO: %s\n",
412 strerror (errno));
413 break;
414 }
415 else
416 {
417 write_std.pos += ret;
418 /* check if finished writing */
419 if (write_std.pos == write_std.size)
420 {
421 write_std.pos = 0;
422 write_std.size = 0;
423 }
424 }
425 }
426
427 if (FD_ISSET (fdpout, &wfds))
428 {
429 ret = write (fdpout,
430 write_pout.buf + write_pout.pos,
431 write_pout.size - write_pout.pos);
432
433 if (0 > ret)
434 {
435 closeprog = 1;
436 fprintf (stderr,
437 "Write ERROR to fdpout failed: %s\n",
438 strerror (errno));
439 }
440 else
441 {
442 write_pout.pos += ret;
443 /* check if finished writing */
444 if (write_pout.pos == write_pout.size)
445 {
446 write_pout.pos = 0;
447 write_pout.size = 0;
448 }
449 }
450 }
451
452 if (FD_ISSET (STDIN_FILENO, &rfds))
453 {
454 readsize = read (STDIN_FILENO, readbuf, sizeof(readbuf));
455
456 if (0 > readsize)
457 {
458 closeprog = 1;
459 fprintf (stderr,
460 "Error reading from STDIN_FILENO: %s\n",
461 strerror (errno));
462 }
463 else if (0 < readsize)
464 {
465 GNUNET_MST_from_buffer (stdin_mst,
466 readbuf,
467 readsize,
468 GNUNET_NO,
469 GNUNET_NO);
470 }
471 else
472 {
473 /* eof */
474 closeprog = 1;
475 }
476 }
477
478 if (FD_ISSET (fdpin, &rfds))
479 {
480 readsize = read (fdpin, readbuf, sizeof(readbuf));
481 if (0 > readsize)
482 {
483 closeprog = 1;
484 fprintf (stderr, "Error reading from fdpin: %s\n", strerror (errno));
485 break;
486 }
487 else if (0 < readsize)
488 {
489 GNUNET_MST_from_buffer (file_in_mst,
490 readbuf,
491 readsize,
492 GNUNET_NO,
493 GNUNET_NO);
494 }
495 else
496 {
497 /* eof */
498 closeprog = 1;
499 }
500 }
501 }
502
503end:
504 /* clean up */
505 if (NULL != stdin_mst)
506 GNUNET_MST_destroy (stdin_mst);
507 if (NULL != file_in_mst)
508 GNUNET_MST_destroy (file_in_mst);
509
510 if (NULL != fpout)
511 fclose (fpout);
512 if (NULL != fpin)
513 fclose (fpin);
514 if (1 == first)
515 {
516 (void) unlink (FIFO_FILE1);
517 (void) unlink (FIFO_FILE2);
518 }
519 return 0;
520}
diff --git a/src/transport/gnunet-helper-transport-wlan.c b/src/transport/gnunet-helper-transport-wlan.c
deleted file mode 100644
index 72dd8b594..000000000
--- a/src/transport/gnunet-helper-transport-wlan.c
+++ /dev/null
@@ -1,2184 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010, 2011, 2012 GNUnet e.V.
4 Copyright (c) 2007, 2008, Andy Green <andy@warmcat.com>
5 Copyright Copyright (C) 2009 Thomas d'Otreppe
6
7 GNUnet is free software: you can redistribute it and/or modify it
8 under the terms of the GNU Affero General Public License as published
9 by the Free Software Foundation, either version 3 of the License,
10 or (at your option) any later version.
11
12 GNUnet is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program. If not, see <http://www.gnu.org/licenses/>.
19
20 SPDX-License-Identifier: AGPL3.0-or-later
21 */
22/**
23 * @file src/transport/gnunet-helper-transport-wlan.c
24 * @brief mediator between the wlan interface and gnunet; must run as root (SUID will do)
25 * This code will work under GNU/Linux only.
26 * @author David Brodski
27 * @author Christian Grothoff
28 *
29 * This program will allow receiving and sending traffic from the WLAN
30 * interface. It will force traffic to be in 'ad-hoc' mode, use the
31 * proper MAC address of the WLAN interface and use a GNUnet-specific
32 * SSID (and a GNUnet-specific SNAP header). It only takes a single
33 * argument, which is the name of the WLAN interface to use. The
34 * program detects if the interface is not a WLAN interface and exits
35 * with an error in that case.
36 *
37 * Once initialized, the program will first send a 'struct
38 * GNUNET_TRANSPORT_WLAN_HelperControlMessage' to 'stdout'. That
39 * message contains the MAC address of the WLAN interface. It will
40 * then read messages from the WLAN interface and send them together
41 * with performance information as 'struct
42 * GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage' messages to 'stdout'.
43 * Furthermore, it will read a stream of messages from 'stdin' that
44 * have the format from 'struct
45 * GNUNET_TRANSPORT_WLAN_RadiotapSendMessage'. Those messages will
46 * then be sent via the WLAN interface; however, the sender MAC
47 * address will be forced to be the correct address from our WLAN
48 * card. If 'stdin' closes, receiving from the WLAN interface will
49 * continue. If 'stdout' causes a SIGPIPE, the process dies from the
50 * signal. Errors cause an error message to be reported to 'stderr',
51 * in most cases the process also exits (with status code '1'). The
52 * program never terminates normally; it is safe to kill the
53 * process with SIGTERM or SIGKILL at any time.
54 *
55 * Since it uses RAW sockets, the binary must be installed SUID or run
56 * as 'root'. In order to keep the security risk of the resulting
57 * SUID binary minimal, the program ONLY opens the RAW socket with
58 * root privileges, then drops them and only then starts to process
59 * command line arguments. The code also does not link against any
60 * shared libraries (except libc) and is strictly minimal (except for
61 * checking for errors). The following list of people have reviewed
62 * this code and considered it safe since the last modification (if
63 * you reviewed it, please have your name added to the list):
64 *
65 * - Christian Grothoff (Apr 3rd 2012)
66 */
67
68/*-
69 * we use our local copy of ieee80211_radiotap.h
70 *
71 * - since we can't support extensions we don't understand
72 * - since linux does not include it in userspace headers
73 *
74 * Portions of this code were taken from the ieee80211_radiotap.h header,
75 * which is
76 *
77 * Copyright (c) 2003, 2004 David Young. All rights reserved.
78 *
79 * Redistribution and use in source and binary forms, with or without
80 * modification, are permitted provided that the following conditions
81 * are met:
82 * 1. Redistributions of source code must retain the above copyright
83 * notice, this list of conditions and the following disclaimer.
84 * 2. Redistributions in binary form must reproduce the above copyright
85 * notice, this list of conditions and the following disclaimer in the
86 * documentation and/or other materials provided with the distribution.
87 * 3. The name of David Young may not be used to endorse or promote
88 * products derived from this software without specific prior
89 * written permission.
90 *
91 * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
92 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
93 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
94 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
95 * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
96 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
97 * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
98 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
99 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
100 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
101 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
102 * OF SUCH DAMAGE.
103 */
104
105/*
106 * Modifications to fit into the linux IEEE 802.11 stack,
107 * Mike Kershaw (dragorn@kismetwireless.net)
108 */
109/*
110 * parts taken from aircrack-ng, parts changend.
111 */
112#include "gnunet_config.h"
113#include <sys/socket.h>
114#include <sys/ioctl.h>
115#include <sys/types.h>
116#include <unistd.h>
117#include <sys/wait.h>
118#include <sys/time.h>
119#include <sys/stat.h>
120#include <netpacket/packet.h>
121#include <linux/if_ether.h>
122#include <linux/if.h>
123#include <linux/wireless.h>
124#include <netinet/in.h>
125#include <linux/if_tun.h>
126#include <stdio.h>
127#include <stdlib.h>
128#include <string.h>
129#include <stdarg.h>
130#include <fcntl.h>
131#include <errno.h>
132#include <dirent.h>
133#include <sys/param.h>
134#include <unistd.h>
135#include <stdint.h>
136
137#include "gnunet_protocols.h"
138#include "plugin_transport_wlan.h"
139
140/**
141 * Packet format type for the messages we receive from
142 * the kernel. This is for Ethernet 10Mbps format (no
143 * performance information included).
144 */
145#define ARPHRD_ETHER 1
146
147
148/**
149 * Packet format type for the messages we receive from
150 * the kernel. This is for plain messages (with no
151 * performance information included).
152 */
153#define ARPHRD_IEEE80211 801
154
155
156/**
157 * Packet format type for the messages we receive from
158 * the kernel. This is for the PRISM format.
159 */
160#define ARPHRD_IEEE80211_PRISM 802
161
162/**
163 * Packet format type for the messages we receive from
164 * the kernel. This is for messages with a
165 * 'struct Ieee80211RadiotapHeader' (see below).
166 */
167#define ARPHRD_IEEE80211_FULL 803
168
169
170/**
171 * Maximum size of a message allowed in either direction
172 * (used for our receive and sent buffers).
173 */
174#define MAXLINE 4096
175
176
177/* ********* structure of messages of type ARPHRD_IEEE80211_PRISM *********** */
178
179/**
180 * Device name length in PRISM frames.
181 * (In the kernel, this is "WLAN_DEVNAMELEN_MAX")
182 */
183#define PRISM_DEVICE_NAME_LENGTH 16
184
185/**
186 * Monitor Frame (indicator that we have a 'struct PrismHeader').
187 */
188#define PRISM_MSGCODE_MONITOR 0x0041
189
190/**
191 * Mac time element. In micro-seconds.
192 * Drivers appear to use a 64bit counter to hold mactime internal
193 * the then fill the prism header with the lower 32 bits
194 */
195#define PRISM_DID_MACTIME 0x2041
196
197/**
198 * Channel element
199 */
200#define PRISM_DID_CHANNEL 0x3041
201
202/**
203 * Signal element. Should be the signal strength in dbm, some people
204 * suggest that instead "100 - (strength in dbm)" is used (to make this
205 * a positive integer).
206 */
207#define PRISM_DID_SIGNAL 0x6041
208
209/**
210 * Noise element
211 */
212#define PRISM_DID_NOISE 0x7041
213
214/**
215 * Rate element, in units/multiples of 500Khz
216 */
217#define PRISM_DID_RATE 0x8041
218
219
220/**
221 * Value is set (supplied)
222 */
223#define PRISM_STATUS_OK 0
224
225/**
226 * Value not supplied.
227 */
228#define PRISM_STATUS_NO_VALUE 1
229
230
231/**
232 * Values in the 'struct PrismHeader'. All in host byte order (!).
233 */
234struct PrismValue
235{
236 /**
237 * This has a different ID for each parameter, see
238 * PRISM_DID_* constants.
239 */
240 uint32_t did;
241
242 /**
243 * See PRISM_STATUS_*-constants. Note that they are unusual: 0 = set; 1 = not set
244 */
245 uint16_t status;
246
247 /**
248 * length of data (which is always a uint32_t, but presumably this can be used
249 * to specify that fewer bytes are used (with values in 'len' from 0-4). We
250 * ignore this field.
251 */
252 uint16_t len;
253
254 /**
255 * The data value
256 */
257 uint32_t data;
258} __attribute__ ((packed));
259
260
261/**
262 * Prism header format ('struct p80211msg' in Linux). All in host byte order (!).
263 */
264struct PrismHeader
265{
266 /**
267 * We expect this to be a PRISM_MSGCODE_*.
268 */
269 uint32_t msgcode;
270
271 /**
272 * The length of the entire header.
273 */
274 uint32_t msglen;
275
276 /**
277 * Name of the device that captured the packet.
278 */
279 char devname[PRISM_DEVICE_NAME_LENGTH];
280
281 /* followed by 'struct PrismValue's. Documentation suggests that these
282 are typically the hosttime, mactime, channel, rssi, sq, signal, noise,
283 rate, istx and frmlen values, but documentation is sparse. So we
284 will use the 'did' fields to find out what we actually got. */
285} __attribute__ ((packed));
286
287
288/* ****** end of structure of messages of type ARPHRD_IEEE80211_PRISM ******* */
289
290/* ********** structure of messages of type ARPHRD_IEEE80211_FULL *********** */
291
292/**
293 * Bits in the 'it_present' bitmask from the 'struct
294 * Ieee80211RadiotapHeader'. For each value, we give the name, data
295 * type, unit and then a description below. Note that the actual size
296 * of the extension can be bigger as arguments must be padded so that
297 * args of a given length must begin at a boundary of that length.
298 * However, note that compound args are allowed (eg, 2 x uint16_t for
299 * IEEE80211_RADIOTAP_CHANNEL) so total argument length is not a
300 * reliable indicator of alignment requirement. See also
301 * 'man 9 ieee80211_radiotap'.
302 */
303enum RadiotapType
304{
305 /**
306 * IEEE80211_RADIOTAP_TSFT __le64 microseconds
307 *
308 * Value in microseconds of the MAC's 64-bit 802.11 Time
309 * Synchronization Function timer when the first bit of the
310 * MPDU arrived at the MAC. For received frames, only.
311 */
312 IEEE80211_RADIOTAP_TSFT = 0,
313
314 /**
315 * IEEE80211_RADIOTAP_FLAGS uint8_t bitmap
316 *
317 * Properties of transmitted and received frames. See flags
318 * defined below.
319 */
320 IEEE80211_RADIOTAP_FLAGS = 1,
321
322 /**
323 * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s
324 *
325 * Tx/Rx data rate
326 */
327 IEEE80211_RADIOTAP_RATE = 2,
328
329 /**
330 * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap
331 *
332 * Tx/Rx frequency in MHz, followed by flags (see below).
333 */
334 IEEE80211_RADIOTAP_CHANNEL = 3,
335 /**
336 * IEEE80211_RADIOTAP_FHSS __le16 see below
337 *
338 * For frequency-hopping radios, the hop set (first byte)
339 * and pattern (second byte).
340 */
341 IEEE80211_RADIOTAP_FHSS = 4,
342
343 /**
344 * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
345 * one milliwatt (dBm)
346 *
347 * RF signal power at the antenna, decibel difference from
348 * one milliwatt.
349 */
350 IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
351
352 /**
353 * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
354 * one milliwatt (dBm)
355 *
356 * RF noise power at the antenna, decibel difference from one
357 * milliwatt.
358 */
359 IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
360
361 /**
362 * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless
363 *
364 * Quality of Barker code lock. Unitless. Monotonically
365 * nondecreasing with "better" lock strength. Called "Signal
366 * Quality" in datasheets. (Is there a standard way to measure
367 * this?)
368 */
369 IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
370
371 /**
372 * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless
373 *
374 * Transmit power expressed as unitless distance from max
375 * power set at factory calibration. 0 is max power.
376 * Monotonically nondecreasing with lower power levels.
377 */
378 IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
379
380 /**
381 * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB)
382 *
383 * Transmit power expressed as decibel distance from max power
384 * set at factory calibration. 0 is max power. Monotonically
385 * nondecreasing with lower power levels.
386 */
387 IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
388
389 /**
390 * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
391 * one milliwatt (dBm)
392 *
393 * Transmit power expressed as dBm (decibels from a 1 milliwatt
394 * reference). This is the absolute power level measured at
395 * the antenna port.
396 */
397 IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
398
399 /**
400 * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index
401 *
402 * Unitless indication of the Rx/Tx antenna for this packet.
403 * The first antenna is antenna 0.
404 */
405 IEEE80211_RADIOTAP_ANTENNA = 11,
406
407 /**
408 * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB)
409 *
410 * RF signal power at the antenna, decibel difference from an
411 * arbitrary, fixed reference.
412 */
413 IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
414
415 /**
416 * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB)
417 *
418 * RF noise power at the antenna, decibel difference from an
419 * arbitrary, fixed reference point.
420 */
421 IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
422
423 /**
424 * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap
425 *
426 * Properties of received frames. See flags defined below.
427 */
428 IEEE80211_RADIOTAP_RX_FLAGS = 14,
429
430 /**
431 * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap
432 *
433 * Properties of transmitted frames. See flags defined below.
434 */
435 IEEE80211_RADIOTAP_TX_FLAGS = 15,
436
437 /**
438 * IEEE80211_RADIOTAP_RTS_RETRIES uint8_t data
439 *
440 * Number of rts retries a transmitted frame used.
441 */
442 IEEE80211_RADIOTAP_RTS_RETRIES = 16,
443
444 /**
445 * IEEE80211_RADIOTAP_DATA_RETRIES uint8_t data
446 *
447 * Number of unicast retries a transmitted frame used.
448 */
449 IEEE80211_RADIOTAP_DATA_RETRIES = 17,
450
451 /**
452 * Extension bit, used to indicate that more bits are needed for
453 * the bitmask.
454 */
455 IEEE80211_RADIOTAP_EXT = 31
456};
457
458/**
459 * Bitmask indicating an extension of the bitmask is used.
460 * (Mask corresponding to IEEE80211_RADIOTAP_EXT).
461 */
462#define IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK (1 << IEEE80211_RADIOTAP_EXT)
463
464
465/**
466 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
467 * as part of a 'struct Ieee80211RadiotapHeader' extension
468 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
469 * 'it_present'). The radiotap flags are an 8-bit field.
470 *
471 * Frame was sent/received during CFP (Contention Free Period)
472 */
473#define IEEE80211_RADIOTAP_F_CFP 0x01
474
475/**
476 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
477 * as part of a 'struct Ieee80211RadiotapHeader' extension
478 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
479 * 'it_present'). The radiotap flags are an 8-bit field.
480 *
481 * Frame was sent/received with short preamble
482 */
483#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02
484
485/**
486 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
487 * as part of a 'struct Ieee80211RadiotapHeader' extension
488 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
489 * 'it_present'). The radiotap flags are an 8-bit field.
490 *
491 * Frame was sent/received with WEP encryption
492 */
493#define IEEE80211_RADIOTAP_F_WEP 0x04
494
495/**
496 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
497 * as part of a 'struct Ieee80211RadiotapHeader' extension
498 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
499 * 'it_present'). The radiotap flags are an 8-bit field.
500 *
501 * Frame was sent/received with fragmentation
502 */
503#define IEEE80211_RADIOTAP_F_FRAG 0x08
504
505/**
506 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
507 * as part of a 'struct Ieee80211RadiotapHeader' extension
508 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
509 * 'it_present'). The radiotap flags are an 8-bit field.
510 *
511 * Frame includes FCS (CRC at the end that needs to be removeD).
512 */
513#define IEEE80211_RADIOTAP_F_FCS 0x10
514
515/**
516 * Bit in IEEE80211_RADIOTAP_FLAGS (which we might get
517 * as part of a 'struct Ieee80211RadiotapHeader' extension
518 * if the IEEE80211_RADIOTAP_FLAGS bit is set in
519 * 'it_present'). The radiotap flags are an 8-bit field.
520 *
521 * Frame has padding between 802.11 header and payload
522 * (to 32-bit boundary)
523 */
524#define IEEE80211_RADIOTAP_F_DATAPAD 0x20
525
526
527/**
528 * For IEEE80211_RADIOTAP_RX_FLAGS:
529 * frame failed crc check
530 */
531#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001
532
533/**
534 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
535 * failed due to excessive retries
536 */
537#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001
538
539/**
540 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
541 * used cts 'protection'
542 */
543#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002
544
545/**
546 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
547 * used rts/cts handshake
548 */
549#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004
550
551/**
552 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
553 * frame should not be ACKed
554 */
555#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008
556
557/**
558 * For IEEE80211_RADIOTAP_TX_FLAGS ('txflags' in 'struct RadiotapTransmissionHeader'):
559 * sequence number handled by userspace
560 */
561#define IEEE80211_RADIOTAP_F_TX_NOSEQ 0x0010
562
563
564/**
565 * Generic header for radiotap messages (receiving and sending). A
566 * bit mask (it_present) determines which specific records follow.
567 *
568 * I am trying to describe precisely what the application programmer
569 * should expect in the following, and for that reason I tell the
570 * units and origin of each measurement (where it applies), or else I
571 * use sufficiently weaselly language ("is a monotonically nondecreasing
572 * function of...") that I cannot set false expectations for lawyerly
573 * readers.
574 *
575 * The radio capture header precedes the 802.11 header.
576 * All data in the header is little endian on all platforms.
577 */
578struct Ieee80211RadiotapHeader
579{
580 /**
581 * Version 0. Only increases for drastic changes, introduction of
582 * compatible new fields does not count.
583 */
584 uint8_t it_version;
585
586 /**
587 * Padding. Set to 0.
588 */
589 uint8_t it_pad;
590
591 /**
592 * length of the whole header in bytes, including it_version,
593 * it_pad, it_len, and data fields.
594 */
595 uint16_t it_len;
596
597 /**
598 * A bitmap telling which fields are present. Set bit 31
599 * (0x80000000) to extend the bitmap by another 32 bits. Additional
600 * extensions are made by setting bit 31.
601 */
602 uint32_t it_present;
603};
604
605
606/**
607 * Format of the header we need to prepend to messages to be sent to the
608 * Kernel.
609 */
610struct RadiotapTransmissionHeader
611{
612 /**
613 * First we begin with the 'generic' header we also get when receiving
614 * messages.
615 */
616 struct Ieee80211RadiotapHeader header;
617
618 /**
619 * Transmission rate (we use 0, kernel makes up its mind anyway).
620 */
621 uint8_t rate;
622
623 /**
624 * Padding (we use 0). There is a requirement to pad args, so that
625 * args of a given length must begin at a boundary of that length.
626 * As our next argument is the 'it_len' with 2 bytes, we need 1 byte
627 * of padding.
628 */
629 uint8_t pad1;
630
631 /**
632 * Transmission flags from on the IEEE80211_RADIOTAP_F_TX_* constant family.
633 */
634 uint16_t txflags;
635};
636
637/**
638 * The above 'struct RadiotapTransmissionHeader' should have the
639 * following value for 'header.it_present' based on the presence of
640 * the 'rate' and 'txflags' in the overall struct.
641 */
642#define IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK ((1 \
643 << \
644 IEEE80211_RADIOTAP_RATE) \
645 | (1 \
646 << \
647 IEEE80211_RADIOTAP_TX_FLAGS))
648
649
650/**
651 * struct Ieee80211RadiotapHeaderIterator - tracks walk through present radiotap arguments
652 * in the radiotap header. Used when we parse radiotap packets received from the kernel.
653 */
654struct Ieee80211RadiotapHeaderIterator
655{
656 /**
657 * pointer to the radiotap header we are walking through
658 */
659 const struct Ieee80211RadiotapHeader *rtheader;
660
661 /**
662 * pointer to current radiotap arg
663 */
664 const uint8_t *this_arg;
665
666 /**
667 * internal next argument pointer
668 */
669 const uint8_t *arg;
670
671 /**
672 * internal pointer to next present uint32_t (if IEEE80211_RADIOTAP_EXT is used).
673 */
674 const uint32_t *next_bitmap;
675
676 /**
677 * length of radiotap header in host byte ordering
678 */
679 size_t max_length;
680
681 /**
682 * internal shifter for current uint32_t bitmap, (it_present in host byte order),
683 * If bit 0 is set, the 'arg_index' argument is present.
684 */
685 uint32_t bitmap_shifter;
686
687 /**
688 * IEEE80211_RADIOTAP_... index of current arg
689 */
690 unsigned int this_arg_index;
691
692 /**
693 * internal next argument index
694 */
695 unsigned int arg_index;
696};
697
698
699/* ************** end of structure of ARPHRD_IEEE80211_FULL ************** */
700
701/* ************************** our globals ******************************* */
702
703/**
704 * struct for storing the information of the hardware. There is only
705 * one of these.
706 */
707struct HardwareInfos
708{
709 /**
710 * file descriptor for the raw socket
711 */
712 int fd_raw;
713
714 /**
715 * Which format has the header that we're getting when receiving packets?
716 * Some ARPHRD_IEEE80211_XXX-value.
717 */
718 int arptype_in;
719
720 /**
721 * Name of the interface, not necessarily 0-terminated (!).
722 */
723 char iface[IFNAMSIZ];
724
725 /**
726 * MAC address of our own WLAN interface.
727 */
728 struct GNUNET_TRANSPORT_WLAN_MacAddress pl_mac;
729};
730
731
732/**
733 * IO buffer used for buffering data in transit (to wireless or to stdout).
734 */
735struct SendBuffer
736{
737 /**
738 * How many bytes of data are stored in 'buf' for transmission right now?
739 * Data always starts at offset 0 and extends to 'size'.
740 */
741 size_t size;
742
743 /**
744 * How many bytes that were stored in 'buf' did we already write to the
745 * destination? Always smaller than 'size'.
746 */
747 size_t pos;
748
749 /**
750 * Buffered data; twice the maximum allowed message size as we add some
751 * headers.
752 */
753 char buf[MAXLINE * 2];
754};
755
756
757/**
758 * Buffer for data read from stdin to be transmitted to the wirless card.
759 */
760static struct SendBuffer write_pout;
761
762/**
763 * Buffer for data read from the wireless card to be transmitted to stdout.
764 */
765static struct SendBuffer write_std;
766
767
768/* *********** specialized version of server_mst.c begins here ********** */
769
770/**
771 * To what multiple do we align messages? 8 byte should suffice for everyone
772 * for now.
773 */
774#define ALIGN_FACTOR 8
775
776/**
777 * Smallest supported message.
778 */
779#define MIN_BUFFER_SIZE sizeof(struct GNUNET_MessageHeader)
780
781
782/**
783 * Functions with this signature are called whenever a
784 * complete message is received by the tokenizer.
785 *
786 * @param cls closure
787 * @param message the actual message
788 */
789typedef void (*MessageTokenizerCallback) (void *cls,
790 const struct
791 GNUNET_MessageHeader *
792 message);
793
794/**
795 * Handle to a message stream tokenizer.
796 */
797struct MessageStreamTokenizer
798{
799 /**
800 * Function to call on completed messages.
801 */
802 MessageTokenizerCallback cb;
803
804 /**
805 * Closure for cb.
806 */
807 void *cb_cls;
808
809 /**
810 * Size of the buffer (starting at 'hdr').
811 */
812 size_t curr_buf;
813
814 /**
815 * How many bytes in buffer have we already processed?
816 */
817 size_t off;
818
819 /**
820 * How many bytes in buffer are valid right now?
821 */
822 size_t pos;
823
824 /**
825 * Beginning of the buffer. Typed like this to force alignment.
826 */
827 struct GNUNET_MessageHeader *hdr;
828};
829
830
831/**
832 * Create a message stream tokenizer.
833 *
834 * @param cb function to call on completed messages
835 * @param cb_cls closure for cb
836 * @return handle to tokenizer
837 */
838static struct MessageStreamTokenizer *
839mst_create (MessageTokenizerCallback cb,
840 void *cb_cls)
841{
842 struct MessageStreamTokenizer *ret;
843
844 ret = malloc (sizeof(struct MessageStreamTokenizer));
845 if (NULL == ret)
846 {
847 fprintf (stderr, "Failed to allocate buffer for tokenizer\n");
848 exit (1);
849 }
850 ret->hdr = malloc (MIN_BUFFER_SIZE);
851 if (NULL == ret->hdr)
852 {
853 fprintf (stderr, "Failed to allocate buffer for alignment\n");
854 exit (1);
855 }
856 ret->curr_buf = MIN_BUFFER_SIZE;
857 ret->cb = cb;
858 ret->cb_cls = cb_cls;
859 return ret;
860}
861
862
863/**
864 * Add incoming data to the receive buffer and call the
865 * callback for all complete messages.
866 *
867 * @param mst tokenizer to use
868 * @param buf input data to add
869 * @param size number of bytes in buf
870 * @return GNUNET_OK if we are done processing (need more data)
871 * GNUNET_SYSERR if the data stream is corrupt
872 */
873static int
874mst_receive (struct MessageStreamTokenizer *mst,
875 const char *buf, size_t size)
876{
877 const struct GNUNET_MessageHeader *hdr;
878 size_t delta;
879 uint16_t want;
880 char *ibuf;
881 int need_align;
882 unsigned long offset;
883 int ret;
884
885 ret = GNUNET_OK;
886 ibuf = (char *) mst->hdr;
887 while (mst->pos > 0)
888 {
889do_align:
890 if ((mst->curr_buf - mst->off < sizeof(struct GNUNET_MessageHeader)) ||
891 (0 != (mst->off % ALIGN_FACTOR)))
892 {
893 /* need to align or need more space */
894 mst->pos -= mst->off;
895 memmove (ibuf, &ibuf[mst->off], mst->pos);
896 mst->off = 0;
897 }
898 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
899 {
900 delta =
901 GNUNET_MIN (sizeof(struct GNUNET_MessageHeader)
902 - (mst->pos - mst->off), size);
903 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
904 mst->pos += delta;
905 buf += delta;
906 size -= delta;
907 }
908 if (mst->pos - mst->off < sizeof(struct GNUNET_MessageHeader))
909 {
910 return GNUNET_OK;
911 }
912 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
913 want = ntohs (hdr->size);
914 if (want < sizeof(struct GNUNET_MessageHeader))
915 {
916 fprintf (stderr,
917 "Received invalid message from stdin\n");
918 exit (1);
919 }
920 if (mst->curr_buf - mst->off < want)
921 {
922 /* need more space */
923 mst->pos -= mst->off;
924 memmove (ibuf, &ibuf[mst->off], mst->pos);
925 mst->off = 0;
926 }
927 if (want > mst->curr_buf)
928 {
929 mst->hdr = realloc (mst->hdr, want);
930 if (NULL == mst->hdr)
931 {
932 fprintf (stderr, "Failed to allocate buffer for alignment\n");
933 exit (1);
934 }
935 ibuf = (char *) mst->hdr;
936 mst->curr_buf = want;
937 }
938 hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
939 if (mst->pos - mst->off < want)
940 {
941 delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
942 GNUNET_memcpy (&ibuf[mst->pos], buf, delta);
943 mst->pos += delta;
944 buf += delta;
945 size -= delta;
946 }
947 if (mst->pos - mst->off < want)
948 {
949 return GNUNET_OK;
950 }
951 mst->cb (mst->cb_cls, hdr);
952 mst->off += want;
953 if (mst->off == mst->pos)
954 {
955 /* reset to beginning of buffer, it's free right now! */
956 mst->off = 0;
957 mst->pos = 0;
958 }
959 }
960 while (size > 0)
961 {
962 if (size < sizeof(struct GNUNET_MessageHeader))
963 break;
964 offset = (unsigned long) buf;
965 need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO;
966 if (GNUNET_NO == need_align)
967 {
968 /* can try to do zero-copy and process directly from original buffer */
969 hdr = (const struct GNUNET_MessageHeader *) buf;
970 want = ntohs (hdr->size);
971 if (want < sizeof(struct GNUNET_MessageHeader))
972 {
973 fprintf (stderr,
974 "Received invalid message from stdin\n");
975 exit (1);
976 }
977 if (size < want)
978 break; /* or not, buffer incomplete, so copy to private buffer... */
979 mst->cb (mst->cb_cls, hdr);
980 buf += want;
981 size -= want;
982 }
983 else
984 {
985 /* need to copy to private buffer to align;
986 * yes, we go a bit more spaghetti than usual here */
987 goto do_align;
988 }
989 }
990 if (size > 0)
991 {
992 if (size + mst->pos > mst->curr_buf)
993 {
994 mst->hdr = realloc (mst->hdr, size + mst->pos);
995 if (NULL == mst->hdr)
996 {
997 fprintf (stderr, "Failed to allocate buffer for alignment\n");
998 exit (1);
999 }
1000 ibuf = (char *) mst->hdr;
1001 mst->curr_buf = size + mst->pos;
1002 }
1003 if (mst->pos + size > mst->curr_buf)
1004 {
1005 fprintf (stderr,
1006 "Assertion failed\n");
1007 exit (1);
1008 }
1009 GNUNET_memcpy (&ibuf[mst->pos], buf, size);
1010 mst->pos += size;
1011 }
1012 return ret;
1013}
1014
1015
1016/**
1017 * Destroys a tokenizer.
1018 *
1019 * @param mst tokenizer to destroy
1020 */
1021static void
1022mst_destroy (struct MessageStreamTokenizer *mst)
1023{
1024 free (mst->hdr);
1025 free (mst);
1026}
1027
1028
1029/* ***************** end of server_mst.c clone ***************** **/
1030
1031
1032/* ************** code for handling of ARPHRD_IEEE80211_FULL ************** */
1033
1034/**
1035 * Radiotap header iteration
1036 *
1037 * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
1038 * struct Ieee80211RadiotapHeaderIterator (no need to init the struct beforehand)
1039 * then loop calling __ieee80211_radiotap_iterator_next()... it returns -1
1040 * if there are no more args in the header, or the next argument type index
1041 * that is present. The iterator's this_arg member points to the start of the
1042 * argument associated with the current argument index that is present,
1043 * which can be found in the iterator's this_arg_index member. This arg
1044 * index corresponds to the IEEE80211_RADIOTAP_... defines.
1045 *
1046 * @param iterator iterator to initialize
1047 * @param radiotap_header message to parse
1048 * @param max_length number of valid bytes in radiotap_header
1049 * @return 0 on success, -1 on error
1050 */
1051static int
1052ieee80211_radiotap_iterator_init (struct
1053 Ieee80211RadiotapHeaderIterator *iterator,
1054 const struct
1055 Ieee80211RadiotapHeader *radiotap_header,
1056 size_t max_length)
1057{
1058 if ((iterator == NULL) ||
1059 (radiotap_header == NULL))
1060 return -1;
1061
1062 /* Linux only supports version 0 radiotap format */
1063 if (0 != radiotap_header->it_version)
1064 return -1;
1065
1066 /* sanity check for allowed length and radiotap length field */
1067 if ((max_length < sizeof(struct Ieee80211RadiotapHeader)) ||
1068 (max_length < (GNUNET_le16toh (radiotap_header->it_len))))
1069 return -1;
1070
1071 memset (iterator, 0, sizeof(struct Ieee80211RadiotapHeaderIterator));
1072 iterator->rtheader = radiotap_header;
1073 iterator->max_length = GNUNET_le16toh (radiotap_header->it_len);
1074 iterator->bitmap_shifter = GNUNET_le32toh (radiotap_header->it_present);
1075 iterator->arg = ((uint8_t *) radiotap_header) + sizeof(struct
1076 Ieee80211RadiotapHeader);
1077
1078 /* find payload start allowing for extended bitmap(s) */
1079 if (0 != (iterator->bitmap_shifter & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK))
1080 {
1081 while (GNUNET_le32toh (*((uint32_t *) iterator->arg))
1082 & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)
1083 {
1084 iterator->arg += sizeof(uint32_t);
1085 /*
1086 * check for insanity where the present bitmaps
1087 * keep claiming to extend up to or even beyond the
1088 * stated radiotap header length
1089 */if (iterator->arg - ((uint8_t *) iterator->rtheader) >
1090 iterator->max_length)
1091 return -1;
1092 }
1093 iterator->arg += sizeof(uint32_t);
1094 /*
1095 * no need to check again for blowing past stated radiotap
1096 * header length, because ieee80211_radiotap_iterator_next
1097 * checks it before it is dereferenced
1098 */}
1099 /* we are all initialized happily */
1100 return 0;
1101}
1102
1103
1104/**
1105 * Returns the next radiotap parser iterator arg.
1106 *
1107 * This function returns the next radiotap arg index (IEEE80211_RADIOTAP_...)
1108 * and sets iterator->this_arg to point to the payload for the arg. It takes
1109 * care of alignment handling and extended present fields. interator->this_arg
1110 * can be changed by the caller. The args pointed to are in little-endian
1111 * format.
1112 *
1113 * @param iterator: radiotap_iterator to move to next arg (if any)
1114 * @return next present arg index on success or -1 if no more or error
1115 */
1116static int
1117ieee80211_radiotap_iterator_next (struct
1118 Ieee80211RadiotapHeaderIterator *iterator)
1119{
1120 /*
1121 * small length lookup table for all radiotap types we heard of
1122 * starting from b0 in the bitmap, so we can walk the payload
1123 * area of the radiotap header
1124 *
1125 * There is a requirement to pad args, so that args
1126 * of a given length must begin at a boundary of that length
1127 * -- but note that compound args are allowed (eg, 2 x uint16_t
1128 * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
1129 * a reliable indicator of alignment requirement.
1130 *
1131 * upper nybble: content alignment for arg
1132 * lower nybble: content length for arg
1133 */static const uint8_t rt_sizes[] = {
1134 [IEEE80211_RADIOTAP_TSFT] = 0x88,
1135 [IEEE80211_RADIOTAP_FLAGS] = 0x11,
1136 [IEEE80211_RADIOTAP_RATE] = 0x11,
1137 [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
1138 [IEEE80211_RADIOTAP_FHSS] = 0x22,
1139 [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
1140 [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
1141 [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
1142 [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
1143 [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
1144 [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
1145 [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
1146 [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
1147 [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
1148 [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
1149 [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
1150 [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
1151 [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11
1152 /*
1153 * add more here as they are defined in
1154 * include/net/ieee80211_radiotap.h
1155 */
1156 };
1157
1158 /*
1159 * for every radiotap entry we can at
1160 * least skip (by knowing the length)...
1161 */
1162 while (iterator->arg_index < sizeof(rt_sizes))
1163 {
1164 int hit = (0 != (iterator->bitmap_shifter & 1));
1165
1166 if (hit)
1167 {
1168 unsigned int wanted_alignment;
1169 unsigned int unalignment;
1170 /*
1171 * arg is present, account for alignment padding
1172 * 8-bit args can be at any alignment
1173 * 16-bit args must start on 16-bit boundary
1174 * 32-bit args must start on 32-bit boundary
1175 * 64-bit args must start on 64-bit boundary
1176 *
1177 * note that total arg size can differ from alignment of
1178 * elements inside arg, so we use upper nybble of length table
1179 * to base alignment on. First, 'wanted_alignment' is set to be
1180 * 1 for 8-bit, 2 for 16-bit, 4 for 32-bit and 8 for 64-bit
1181 * arguments. Then, we calculate the 'unalignment' (how many
1182 * bytes we are over by taking the difference of 'arg' and the
1183 * overall starting point modulo the desired alignment. As
1184 * desired alignments are powers of two, we can do modulo with
1185 * binary "&" (and also avoid the possibility of a division by
1186 * zero if the 'rt_sizes' table contains bogus entries).
1187 *
1188 * also note: these alignments are relative to the start of the
1189 * radiotap header. There is no guarantee that the radiotap
1190 * header itself is aligned on any kind of boundary, thus we
1191 * need to really look at the delta here.
1192 */wanted_alignment = rt_sizes[iterator->arg_index] >> 4;
1193 unalignment = (((void *) iterator->arg) - ((void *) iterator->rtheader))
1194 & (wanted_alignment - 1);
1195 if (0 != unalignment)
1196 {
1197 /* need padding (by 'wanted_alignment - unalignment') */
1198 iterator->arg_index += wanted_alignment - unalignment;
1199 }
1200
1201 /*
1202 * this is what we will return to user, but we need to
1203 * move on first so next call has something fresh to test
1204 */
1205 iterator->this_arg_index = iterator->arg_index;
1206 iterator->this_arg = iterator->arg;
1207
1208 /* internally move on the size of this arg (using lower nybble from
1209 the table) */
1210 iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
1211
1212 /*
1213 * check for insanity where we are given a bitmap that
1214 * claims to have more arg content than the length of the
1215 * radiotap section. We will normally end up equalling this
1216 * max_length on the last arg, never exceeding it.
1217 */if ((((void *) iterator->arg) - ((void *) iterator->rtheader)) >
1218 iterator->max_length)
1219 return -1;
1220 }
1221
1222 /* Now, move on to next bit / next entry */
1223 iterator->arg_index++;
1224
1225 if (0 == (iterator->arg_index % 32))
1226 {
1227 /* completed current uint32_t bitmap */
1228 if (0 != (iterator->bitmap_shifter & 1))
1229 {
1230 /* bit 31 was set, there is more; move to next uint32_t bitmap */
1231 iterator->bitmap_shifter = GNUNET_le32toh (*iterator->next_bitmap);
1232 iterator->next_bitmap++;
1233 }
1234 else
1235 {
1236 /* no more bitmaps: end (by setting arg_index to high, unsupported value) */
1237 iterator->arg_index = sizeof(rt_sizes);
1238 }
1239 }
1240 else
1241 {
1242 /* just try the next bit (while loop will move on) */
1243 iterator->bitmap_shifter >>= 1;
1244 }
1245
1246 /* if we found a valid arg earlier, return it now */
1247 if (hit)
1248 return iterator->this_arg_index;
1249 }
1250
1251 /* we don't know how to handle any more args (or there are no more),
1252 so we're done (this is not an error) */
1253 return -1;
1254}
1255
1256
1257/**
1258 * Calculate crc32, the start of the calculation
1259 *
1260 * @param buf buffer to calc the crc
1261 * @param len len of the buffer
1262 * @return crc sum
1263 */
1264static unsigned long
1265calc_crc_osdep (const unsigned char *buf, size_t len)
1266{
1267 static const unsigned long int crc_tbl_osdep[256] = {
1268 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
1269 0xE963A535, 0x9E6495A3,
1270 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
1271 0xE7B82D07, 0x90BF1D91,
1272 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB,
1273 0xF4D4B551, 0x83D385C7,
1274 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
1275 0xFA0F3D63, 0x8D080DF5,
1276 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447,
1277 0xD20D85FD, 0xA50AB56B,
1278 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
1279 0xDCD60DCF, 0xABD13D59,
1280 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
1281 0xCFBA9599, 0xB8BDA50F,
1282 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11,
1283 0xC1611DAB, 0xB6662D3D,
1284 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
1285 0x9FBFE4A5, 0xE8B8D433,
1286 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
1287 0x91646C97, 0xE6635C01,
1288 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B,
1289 0x8208F4C1, 0xF50FC457,
1290 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49,
1291 0x8CD37CF3, 0xFBD44C65,
1292 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
1293 0xA4D1C46D, 0xD3D6F4FB,
1294 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
1295 0xAA0A4C5F, 0xDD0D7CC9,
1296 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
1297 0xB966D409, 0xCE61E49F,
1298 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
1299 0xB7BD5C3B, 0xC0BA6CAD,
1300 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF,
1301 0x04DB2615, 0x73DC1683,
1302 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
1303 0x0A00AE27, 0x7D079EB1,
1304 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
1305 0x196C3671, 0x6E6B06E7,
1306 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9,
1307 0x17B7BE43, 0x60B08ED5,
1308 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767,
1309 0x3FB506DD, 0x48B2364B,
1310 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
1311 0x316E8EEF, 0x4669BE79,
1312 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
1313 0x220216B9, 0x5505262F,
1314 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
1315 0x2CD99E8B, 0x5BDEAE1D,
1316 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
1317 0x72076785, 0x05005713,
1318 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
1319 0x7CDCEFB7, 0x0BDBDF21,
1320 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B,
1321 0x6FB077E1, 0x18B74777,
1322 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
1323 0x616BFFD3, 0x166CCF45,
1324 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
1325 0x4969474D, 0x3E6E77DB,
1326 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
1327 0x47B2CF7F, 0x30B5FFE9,
1328 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
1329 0x54DE5729, 0x23D967BF,
1330 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1,
1331 0x5A05DF1B, 0x2D02EF8D
1332 };
1333
1334 unsigned long crc = 0xFFFFFFFF;
1335
1336 for (; len > 0; len--, buf++)
1337 crc = crc_tbl_osdep[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
1338 return(~crc);
1339}
1340
1341
1342/**
1343 * Calculate and check crc of the wlan packet
1344 *
1345 * @param buf buffer of the packet, with len + 4 bytes of data,
1346 * the last 4 bytes being the checksum
1347 * @param len length of the payload in data
1348 * @return 0 on success (checksum matches), 1 on error
1349 */
1350static int
1351check_crc_buf_osdep (const unsigned char *buf, size_t len)
1352{
1353 unsigned long crc;
1354
1355 crc = calc_crc_osdep (buf, len);
1356 buf += len;
1357 if ((((crc) & 0xFF) == buf[0]) && (((crc >> 8) & 0xFF) == buf[1]) &&
1358 ( ((crc >> 16) & 0xFF) == buf[2]) && ( ((crc >> 24) & 0xFF) == buf[3]) )
1359 return 0;
1360 return 1;
1361}
1362
1363
1364/* ************end of code for handling of ARPHRD_IEEE80211_FULL ************** */
1365
1366
1367/* ************beginning of code for reading packets from kernel ************** */
1368
1369/**
1370 * Return the channel from the frequency (in Mhz)
1371 *
1372 * @param frequency of the channel
1373 * @return number of the channel
1374 */
1375static int
1376get_channel_from_frequency (int32_t frequency)
1377{
1378 if ((frequency >= 2412) && (frequency <= 2472))
1379 return (frequency - 2407) / 5;
1380 if (frequency == 2484)
1381 return 14;
1382 if ((frequency >= 5000) && (frequency <= 6100))
1383 return (frequency - 5000) / 5;
1384 return -1;
1385}
1386
1387
1388/**
1389 * Get the channel used by our WLAN interface.
1390 *
1391 * @param dev pointer to the dev struct of the card
1392 * @return channel number, -1 on error
1393 */
1394static int
1395linux_get_channel (const struct HardwareInfos *dev)
1396{
1397 struct iwreq wrq;
1398 int32_t frequency;
1399
1400 memset (&wrq, 0, sizeof(struct iwreq));
1401 strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ);
1402 if (0 > ioctl (dev->fd_raw, SIOCGIWFREQ, &wrq))
1403 return -1;
1404 frequency = wrq.u.freq.m; /* 'iw_freq' defines 'm' as '__s32', so we keep it signed */
1405 if (100000000 < frequency)
1406 frequency /= 100000;
1407 else if (1000000 < frequency)
1408 frequency /= 1000;
1409 if (1000 < frequency)
1410 return get_channel_from_frequency (frequency);
1411 return frequency;
1412}
1413
1414
1415/**
1416 * Read from the raw socket (the wlan card), parse the packet and
1417 * put the result into the buffer for transmission to 'stdout'.
1418 *
1419 * @param dev pointer to the struct of the wlan card
1420 * @param buf buffer to read to; first bytes will be the 'struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame',
1421 * followed by the actual payload
1422 * @param buf_size size of the buffer
1423 * @param ri where to write radiotap_rx info
1424 * @return number of bytes written to 'buf'
1425 */
1426static ssize_t
1427linux_read (struct HardwareInfos *dev,
1428 unsigned char *buf, size_t buf_size,
1429 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *ri)
1430{
1431 unsigned char tmpbuf[buf_size];
1432 ssize_t caplen;
1433 size_t n;
1434 int got_signal = 0;
1435 int got_noise = 0;
1436 int got_channel = 0;
1437 int fcs_removed = 0;
1438
1439 caplen = read (dev->fd_raw, tmpbuf, buf_size);
1440 if (0 > caplen)
1441 {
1442 if (EAGAIN == errno)
1443 return 0;
1444 fprintf (stderr, "Failed to read from RAW socket: %s\n", strerror (errno));
1445 return -1;
1446 }
1447
1448 memset (ri, 0, sizeof(*ri));
1449 switch (dev->arptype_in)
1450 {
1451 case ARPHRD_IEEE80211_PRISM:
1452 {
1453 const struct PrismHeader *ph;
1454
1455 ph = (const struct PrismHeader*) tmpbuf;
1456 n = ph->msglen;
1457 if ((n < 8) || (n >= caplen))
1458 return 0; /* invalid format */
1459 if ((PRISM_MSGCODE_MONITOR == ph->msgcode) &&
1460 (n >= sizeof(struct PrismHeader)))
1461 {
1462 const char *pos;
1463 size_t left;
1464 struct PrismValue pv;
1465
1466 left = n - sizeof(struct PrismHeader);
1467 pos = (const char *) &ph[1];
1468 while (left > sizeof(struct PrismValue))
1469 {
1470 left -= sizeof(struct PrismValue);
1471 GNUNET_memcpy (&pv, pos, sizeof(struct PrismValue));
1472 pos += sizeof(struct PrismValue);
1473
1474 switch (pv.did)
1475 {
1476 case PRISM_DID_NOISE:
1477 if (PRISM_STATUS_OK == pv.status)
1478 {
1479 ri->ri_noise = pv.data;
1480 /* got_noise = 1; */
1481 }
1482 break;
1483
1484 case PRISM_DID_RATE:
1485 if (PRISM_STATUS_OK == pv.status)
1486 ri->ri_rate = pv.data * 500000;
1487 break;
1488
1489 case PRISM_DID_CHANNEL:
1490 if (PRISM_STATUS_OK == pv.status)
1491 {
1492 ri->ri_channel = pv.data;
1493 got_channel = 1;
1494 }
1495 break;
1496
1497 case PRISM_DID_MACTIME:
1498 if (PRISM_STATUS_OK == pv.status)
1499 ri->ri_mactime = pv.data;
1500 break;
1501
1502 case PRISM_DID_SIGNAL:
1503 if (PRISM_STATUS_OK == pv.status)
1504 {
1505 ri->ri_power = pv.data;
1506 /* got_signal = 1; */
1507 }
1508 break;
1509 }
1510 }
1511 }
1512 if ((n < 8) || (n >= caplen))
1513 return 0; /* invalid format */
1514 }
1515 break;
1516
1517 case ARPHRD_IEEE80211_FULL:
1518 {
1519 struct Ieee80211RadiotapHeaderIterator iterator;
1520 struct Ieee80211RadiotapHeader *rthdr;
1521
1522 memset (&iterator, 0, sizeof(iterator));
1523 rthdr = (struct Ieee80211RadiotapHeader *) tmpbuf;
1524 n = GNUNET_le16toh (rthdr->it_len);
1525 if ((n < sizeof(struct Ieee80211RadiotapHeader)) || (n >= caplen))
1526 return 0; /* invalid 'it_len' */
1527 if (0 != ieee80211_radiotap_iterator_init (&iterator, rthdr, caplen))
1528 return 0;
1529 /* go through the radiotap arguments we have been given by the driver */
1530 while (0 <= ieee80211_radiotap_iterator_next (&iterator))
1531 {
1532 switch (iterator.this_arg_index)
1533 {
1534 case IEEE80211_RADIOTAP_TSFT:
1535 ri->ri_mactime = GNUNET_le64toh (*((uint64_t *) iterator.this_arg));
1536 break;
1537
1538 case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
1539 if (! got_signal)
1540 {
1541 ri->ri_power = *((int8_t *) iterator.this_arg);
1542 got_signal = 1;
1543 }
1544 break;
1545
1546 case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
1547 if (! got_signal)
1548 {
1549 ri->ri_power = *((int8_t *) iterator.this_arg);
1550 got_signal = 1;
1551 }
1552 break;
1553
1554 case IEEE80211_RADIOTAP_DBM_ANTNOISE:
1555 if (! got_noise)
1556 {
1557 ri->ri_noise = *((int8_t *) iterator.this_arg);
1558 got_noise = 1;
1559 }
1560 break;
1561
1562 case IEEE80211_RADIOTAP_DB_ANTNOISE:
1563 if (! got_noise)
1564 {
1565 ri->ri_noise = *((int8_t *) iterator.this_arg);
1566 got_noise = 1;
1567 }
1568 break;
1569
1570 case IEEE80211_RADIOTAP_ANTENNA:
1571 ri->ri_antenna = *iterator.this_arg;
1572 break;
1573
1574 case IEEE80211_RADIOTAP_CHANNEL:
1575 ri->ri_channel = *iterator.this_arg;
1576 got_channel = 1;
1577 break;
1578
1579 case IEEE80211_RADIOTAP_RATE:
1580 ri->ri_rate = (*iterator.this_arg) * 500000;
1581 break;
1582
1583 case IEEE80211_RADIOTAP_FLAGS:
1584 {
1585 uint8_t flags = *iterator.this_arg;
1586 /* is the CRC visible at the end? if so, remove */
1587 if (0 != (flags & IEEE80211_RADIOTAP_F_FCS))
1588 {
1589 fcs_removed = 1;
1590 caplen -= sizeof(uint32_t);
1591 }
1592 break;
1593 }
1594
1595 case IEEE80211_RADIOTAP_RX_FLAGS:
1596 {
1597 uint16_t flags = ntohs (*((uint16_t *) iterator.this_arg));
1598 if (0 != (flags & IEEE80211_RADIOTAP_F_RX_BADFCS))
1599 return 0;
1600 }
1601 break;
1602 } /* end of 'switch' */
1603 } /* end of the 'while' loop */
1604 }
1605 break;
1606
1607 case ARPHRD_IEEE80211:
1608 n = 0; /* no header */
1609 break;
1610
1611 case ARPHRD_ETHER:
1612 {
1613 if (sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame) > caplen)
1614 return 0; /* invalid */
1615 GNUNET_memcpy (&buf[sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame)],
1616 tmpbuf + sizeof(struct
1617 GNUNET_TRANSPORT_WLAN_Ieee8023Frame),
1618 caplen - sizeof(struct
1619 GNUNET_TRANSPORT_WLAN_Ieee8023Frame)
1620 - 4 /* 4 byte FCS */);
1621 return caplen - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame) - 4;
1622 }
1623
1624 default:
1625 errno = ENOTSUP; /* unsupported format */
1626 return -1;
1627 }
1628 caplen -= n;
1629 if (! got_channel)
1630 ri->ri_channel = linux_get_channel (dev);
1631
1632 /* detect CRC32 at the end, even if the flag wasn't set and remove it */
1633 if ((0 == fcs_removed) &&
1634 (0 == check_crc_buf_osdep (tmpbuf + n, caplen - sizeof(uint32_t))))
1635 {
1636 /* NOTE: this heuristic can of course fail if there happens to
1637 be a matching checksum at the end. Would be good to have
1638 some data to see how often this heuristic actually works. */
1639 caplen -= sizeof(uint32_t);
1640 }
1641 /* copy payload to target buffer */
1642 GNUNET_memcpy (buf, tmpbuf + n, caplen);
1643 return caplen;
1644}
1645
1646
1647/* ************end of code for reading packets from kernel ************** */
1648
1649/* ************other helper functions for main start here ************** */
1650
1651
1652/**
1653 * Open the wireless network interface for reading/writing.
1654 *
1655 * @param dev pointer to the device struct
1656 * @return 0 on success
1657 */
1658static int
1659open_device_raw (struct HardwareInfos *dev)
1660{
1661 struct ifreq ifr;
1662 struct iwreq wrq;
1663 struct packet_mreq mr;
1664 struct sockaddr_ll sll;
1665
1666 /* find the interface index */
1667 memset (&ifr, 0, sizeof(ifr));
1668 strncpy (ifr.ifr_name, dev->iface, IFNAMSIZ);
1669 if (-1 == ioctl (dev->fd_raw, SIOCGIFINDEX, &ifr))
1670 {
1671 fprintf (stderr, "ioctl(SIOCGIFINDEX) on interface `%.*s' failed: %s\n",
1672 IFNAMSIZ, dev->iface, strerror (errno));
1673 return 1;
1674 }
1675
1676 /* lookup the hardware type */
1677 memset (&sll, 0, sizeof(sll));
1678 sll.sll_family = AF_PACKET;
1679 sll.sll_ifindex = ifr.ifr_ifindex;
1680 sll.sll_protocol = htons (ETH_P_ALL);
1681 if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr))
1682 {
1683 fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n",
1684 IFNAMSIZ, dev->iface, strerror (errno));
1685 return 1;
1686 }
1687 if (((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
1688 (ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) &&
1689 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
1690 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)))
1691 {
1692 fprintf (stderr,
1693 "Error: interface `%.*s' is not using a supported hardware address family (got %d)\n",
1694 IFNAMSIZ, dev->iface,
1695 ifr.ifr_hwaddr.sa_family);
1696 return 1;
1697 }
1698
1699 /* lookup iw mode */
1700 memset (&wrq, 0, sizeof(struct iwreq));
1701 strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ);
1702 if (-1 == ioctl (dev->fd_raw, SIOCGIWMODE, &wrq))
1703 {
1704 /* most probably not supported (ie for rtap ipw interface) *
1705 * so just assume its correctly set... */
1706 wrq.u.mode = IW_MODE_MONITOR;
1707 }
1708
1709 if ((wrq.u.mode != IW_MODE_MONITOR) &&
1710 (wrq.u.mode != IW_MODE_ADHOC))
1711 {
1712 fprintf (stderr,
1713 "Error: interface `%.*s' is not in monitor or ad-hoc mode (got %d)\n",
1714 IFNAMSIZ, dev->iface,
1715 wrq.u.mode);
1716 return 1;
1717 }
1718
1719 /* Is interface st to up, broadcast & running ? */
1720 if ((ifr.ifr_flags | IFF_UP | IFF_BROADCAST | IFF_RUNNING) != ifr.ifr_flags)
1721 {
1722 /* Bring interface up */
1723 ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_RUNNING;
1724
1725 if (-1 == ioctl (dev->fd_raw, SIOCSIFFLAGS, &ifr))
1726 {
1727 fprintf (stderr, "ioctl(SIOCSIFFLAGS) on interface `%.*s' failed: %s\n",
1728 IFNAMSIZ, dev->iface, strerror (errno));
1729 return 1;
1730 }
1731 }
1732
1733 /* bind the raw socket to the interface */
1734 if (-1 == bind (dev->fd_raw, (struct sockaddr *) &sll, sizeof(sll)))
1735 {
1736 fprintf (stderr, "Failed to bind interface `%.*s': %s\n", IFNAMSIZ,
1737 dev->iface, strerror (errno));
1738 return 1;
1739 }
1740
1741 /* lookup the hardware type */
1742 if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr))
1743 {
1744 fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n",
1745 IFNAMSIZ, dev->iface, strerror (errno));
1746 return 1;
1747 }
1748
1749 GNUNET_memcpy (&dev->pl_mac, ifr.ifr_hwaddr.sa_data, MAC_ADDR_SIZE);
1750 dev->arptype_in = ifr.ifr_hwaddr.sa_family;
1751 if ((ifr.ifr_hwaddr.sa_family != ARPHRD_ETHER) &&
1752 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
1753 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
1754 (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL))
1755 {
1756 fprintf (stderr, "Unsupported hardware link type %d on interface `%.*s'\n",
1757 ifr.ifr_hwaddr.sa_family, IFNAMSIZ, dev->iface);
1758 return 1;
1759 }
1760
1761 /* enable promiscuous mode */
1762 memset (&mr, 0, sizeof(mr));
1763 mr.mr_ifindex = sll.sll_ifindex;
1764 mr.mr_type = PACKET_MR_PROMISC;
1765 if (0 !=
1766 setsockopt (dev->fd_raw, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr,
1767 sizeof(mr)))
1768 {
1769 fprintf (stderr,
1770 "Failed to enable promiscuous mode on interface `%.*s'\n",
1771 IFNAMSIZ,
1772 dev->iface);
1773 return 1;
1774 }
1775 return 0;
1776}
1777
1778
1779/**
1780 * Test if the given interface name really corresponds to a wireless
1781 * device.
1782 *
1783 * @param iface name of the interface
1784 * @return 0 on success, 1 on error
1785 */
1786static int
1787test_wlan_interface (const char *iface)
1788{
1789 char strbuf[512];
1790 struct stat sbuf;
1791 int ret;
1792
1793 ret = snprintf (strbuf, sizeof(strbuf),
1794 "/sys/class/net/%s/phy80211/subsystem",
1795 iface);
1796 if ((ret < 0) || (ret >= sizeof(strbuf)) || (0 != stat (strbuf, &sbuf)))
1797 {
1798 fprintf (stderr,
1799 "Did not find 802.11 interface `%s'. Exiting.\n",
1800 iface);
1801 exit (1);
1802 }
1803 return 0;
1804}
1805
1806
1807/**
1808 * Test incoming packets mac for being our own.
1809 *
1810 * @param taIeeeHeader buffer of the packet
1811 * @param dev the Hardware_Infos struct
1812 * @return 0 if mac belongs to us, 1 if mac is for another target
1813 */
1814static int
1815mac_test (const struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1816 const struct HardwareInfos *dev)
1817{
1818 static struct GNUNET_TRANSPORT_WLAN_MacAddress all_zeros;
1819
1820 if ((0 == memcmp (&taIeeeHeader->addr3, &all_zeros, MAC_ADDR_SIZE)) ||
1821 (0 == memcmp (&taIeeeHeader->addr1, &all_zeros, MAC_ADDR_SIZE)))
1822 return 0; /* some drivers set no Macs, then assume it is all for us! */
1823
1824 if (0 != memcmp (&taIeeeHeader->addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE))
1825 return 1; /* not a GNUnet ad-hoc package */
1826 if ((0 == memcmp (&taIeeeHeader->addr1, &dev->pl_mac, MAC_ADDR_SIZE)) ||
1827 (0 == memcmp (&taIeeeHeader->addr1, &bc_all_mac, MAC_ADDR_SIZE)))
1828 return 0; /* for us, or broadcast */
1829 return 1; /* not for us */
1830}
1831
1832
1833/**
1834 * Set the wlan header to sane values to make attacks more difficult
1835 *
1836 * @param taIeeeHeader pointer to the header of the packet
1837 * @param dev pointer to the Hardware_Infos struct
1838 */
1839static void
1840mac_set (struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *taIeeeHeader,
1841 const struct HardwareInfos *dev)
1842{
1843 taIeeeHeader->frame_control = htons (IEEE80211_FC0_TYPE_DATA);
1844 taIeeeHeader->addr2 = dev->pl_mac;
1845 taIeeeHeader->addr3 = mac_bssid_gnunet;
1846}
1847
1848
1849/**
1850 * Process data from the stdin. Takes the message, prepends the
1851 * radiotap transmission header, forces the sender MAC to be correct
1852 * and puts it into our buffer for transmission to the kernel.
1853 *
1854 * @param cls pointer to the device struct ('struct HardwareInfos*')
1855 * @param hdr pointer to the start of the packet
1856 */
1857static void
1858stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr)
1859{
1860 struct HardwareInfos *dev = cls;
1861 const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *header;
1862 struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame *wlanheader;
1863 size_t sendsize;
1864 struct RadiotapTransmissionHeader rtheader;
1865 struct GNUNET_TRANSPORT_WLAN_Ieee8023Frame etheader;
1866
1867 sendsize = ntohs (hdr->size);
1868 if ((sendsize <
1869 sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)) ||
1870 (GNUNET_MESSAGE_TYPE_WLAN_DATA_TO_HELPER != ntohs (hdr->type)))
1871 {
1872 fprintf (stderr, "Received malformed message\n");
1873 exit (1);
1874 }
1875 sendsize -= (sizeof(struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage)
1876 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
1877 if (MAXLINE < sendsize)
1878 {
1879 fprintf (stderr, "Packet too big for buffer\n");
1880 exit (1);
1881 }
1882 header = (const struct GNUNET_TRANSPORT_WLAN_RadiotapSendMessage *) hdr;
1883 switch (dev->arptype_in)
1884 {
1885 case ARPHRD_IEEE80211_PRISM:
1886 case ARPHRD_IEEE80211_FULL:
1887 case ARPHRD_IEEE80211:
1888 rtheader.header.it_version = 0;
1889 rtheader.header.it_pad = 0;
1890 rtheader.header.it_len = GNUNET_htole16 (sizeof(rtheader));
1891 rtheader.header.it_present = GNUNET_htole16 (
1892 IEEE80211_RADIOTAP_OUR_TRANSMISSION_HEADER_MASK);
1893 rtheader.rate = header->rate;
1894 rtheader.pad1 = 0;
1895 rtheader.txflags = GNUNET_htole16 (IEEE80211_RADIOTAP_F_TX_NOACK
1896 | IEEE80211_RADIOTAP_F_TX_NOSEQ);
1897 GNUNET_memcpy (write_pout.buf, &rtheader, sizeof(rtheader));
1898 GNUNET_memcpy (&write_pout.buf[sizeof(rtheader)], &header->frame, sendsize);
1899 wlanheader = (struct
1900 GNUNET_TRANSPORT_WLAN_Ieee80211Frame *) &write_pout.buf[sizeof(
1901 rtheader)
1902 ];
1903
1904 /* payload contains MAC address, but we don't trust it, so we'll
1905 * overwrite it with OUR MAC address to prevent mischief */
1906 mac_set (wlanheader, dev);
1907 write_pout.size = sendsize + sizeof(rtheader);
1908 break;
1909
1910 case ARPHRD_ETHER:
1911 etheader.dst = header->frame.addr1;
1912 /* etheader.src = header->frame.addr2; --- untrusted input */
1913 etheader.src = dev->pl_mac;
1914 etheader.type = htons (ETH_P_IP);
1915 GNUNET_memcpy (write_pout.buf, &etheader, sizeof(etheader));
1916 GNUNET_memcpy (&write_pout.buf[sizeof(etheader)], &header[1], sendsize
1917 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame));
1918 write_pout.size = sendsize - sizeof(struct
1919 GNUNET_TRANSPORT_WLAN_Ieee80211Frame)
1920 + sizeof(etheader);
1921 break;
1922
1923 default:
1924 fprintf (stderr,
1925 "Unsupported ARPTYPE!\n");
1926 break;
1927 }
1928}
1929
1930
1931/**
1932 * Main function of the helper. This code accesses a WLAN interface
1933 * in monitoring mode (layer 2) and then forwards traffic in both
1934 * directions between the WLAN interface and stdin/stdout of this
1935 * process. Error messages are written to stdout.
1936 *
1937 * @param argc number of arguments, must be 2
1938 * @param argv arguments only argument is the name of the interface (e.g. 'mon0')
1939 * @return 0 on success (never happens, as we don't return unless aborted), 1 on error
1940 */
1941int
1942main (int argc, char *argv[])
1943{
1944 struct HardwareInfos dev;
1945 char readbuf[MAXLINE];
1946 int maxfd;
1947 fd_set rfds;
1948 fd_set wfds;
1949 int stdin_open;
1950 struct MessageStreamTokenizer *stdin_mst;
1951 int raw_eno;
1952
1953 /* assert privs so we can modify the firewall rules! */
1954 {
1955#ifdef HAVE_SETRESUID
1956 uid_t uid = getuid ();
1957
1958 if (0 != setresuid (uid, 0, 0))
1959 {
1960 fprintf (stderr,
1961 "Failed to setresuid to root: %s\n",
1962 strerror (errno));
1963 return 254;
1964 }
1965#else
1966 if (0 != seteuid (0))
1967 {
1968 fprintf (stderr,
1969 "Failed to seteuid back to root: %s\n", strerror (errno));
1970 return 254;
1971 }
1972#endif
1973 }
1974
1975 /* make use of SGID capabilities on POSIX */
1976 memset (&dev, 0, sizeof(dev));
1977 dev.fd_raw = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
1978 raw_eno = errno; /* remember for later */
1979
1980 /* now that we've dropped root rights, we can do error checking */
1981 if (2 != argc)
1982 {
1983 fprintf (stderr,
1984 "You must specify the name of the interface as the first and only argument to this program.\n");
1985 if (-1 != dev.fd_raw)
1986 (void) close (dev.fd_raw);
1987 return 1;
1988 }
1989
1990 if (-1 == dev.fd_raw)
1991 {
1992 fprintf (stderr, "Failed to create raw socket: %s\n", strerror (raw_eno));
1993 return 1;
1994 }
1995 if (dev.fd_raw >= FD_SETSIZE)
1996 {
1997 fprintf (stderr, "File descriptor too large for select (%d > %d)\n",
1998 dev.fd_raw, FD_SETSIZE);
1999 (void) close (dev.fd_raw);
2000 return 1;
2001 }
2002 if (0 != test_wlan_interface (argv[1]))
2003 {
2004 (void) close (dev.fd_raw);
2005 return 1;
2006 }
2007 memcpy (dev.iface, argv[1], IFNAMSIZ);
2008 if (0 != open_device_raw (&dev))
2009 {
2010 (void) close (dev.fd_raw);
2011 return 1;
2012 }
2013
2014 /* drop privs */
2015 {
2016 uid_t uid = getuid ();
2017#ifdef HAVE_SETRESUID
2018 if (0 != setresuid (uid, uid, uid))
2019 {
2020 fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
2021 if (-1 != dev.fd_raw)
2022 (void) close (dev.fd_raw);
2023 return 1;
2024 }
2025#else
2026 if (0 != (setuid (uid) | seteuid (uid)))
2027 {
2028 fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
2029 if (-1 != dev.fd_raw)
2030 (void) close (dev.fd_raw);
2031 return 1;
2032 }
2033#endif
2034 }
2035
2036
2037 /* send MAC address of the WLAN interface to STDOUT first */
2038 {
2039 struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
2040
2041 macmsg.hdr.size = htons (sizeof(macmsg));
2042 macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
2043 GNUNET_memcpy (&macmsg.mac, &dev.pl_mac, sizeof(struct
2044 GNUNET_TRANSPORT_WLAN_MacAddress));
2045 GNUNET_memcpy (write_std.buf, &macmsg, sizeof(macmsg));
2046 write_std.size = sizeof(macmsg);
2047 }
2048
2049 stdin_mst = mst_create (&stdin_send_hw, &dev);
2050 stdin_open = 1;
2051 while (1)
2052 {
2053 maxfd = -1;
2054 FD_ZERO (&rfds);
2055 if ((0 == write_pout.size) && (1 == stdin_open))
2056 {
2057 FD_SET (STDIN_FILENO, &rfds);
2058 maxfd = MAX (maxfd, STDIN_FILENO);
2059 }
2060 if (0 == write_std.size)
2061 {
2062 FD_SET (dev.fd_raw, &rfds);
2063 maxfd = MAX (maxfd, dev.fd_raw);
2064 }
2065 FD_ZERO (&wfds);
2066 if (0 < write_std.size)
2067 {
2068 FD_SET (STDOUT_FILENO, &wfds);
2069 maxfd = MAX (maxfd, STDOUT_FILENO);
2070 }
2071 if (0 < write_pout.size)
2072 {
2073 FD_SET (dev.fd_raw, &wfds);
2074 maxfd = MAX (maxfd, dev.fd_raw);
2075 }
2076 {
2077 int retval = select (maxfd + 1, &rfds, &wfds, NULL, NULL);
2078 if ((-1 == retval) && (EINTR == errno))
2079 continue;
2080 if (0 > retval)
2081 {
2082 fprintf (stderr, "select failed: %s\n", strerror (errno));
2083 break;
2084 }
2085 }
2086 if (FD_ISSET (STDOUT_FILENO, &wfds))
2087 {
2088 ssize_t ret =
2089 write (STDOUT_FILENO, write_std.buf + write_std.pos,
2090 write_std.size - write_std.pos);
2091 if (0 > ret)
2092 {
2093 fprintf (stderr, "Failed to write to STDOUT: %s\n", strerror (errno));
2094 break;
2095 }
2096 write_std.pos += ret;
2097 if (write_std.pos == write_std.size)
2098 {
2099 write_std.pos = 0;
2100 write_std.size = 0;
2101 }
2102 }
2103 if (FD_ISSET (dev.fd_raw, &wfds))
2104 {
2105 ssize_t ret =
2106 write (dev.fd_raw, write_pout.buf + write_pout.pos,
2107 write_pout.size - write_pout.pos);
2108 if (0 > ret)
2109 {
2110 fprintf (stderr, "Failed to write to WLAN device: %s\n",
2111 strerror (errno));
2112 break;
2113 }
2114 write_pout.pos += ret;
2115 if ((write_pout.pos != write_pout.size) && (0 != ret))
2116 {
2117 /* we should not get partial sends with packet-oriented devices... */
2118 fprintf (stderr, "Write error, partial send: %u/%u\n",
2119 (unsigned int) write_pout.pos,
2120 (unsigned int) write_pout.size);
2121 break;
2122 }
2123 if (write_pout.pos == write_pout.size)
2124 {
2125 write_pout.pos = 0;
2126 write_pout.size = 0;
2127 }
2128 }
2129
2130 if (FD_ISSET (STDIN_FILENO, &rfds))
2131 {
2132 ssize_t ret =
2133 read (STDIN_FILENO, readbuf, sizeof(readbuf));
2134 if (0 > ret)
2135 {
2136 fprintf (stderr, "Read error from STDIN: %s\n", strerror (errno));
2137 break;
2138 }
2139 if (0 == ret)
2140 {
2141 /* stop reading... */
2142 stdin_open = 0;
2143 }
2144 mst_receive (stdin_mst, readbuf, ret);
2145 }
2146
2147 if (FD_ISSET (dev.fd_raw, &rfds))
2148 {
2149 struct GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *rrm;
2150 ssize_t ret;
2151
2152 rrm = (struct
2153 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage *) write_std.buf;
2154 ret =
2155 linux_read (&dev, (unsigned char *) &rrm->frame,
2156 sizeof(write_std.buf)
2157 - sizeof(struct
2158 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2159 + sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame),
2160 rrm);
2161 if (0 > ret)
2162 {
2163 fprintf (stderr, "Read error from raw socket: %s\n", strerror (errno));
2164 break;
2165 }
2166 if ((0 < ret) && (0 == mac_test (&rrm->frame, &dev)))
2167 {
2168 write_std.size = ret
2169 + sizeof(struct
2170 GNUNET_TRANSPORT_WLAN_RadiotapReceiveMessage)
2171 - sizeof(struct GNUNET_TRANSPORT_WLAN_Ieee80211Frame);
2172 rrm->header.size = htons (write_std.size);
2173 rrm->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA_FROM_HELPER);
2174 }
2175 }
2176 }
2177 /* Error handling, try to clean up a bit at least */
2178 mst_destroy (stdin_mst);
2179 (void) close (dev.fd_raw);
2180 return 1; /* we never exit 'normally' */
2181}
2182
2183
2184/* end of gnunet-helper-transport-wlan.c */
diff --git a/src/transport/gnunet-service-tng.c b/src/transport/gnunet-service-tng.c
deleted file mode 100644
index 18ec0aa0b..000000000
--- a/src/transport/gnunet-service-tng.c
+++ /dev/null
@@ -1,11152 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2016, 2018, 2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/gnunet-service-tng.c
22 * @brief main for gnunet-service-tng
23 * @author Christian Grothoff
24 *
25 * TODO:
26 * Implement next:
27 * - review retransmission logic, right now there is no smartness there!
28 * => congestion control, etc [PERFORMANCE-BASICS]
29 *
30 * Optimizations-Statistics:
31 * - Track ACK losses based on ACK-counter [ROUTING]
32 * - Need to track total bandwidth per VirtualLink and adjust how frequently
33 * we send FC messages based on bandwidth-delay-product (and relation
34 * to the window size!). See OPTIMIZE-FC-BDP.
35 * - Consider more statistics in #check_connection_quality() [FIXME-CONQ-STATISTICS]
36 * - Adapt available_fc_window_size, using larger values for high-bandwidth
37 * and high-latency links *if* we have the RAM [GOODPUT / utilization / stalls]
38 * - Set last_window_consum_limit promise properly based on
39 * latency and bandwidth of the respective connection [GOODPUT / utilization / stalls]
40 *
41 * Optimizations-DV:
42 * - When forwarding DV learn messages, if a peer is reached that
43 * has a *bidirectional* link to the origin beyond 1st hop,
44 * do NOT forward it to peers _other_ than the origin, as
45 * there is clearly a better path directly from the origin to
46 * whatever else we could reach.
47 * - When we passively learned DV (with unconfirmed freshness), we
48 * right now add the path to our list but with a zero path_valid_until
49 * time and only use it for unconfirmed routes. However, we could consider
50 * triggering an explicit validation mechanism ourselves, specifically routing
51 * a challenge-response message over the path [ROUTING]
52 * = if available, try to confirm unconfirmed DV paths when trying to establish
53 * virtual link for a `struct IncomingRequest`. (i.e. if DVH is
54 * unconfirmed, incoming requests cause us to try to validate a passively
55 * learned path (requires new message type!))
56 *
57 * Optimizations-Fragmentation:
58 * - Fragments send over a reliable channel could do without the
59 * AcknowledgementUUIDP altogether, as they won't be acked! [BANDWIDTH]
60 * (-> have 2nd type of acknowledgment message; low priority, as we
61 * do not have an MTU-limited *reliable* communicator) [FIXME-FRAG-REL-UUID]
62 * - if messages are below MTU, consider adding ACKs and other stuff
63 * to the same transmission to avoid tiny messages (requires planning at
64 * receiver, and additional MST-style demultiplex at receiver!) [PACKET COUNT]
65 *
66 * Optimizations-internals:
67 * - queue_send_msg by API design has to make a copy
68 * of the payload, and route_message on top of that requires a malloc/free.
69 * Change design to approximate "zero" copy better... [CPU]
70 * - could avoid copying body of message into each fragment and keep
71 * fragments as just pointers into the original message and only
72 * fully build fragments just before transmission (optimization, should
73 * reduce CPU and memory use) [CPU, MEMORY]
74 */
75#include "platform.h"
76#include "gnunet_util_lib.h"
77#include "gnunet_statistics_service.h"
78#include "gnunet_transport_monitor_service.h"
79#include "gnunet_peerstore_service.h"
80#include "gnunet_hello_lib.h"
81#include "gnunet_signatures.h"
82#include "transport.h"
83
84/**
85 * Maximum number of FC retransmissions for a runing retransmission task.
86 */
87#define MAX_FC_RETRANSMIT_COUNT 1000
88
89/**
90 * Maximum number of messages we acknowledge together in one
91 * cumulative ACK. Larger values may save a bit of bandwidth.
92 */
93#define MAX_CUMMULATIVE_ACKS 64
94
95/**
96 * What is the 1:n chance that we send a Flow control response when
97 * receiving a flow control message that did not change anything for
98 * us? Basically, this is used in the case where both peers are stuck
99 * on flow control (no window changes), but one might continue sending
100 * flow control messages to the other peer as the first FC message
101 * when things stalled got lost, and then subsequently the other peer
102 * does *usually* not respond as nothing changed. So to ensure that
103 * eventually the FC messages stop, we do send with 1/8th probability
104 * an FC message even if nothing changed. That prevents one peer
105 * being stuck in sending (useless) FC messages "forever".
106 */
107#define FC_NO_CHANGE_REPLY_PROBABILITY 8
108
109/**
110 * What is the size we assume for a read operation in the
111 * absence of an MTU for the purpose of flow control?
112 */
113#define IN_PACKET_SIZE_WITHOUT_MTU 128
114
115/**
116 * Number of slots we keep of historic data for computation of
117 * goodput / message loss ratio.
118 */
119#define GOODPUT_AGING_SLOTS 4
120
121/**
122 * How big is the flow control window size by default;
123 * limits per-neighbour RAM utilization.
124 */
125#define DEFAULT_WINDOW_SIZE (128 * 1024)
126
127/**
128 * For how many incoming connections do we try to create a
129 * virtual link for (at the same time!). This does NOT
130 * limit the number of incoming connections, just the number
131 * for which we are actively trying to find working addresses
132 * in the absence (!) of our own applications wanting the
133 * link to go up.
134 */
135#define MAX_INCOMING_REQUEST 16
136
137/**
138 * Maximum number of peers we select for forwarding DVInit
139 * messages at the same time (excluding initiator).
140 */
141#define MAX_DV_DISCOVERY_SELECTION 16
142
143/**
144 * Window size. How many messages to the same target do we pass
145 * to CORE without a RECV_OK in between? Small values limit
146 * thoughput, large values will increase latency.
147 *
148 * FIXME-OPTIMIZE: find out what good values are experimentally,
149 * maybe set adaptively (i.e. to observed available bandwidth).
150 */
151#define RECV_WINDOW_SIZE 4
152
153/**
154 * Minimum number of hops we should forward DV learn messages
155 * even if they are NOT useful for us in hope of looping
156 * back to the initiator?
157 *
158 * FIXME: allow initiator some control here instead?
159 */
160#define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
161
162/**
163 * Maximum DV distance allowed ever.
164 */
165#define MAX_DV_HOPS_ALLOWED 16
166
167/**
168 * Maximum number of DV learning activities we may
169 * have pending at the same time.
170 */
171#define MAX_DV_LEARN_PENDING 64
172
173/**
174 * Maximum number of DV paths we keep simultaneously to the same target.
175 */
176#define MAX_DV_PATHS_TO_TARGET 3
177
178/**
179 * If a queue delays the next message by more than this number
180 * of seconds we log a warning. Note: this is for testing,
181 * the value chosen here might be too aggressively low!
182 */
183#define DELAY_WARN_THRESHOLD \
184 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
185
186/**
187 * If a DVBox could not be forwarded after this number of
188 * seconds we drop it.
189 */
190#define DV_FORWARD_TIMEOUT \
191 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
192
193/**
194 * Default value for how long we wait for reliability ack.
195 */
196#define DEFAULT_ACK_WAIT_DURATION \
197 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
198
199/**
200 * We only consider queues as "quality" connections when
201 * suppressing the generation of DV initiation messages if
202 * the latency of the queue is below this threshold.
203 */
204#define DV_QUALITY_RTT_THRESHOLD \
205 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
206
207/**
208 * How long do we consider a DV path valid if we see no
209 * further updates on it? Note: the value chosen here might be too low!
210 */
211#define DV_PATH_VALIDITY_TIMEOUT \
212 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
213
214/**
215 * How long do we cache backchannel (struct Backtalker) information
216 * after a backchannel goes inactive?
217 */
218#define BACKCHANNEL_INACTIVITY_TIMEOUT \
219 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
220
221/**
222 * How long before paths expire would we like to (re)discover DV paths? Should
223 * be below #DV_PATH_VALIDITY_TIMEOUT.
224 */
225#define DV_PATH_DISCOVERY_FREQUENCY \
226 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
227
228/**
229 * How long are ephemeral keys valid?
230 */
231#define EPHEMERAL_VALIDITY \
232 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
233
234/**
235 * How long do we keep partially reassembled messages around before giving up?
236 */
237#define REASSEMBLY_EXPIRATION \
238 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
239
240/**
241 * What is the fastest rate at which we send challenges *if* we keep learning
242 * an address (gossip, DHT, etc.)?
243 */
244#define FAST_VALIDATION_CHALLENGE_FREQ \
245 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
246
247/**
248 * What is the slowest rate at which we send challenges?
249 */
250#define MAX_VALIDATION_CHALLENGE_FREQ \
251 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
252
253/**
254 * How long until we forget about historic accumulators and thus
255 * reset the ACK counter? Should exceed the maximum time an
256 * active connection experiences without an ACK.
257 */
258#define ACK_CUMMULATOR_TIMEOUT \
259 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
260
261/**
262 * What is the non-randomized base frequency at which we
263 * would initiate DV learn messages?
264 */
265#define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
266
267/**
268 * How many good connections (confirmed, bi-directional, not DV)
269 * do we need to have to suppress initiating DV learn messages?
270 */
271#define DV_LEARN_QUALITY_THRESHOLD 100
272
273/**
274 * When do we forget an invalid address for sure?
275 */
276#define MAX_ADDRESS_VALID_UNTIL \
277 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
278
279/**
280 * How long do we consider an address valid if we just checked?
281 */
282#define ADDRESS_VALIDATION_LIFETIME \
283 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
284
285/**
286 * What is the maximum frequency at which we do address validation?
287 * A random value between 0 and this value is added when scheduling
288 * the #validation_task (both to ensure we do not validate too often,
289 * and to randomize a bit).
290 */
291#define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
292
293/**
294 * How many network RTTs before an address validation expires should we begin
295 * trying to revalidate? (Note that the RTT used here is the one that we
296 * experienced during the last validation, not necessarily the latest RTT
297 * observed).
298 */
299#define VALIDATION_RTT_BUFFER_FACTOR 3
300
301/**
302 * How many messages can we have pending for a given communicator
303 * process before we start to throttle that communicator?
304 *
305 * Used if a communicator might be CPU-bound and cannot handle the traffic.
306 */
307#define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
308
309/**
310 * How many messages can we have pending for a given queue (queue to
311 * a particular peer via a communicator) process before we start to
312 * throttle that queue?
313 */
314#define QUEUE_LENGTH_LIMIT 32
315
316
317GNUNET_NETWORK_STRUCT_BEGIN
318
319/**
320 * Unique identifier we attach to a message.
321 */
322struct MessageUUIDP
323{
324 /**
325 * Unique value, generated by incrementing the
326 * `message_uuid_ctr` of `struct Neighbour`.
327 */
328 uint64_t uuid GNUNET_PACKED;
329};
330
331
332/**
333 * Unique identifier to map an acknowledgement to a transmission.
334 */
335struct AcknowledgementUUIDP
336{
337 /**
338 * The UUID value.
339 */
340 struct GNUNET_Uuid value;
341};
342
343/**
344 * Outer layer of an encapsulated backchannel message.
345 */
346struct TransportBackchannelEncapsulationMessage
347{
348 /**
349 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
350 */
351 struct GNUNET_MessageHeader header;
352
353 /* Followed by *another* message header which is the message to
354 the communicator */
355
356 /* Followed by a 0-terminated name of the communicator */
357};
358
359
360/**
361 * Body by which a peer confirms that it is using an ephemeral key.
362 */
363struct EphemeralConfirmationPS
364{
365 /**
366 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
367 */
368 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
369
370 /**
371 * How long is this signature over the ephemeral key valid?
372 *
373 * Note that the receiver MUST IGNORE the absolute time, and only interpret
374 * the value as a mononic time and reject "older" values than the last one
375 * observed. This is necessary as we do not want to require synchronized
376 * clocks and may not have a bidirectional communication channel.
377 *
378 * Even with this, there is no real guarantee against replay achieved here,
379 * unless the latest timestamp is persisted. While persistence should be
380 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
381 * communicators must protect against replay attacks when using backchannel
382 * communication!
383 */
384 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
385
386 /**
387 * Target's peer identity.
388 */
389 struct GNUNET_PeerIdentity target;
390
391 /**
392 * Ephemeral key setup by the sender for @e target, used
393 * to encrypt the payload.
394 */
395 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
396};
397
398
399/**
400 * Plaintext of the variable-size payload that is encrypted
401 * within a `struct TransportBackchannelEncapsulationMessage`
402 */
403struct TransportDVBoxPayloadP
404{
405 /**
406 * Sender's peer identity.
407 */
408 struct GNUNET_PeerIdentity sender;
409
410 /**
411 * Signature of the sender over an
412 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
413 */
414 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
415
416 /**
417 * Current monotonic time of the sending transport service. Used to
418 * detect replayed messages. Note that the receiver should remember
419 * a list of the recently seen timestamps and only reject messages
420 * if the timestamp is in the list, or the list is "full" and the
421 * timestamp is smaller than the lowest in the list.
422 *
423 * Like the @e ephemeral_validity, the list of timestamps per peer should be
424 * persisted to guard against replays after restarts.
425 */
426 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
427
428 /* Followed by a `struct GNUNET_MessageHeader` with a message
429 for the target peer */
430};
431
432
433/**
434 * Outer layer of an encapsulated unfragmented application message sent
435 * over an unreliable channel.
436 */
437struct TransportReliabilityBoxMessage
438{
439 /**
440 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
441 */
442 struct GNUNET_MessageHeader header;
443
444 /**
445 * Number of messages still to be sent before a commulative
446 * ACK is requested. Zero if an ACK is requested immediately.
447 * In NBO. Note that the receiver may send the ACK faster
448 * if it believes that is reasonable.
449 */
450 uint32_t ack_countdown GNUNET_PACKED;
451
452 /**
453 * Unique ID of the message used for signalling receipt of
454 * messages sent over possibly unreliable channels. Should
455 * be a random.
456 */
457 struct AcknowledgementUUIDP ack_uuid;
458};
459
460
461/**
462 * Acknowledgement payload.
463 */
464struct TransportCummulativeAckPayloadP
465{
466 /**
467 * How long was the ACK delayed for generating cumulative ACKs?
468 * Used to calculate the correct network RTT by taking the receipt
469 * time of the ack minus the transmission time of the sender minus
470 * this value.
471 */
472 struct GNUNET_TIME_RelativeNBO ack_delay;
473
474 /**
475 * UUID of a message being acknowledged.
476 */
477 struct AcknowledgementUUIDP ack_uuid;
478};
479
480
481/**
482 * Confirmation that the receiver got a
483 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
484 * confirmation may be transmitted over a completely different queue,
485 * so ACKs are identified by a combination of PID of sender and
486 * message UUID, without the queue playing any role!
487 */
488struct TransportReliabilityAckMessage
489{
490 /**
491 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
492 */
493 struct GNUNET_MessageHeader header;
494
495 /**
496 * Counter of ACKs transmitted by the sender to us. Incremented
497 * by one for each ACK, used to detect how many ACKs were lost.
498 */
499 uint32_t ack_counter GNUNET_PACKED;
500
501 /* followed by any number of `struct TransportCummulativeAckPayloadP`
502 messages providing ACKs */
503};
504
505
506/**
507 * Outer layer of an encapsulated fragmented application message.
508 */
509struct TransportFragmentBoxMessage
510{
511 /**
512 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
513 */
514 struct GNUNET_MessageHeader header;
515
516 /**
517 * Offset of this fragment in the overall message.
518 */
519 uint16_t frag_off GNUNET_PACKED;
520
521 /**
522 * Total size of the message that is being fragmented.
523 */
524 uint16_t msg_size GNUNET_PACKED;
525
526 /**
527 * Unique ID of this fragment (and fragment transmission!). Will
528 * change even if a fragment is retransmitted to make each
529 * transmission attempt unique! If a client receives a duplicate
530 * fragment (same @e frag_off for same @a msg_uuid, it must send
531 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
532 */
533 struct AcknowledgementUUIDP ack_uuid;
534
535 /**
536 * Original message ID for of the message that all the fragments
537 * belong to. Must be the same for all fragments.
538 */
539 struct MessageUUIDP msg_uuid;
540};
541
542
543/**
544 * Content signed by the initator during DV learning.
545 *
546 * The signature is required to prevent DDoS attacks. A peer sending out this
547 * message is potentially generating a lot of traffic that will go back to the
548 * initator, as peers receiving this message will try to let the initiator
549 * know that they got the message.
550 *
551 * Without this signature, an attacker could abuse this mechanism for traffic
552 * amplification, sending a lot of traffic to a peer by putting out this type
553 * of message with the victim's peer identity.
554 *
555 * Even with just a signature, traffic amplification would be possible via
556 * replay attacks. The @e monotonic_time limits such replay attacks, as every
557 * potential amplificator will check the @e monotonic_time and only respond
558 * (at most) once per message.
559 */
560struct DvInitPS
561{
562 /**
563 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
564 */
565 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
566
567 /**
568 * Time at the initiator when generating the signature.
569 *
570 * Note that the receiver MUST IGNORE the absolute time, and only interpret
571 * the value as a mononic time and reject "older" values than the last one
572 * observed. This is necessary as we do not want to require synchronized
573 * clocks and may not have a bidirectional communication channel.
574 *
575 * Even with this, there is no real guarantee against replay achieved here,
576 * unless the latest timestamp is persisted. Persistence should be
577 * provided via PEERSTORE if possible.
578 */
579 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
580
581 /**
582 * Challenge value used by the initiator to re-identify the path.
583 */
584 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
585};
586
587
588/**
589 * Content signed by each peer during DV learning.
590 *
591 * This assues the initiator of the DV learning operation that the hop from @e
592 * pred via the signing peer to @e succ actually exists. This makes it
593 * impossible for an adversary to supply the network with bogus routes.
594 *
595 * The @e challenge is included to provide replay protection for the
596 * initiator. This way, the initiator knows that the hop existed after the
597 * original @e challenge was first transmitted, providing a freshness metric.
598 *
599 * Peers other than the initiator that passively learn paths by observing
600 * these messages do NOT benefit from this. Here, an adversary may indeed
601 * replay old messages. Thus, passively learned paths should always be
602 * immediately marked as "potentially stale".
603 */
604struct DvHopPS
605{
606 /**
607 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
608 */
609 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
610
611 /**
612 * Identity of the previous peer on the path.
613 */
614 struct GNUNET_PeerIdentity pred;
615
616 /**
617 * Identity of the next peer on the path.
618 */
619 struct GNUNET_PeerIdentity succ;
620
621 /**
622 * Challenge value used by the initiator to re-identify the path.
623 */
624 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
625};
626
627
628/**
629 * An entry describing a peer on a path in a
630 * `struct TransportDVLearnMessage` message.
631 */
632struct DVPathEntryP
633{
634 /**
635 * Identity of a peer on the path.
636 */
637 struct GNUNET_PeerIdentity hop;
638
639 /**
640 * Signature of this hop over the path, of purpose
641 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
642 */
643 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
644};
645
646
647/**
648 * Internal message used by transport for distance vector learning.
649 * If @e num_hops does not exceed the threshold, peers should append
650 * themselves to the peer list and flood the message (possibly only
651 * to a subset of their neighbours to limit discoverability of the
652 * network topology). To the extend that the @e bidirectional bits
653 * are set, peers may learn the inverse paths even if they did not
654 * initiate.
655 *
656 * Unless received on a bidirectional queue and @e num_hops just
657 * zero, peers that can forward to the initator should always try to
658 * forward to the initiator.
659 */
660struct TransportDVLearnMessage
661{
662 /**
663 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
664 */
665 struct GNUNET_MessageHeader header;
666
667 /**
668 * Number of hops this messages has travelled, in NBO. Zero if
669 * sent by initiator.
670 */
671 uint16_t num_hops GNUNET_PACKED;
672
673 /**
674 * Bitmask of the last 16 hops indicating whether they are confirmed
675 * available (without DV) in both directions or not, in NBO. Used
676 * to possibly instantly learn a path in both directions. Each peer
677 * should shift this value by one to the left, and then set the
678 * lowest bit IF the current sender can be reached from it (without
679 * DV routing).
680 */
681 uint16_t bidirectional GNUNET_PACKED;
682
683 /**
684 * Peers receiving this message and delaying forwarding to other
685 * peers for any reason should increment this value by the non-network
686 * delay created by the peer.
687 */
688 struct GNUNET_TIME_RelativeNBO non_network_delay;
689
690 /**
691 * Time at the initiator when generating the signature.
692 *
693 * Note that the receiver MUST IGNORE the absolute time, and only interpret
694 * the value as a mononic time and reject "older" values than the last one
695 * observed. This is necessary as we do not want to require synchronized
696 * clocks and may not have a bidirectional communication channel.
697 *
698 * Even with this, there is no real guarantee against replay achieved here,
699 * unless the latest timestamp is persisted. Persistence should be
700 * provided via PEERSTORE if possible.
701 */
702 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
703
704 /**
705 * Signature of this hop over the path, of purpose
706 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
707 */
708 struct GNUNET_CRYPTO_EddsaSignature init_sig;
709
710 /**
711 * Identity of the peer that started this learning activity.
712 */
713 struct GNUNET_PeerIdentity initiator;
714
715 /**
716 * Challenge value used by the initiator to re-identify the path.
717 */
718 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
719
720 /* Followed by @e num_hops `struct DVPathEntryP` values,
721 excluding the initiator of the DV trace; the last entry is the
722 current sender; the current peer must not be included. */
723};
724
725
726/**
727 * Outer layer of an encapsulated message send over multiple hops.
728 * The path given only includes the identities of the subsequent
729 * peers, i.e. it will be empty if we are the receiver. Each
730 * forwarding peer should scan the list from the end, and if it can,
731 * forward to the respective peer. The list should then be shortened
732 * by all the entries up to and including that peer. Each hop should
733 * also increment @e total_hops to allow the receiver to get a precise
734 * estimate on the number of hops the message travelled. Senders must
735 * provide a learned path that thus should work, but intermediaries
736 * know of a shortcut, they are allowed to send the message via that
737 * shortcut.
738 *
739 * If a peer finds itself still on the list, it must drop the message.
740 *
741 * The payload of the box can only be decrypted and verified by the
742 * ultimate receiver. Intermediaries do not learn the sender's
743 * identity and the path the message has taken. However, the first
744 * hop does learn the sender as @e total_hops would be zero and thus
745 * the predecessor must be the origin (so this is not really useful
746 * for anonymization).
747 */
748struct TransportDVBoxMessage
749{
750 /**
751 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
752 */
753 struct GNUNET_MessageHeader header;
754
755 /**
756 * Flag if the payload is a control message. In NBO.
757 */
758 unsigned int without_fc;
759
760 /**
761 * Number of total hops this messages travelled. In NBO.
762 * @e origin sets this to zero, to be incremented at
763 * each hop. Peers should limit the @e total_hops value
764 * they accept from other peers.
765 */
766 uint16_t total_hops GNUNET_PACKED;
767
768 /**
769 * Number of hops this messages includes. In NBO. Reduced by one
770 * or more at each hop. Peers should limit the @e num_hops value
771 * they accept from other peers.
772 */
773 uint16_t num_hops GNUNET_PACKED;
774
775 /**
776 * Ephemeral key setup by the sender for target, used to encrypt the
777 * payload. Intermediaries must not change this value.
778 */
779 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
780
781 /**
782 * We use an IV here as the @e ephemeral_key is re-used for
783 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
784 * Intermediaries must not change this value.
785 */
786 struct GNUNET_ShortHashCode iv;
787
788 /**
789 * HMAC over the ciphertext of the encrypted, variable-size body
790 * that follows. Verified via DH of target and @e ephemeral_key.
791 * Intermediaries must not change this value.
792 */
793 struct GNUNET_HashCode hmac;
794
795 /**
796 * Size this msg had initially. This is needed to calculate the hmac at the target.
797 * The header size can not be used for that, because the box size is getting smaller at each hop.
798 */
799 /**
800 * The length of the struct (in bytes, including the length field itself),
801 * in big-endian format.
802 */
803 uint16_t orig_size GNUNET_PACKED;
804
805 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
806 excluding the @e origin and the current peer, the last must be
807 the ultimate target; if @e num_hops is zero, the receiver of this
808 message is the ultimate target. */
809
810 /* Followed by encrypted, variable-size payload, which
811 must begin with a `struct TransportDVBoxPayloadP` */
812
813 /* Followed by the actual message, which itself must not be a
814 a DV_LEARN or DV_BOX message! */
815};
816
817
818/**
819 * Message send to another peer to validate that it can indeed
820 * receive messages at a particular address.
821 */
822struct TransportValidationChallengeMessage
823{
824 /**
825 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
826 */
827 struct GNUNET_MessageHeader header;
828
829 /**
830 * Always zero.
831 */
832 uint32_t reserved GNUNET_PACKED;
833
834 /**
835 * Challenge to be signed by the receiving peer.
836 */
837 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
838
839 /**
840 * Timestamp of the sender, to be copied into the reply to allow
841 * sender to calculate RTT. Must be monotonically increasing!
842 */
843 struct GNUNET_TIME_AbsoluteNBO sender_time;
844};
845
846
847/**
848 * Message signed by a peer to confirm that it can indeed
849 * receive messages at a particular address.
850 */
851struct TransportValidationPS
852{
853 /**
854 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
855 */
856 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
857
858 /**
859 * How long does the sender believe the address on
860 * which the challenge was received to remain valid?
861 */
862 struct GNUNET_TIME_RelativeNBO validity_duration;
863
864 /**
865 * Challenge signed by the receiving peer.
866 */
867 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
868};
869
870
871/**
872 * Message send to a peer to respond to a
873 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
874 */
875struct TransportValidationResponseMessage
876{
877 /**
878 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
879 */
880 struct GNUNET_MessageHeader header;
881
882 /**
883 * Always zero.
884 */
885 uint32_t reserved GNUNET_PACKED;
886
887 /**
888 * The peer's signature matching the
889 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
890 */
891 struct GNUNET_CRYPTO_EddsaSignature signature;
892
893 /**
894 * The challenge that was signed by the receiving peer.
895 */
896 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
897
898 /**
899 * Original timestamp of the sender (was @code{sender_time}),
900 * copied into the reply to allow sender to calculate RTT.
901 */
902 struct GNUNET_TIME_AbsoluteNBO origin_time;
903
904 /**
905 * How long does the sender believe this address to remain
906 * valid?
907 */
908 struct GNUNET_TIME_RelativeNBO validity_duration;
909};
910
911
912/**
913 * Message for Transport-to-Transport Flow control. Specifies the size
914 * of the flow control window, including how much we believe to have
915 * consumed (at transmission time), how much we believe to be allowed
916 * (at transmission time), and how much the other peer is allowed to
917 * send to us, and how much data we already received from the other
918 * peer.
919 */
920struct TransportFlowControlMessage
921{
922 /**
923 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
924 */
925 struct GNUNET_MessageHeader header;
926
927 /**
928 * Sequence number of the flow control message. Incremented by one
929 * for each message. Starts at zero when a virtual link goes up.
930 * Used to detect one-sided connection drops. On wrap-around, the
931 * flow control counters will be reset as if the connection had
932 * dropped.
933 */
934 uint32_t seq GNUNET_PACKED;
935
936 /**
937 * Flow control window size in bytes, in NBO.
938 * The receiver can send this many bytes at most.
939 */
940 uint64_t inbound_window_size GNUNET_PACKED;
941
942 /**
943 * How many bytes has the sender sent that count for flow control at
944 * this time. Used to allow the receiver to estimate the packet
945 * loss rate.
946 */
947 uint64_t outbound_sent GNUNET_PACKED;
948
949 /**
950 * Latest flow control window size we learned from the other peer,
951 * in bytes, in NBO. We are limited to sending at most this many
952 * bytes to the other peer. May help the other peer detect when
953 * flow control messages were lost and should thus be retransmitted.
954 * In particular, if the delta to @e outbound_sent is too small,
955 * this signals that we are stalled.
956 */
957 uint64_t outbound_window_size GNUNET_PACKED;
958
959 /**
960 * Timestamp of the sender. Must be monotonically increasing!
961 * Used to enable receiver to ignore out-of-order packets in
962 * combination with the @e seq. Note that @e seq will go down
963 * (back to zero) whenever either side believes the connection
964 * was dropped, allowing the peers to detect that they need to
965 * reset the counters for the number of bytes sent!
966 */
967 struct GNUNET_TIME_AbsoluteNBO sender_time;
968};
969
970
971GNUNET_NETWORK_STRUCT_END
972
973
974/**
975 * What type of client is the `struct TransportClient` about?
976 */
977enum ClientType
978{
979 /**
980 * We do not know yet (client is fresh).
981 */
982 CT_NONE = 0,
983
984 /**
985 * Is the CORE service, we need to forward traffic to it.
986 */
987 CT_CORE = 1,
988
989 /**
990 * It is a monitor, forward monitor data.
991 */
992 CT_MONITOR = 2,
993
994 /**
995 * It is a communicator, use for communication.
996 */
997 CT_COMMUNICATOR = 3,
998
999 /**
1000 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
1001 */
1002 CT_APPLICATION = 4
1003};
1004
1005
1006/**
1007 * Which transmission options are allowable for transmission?
1008 * Interpreted bit-wise!
1009 */
1010enum RouteMessageOptions
1011{
1012 /**
1013 * Only confirmed, non-DV direct neighbours.
1014 */
1015 RMO_NONE = 0,
1016
1017 /**
1018 * We are allowed to use DV routing for this @a hdr
1019 */
1020 RMO_DV_ALLOWED = 1,
1021
1022 /**
1023 * We are allowed to use unconfirmed queues or DV routes for this message
1024 */
1025 RMO_UNCONFIRMED_ALLOWED = 2,
1026
1027 /**
1028 * Reliable and unreliable, DV and non-DV are all acceptable.
1029 */
1030 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
1031
1032 /**
1033 * If we have multiple choices, it is OK to send this message
1034 * over multiple channels at the same time to improve loss tolerance.
1035 * (We do at most 2 transmissions.)
1036 */
1037 RMO_REDUNDANT = 4
1038};
1039
1040
1041/**
1042 * When did we launch this DV learning activity?
1043 */
1044struct LearnLaunchEntry
1045{
1046 /**
1047 * Kept (also) in a DLL sorted by launch time.
1048 */
1049 struct LearnLaunchEntry *prev;
1050
1051 /**
1052 * Kept (also) in a DLL sorted by launch time.
1053 */
1054 struct LearnLaunchEntry *next;
1055
1056 /**
1057 * Challenge that uniquely identifies this activity.
1058 */
1059 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
1060
1061 /**
1062 * When did we transmit the DV learn message (used to calculate RTT) and
1063 * determine freshness of paths learned via this operation.
1064 */
1065 struct GNUNET_TIME_Absolute launch_time;
1066};
1067
1068
1069/**
1070 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1071 * (or current) transmission performance.
1072 */
1073struct TransmissionHistoryEntry
1074{
1075 /**
1076 * Number of bytes actually sent in the interval.
1077 */
1078 uint64_t bytes_sent;
1079
1080 /**
1081 * Number of bytes received and acknowledged by the other peer in
1082 * the interval.
1083 */
1084 uint64_t bytes_received;
1085};
1086
1087
1088/**
1089 * Performance data for a transmission possibility.
1090 */
1091struct PerformanceData
1092{
1093 /**
1094 * Weighted average for the RTT.
1095 */
1096 struct GNUNET_TIME_Relative aged_rtt;
1097
1098 /**
1099 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1100 * entries.
1101 */
1102 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1103
1104 /**
1105 * What was the last age when we wrote to @e the? Used to clear
1106 * old entries when the age advances.
1107 */
1108 unsigned int last_age;
1109};
1110
1111
1112/**
1113 * Client connected to the transport service.
1114 */
1115struct TransportClient;
1116
1117/**
1118 * A neighbour that at least one communicator is connected to.
1119 */
1120struct Neighbour;
1121
1122/**
1123 * Entry in our #dv_routes table, representing a (set of) distance
1124 * vector routes to a particular peer.
1125 */
1126struct DistanceVector;
1127
1128/**
1129 * A queue is a message queue provided by a communicator
1130 * via which we can reach a particular neighbour.
1131 */
1132struct Queue;
1133
1134/**
1135 * Message awaiting transmission. See detailed comments below.
1136 */
1137struct PendingMessage;
1138
1139/**
1140 * One possible hop towards a DV target.
1141 */
1142struct DistanceVectorHop;
1143
1144/**
1145 * A virtual link is another reachable peer that is known to CORE. It
1146 * can be either a `struct Neighbour` with at least one confirmed
1147 * `struct Queue`, or a `struct DistanceVector` with at least one
1148 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1149 * data that is per neighbour that is not specific to how the
1150 * connectivity is established.
1151 */
1152struct VirtualLink;
1153
1154
1155/**
1156 * Context from #handle_incoming_msg(). Closure for many
1157 * message handlers below.
1158 */
1159struct CommunicatorMessageContext
1160{
1161 /**
1162 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1163 * flow control to unchoke.
1164 */
1165 struct CommunicatorMessageContext *next;
1166
1167 /**
1168 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1169 * flow control to unchoke.
1170 */
1171 struct CommunicatorMessageContext *prev;
1172
1173 /**
1174 * Which communicator provided us with the message.
1175 */
1176 struct TransportClient *tc;
1177
1178 /**
1179 * Additional information for flow control and about the sender.
1180 */
1181 struct GNUNET_TRANSPORT_IncomingMessage im;
1182
1183 /**
1184 * Number of hops the message has travelled (if DV-routed).
1185 * FIXME: make use of this in ACK handling!
1186 */
1187 uint16_t total_hops;
1188};
1189
1190
1191/**
1192 * Closure for #core_env_sent_cb.
1193 */
1194struct CoreSentContext
1195{
1196 /**
1197 * Kept in a DLL to clear @e vl in case @e vl is lost.
1198 */
1199 struct CoreSentContext *next;
1200
1201 /**
1202 * Kept in a DLL to clear @e vl in case @e vl is lost.
1203 */
1204 struct CoreSentContext *prev;
1205
1206 /**
1207 * Virtual link this is about.
1208 */
1209 struct VirtualLink *vl;
1210
1211 /**
1212 * How big was the message.
1213 */
1214 uint16_t size;
1215
1216 /**
1217 * By how much should we increment @e vl's
1218 * incoming_fc_window_size_used once we are done sending to CORE?
1219 * Use to ensure we do not increment twice if there is more than one
1220 * CORE client.
1221 */
1222 uint16_t isize;
1223};
1224
1225
1226/**
1227 * Information we keep for a message that we are reassembling.
1228 */
1229struct ReassemblyContext
1230{
1231 /**
1232 * Original message ID for of the message that all the fragments
1233 * belong to.
1234 */
1235 struct MessageUUIDP msg_uuid;
1236
1237 /**
1238 * Which neighbour is this context for?
1239 */
1240 struct VirtualLink *virtual_link;
1241
1242 /**
1243 * Entry in the reassembly heap (sorted by expiration).
1244 */
1245 struct GNUNET_CONTAINER_HeapNode *hn;
1246
1247 /**
1248 * Bitfield with @e msg_size bits representing the positions
1249 * where we have received fragments. When we receive a fragment,
1250 * we check the bits in @e bitfield before incrementing @e msg_missing.
1251 *
1252 * Allocated after the reassembled message.
1253 */
1254 uint8_t *bitfield;
1255
1256 /**
1257 * At what time will we give up reassembly of this message?
1258 */
1259 struct GNUNET_TIME_Absolute reassembly_timeout;
1260
1261 /**
1262 * Time we received the last fragment. @e avg_ack_delay must be
1263 * incremented by now - @e last_frag multiplied by @e num_acks.
1264 */
1265 struct GNUNET_TIME_Absolute last_frag;
1266
1267 /**
1268 * How big is the message we are reassembling in total?
1269 */
1270 uint16_t msg_size;
1271
1272 /**
1273 * How many bytes of the message are still missing? Defragmentation
1274 * is complete when @e msg_missing == 0.
1275 */
1276 uint16_t msg_missing;
1277
1278 /* Followed by @e msg_size bytes of the (partially) defragmented original
1279 * message */
1280
1281 /* Followed by @e bitfield data */
1282};
1283
1284
1285/**
1286 * A virtual link is another reachable peer that is known to CORE. It
1287 * can be either a `struct Neighbour` with at least one confirmed
1288 * `struct Queue`, or a `struct DistanceVector` with at least one
1289 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1290 * data that is per neighbour that is not specific to how the
1291 * connectivity is established.
1292 */
1293struct VirtualLink
1294{
1295 /**
1296 * Identity of the peer at the other end of the link.
1297 */
1298 struct GNUNET_PeerIdentity target;
1299
1300 /**
1301 * Map with `struct ReassemblyContext` structs for fragments under
1302 * reassembly. May be NULL if we currently have no fragments from
1303 * this @e pid (lazy initialization).
1304 */
1305 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1306
1307 /**
1308 * Heap with `struct ReassemblyContext` structs for fragments under
1309 * reassembly. May be NULL if we currently have no fragments from
1310 * this @e pid (lazy initialization).
1311 */
1312 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1313
1314 /**
1315 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1316 */
1317 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1318
1319 /**
1320 * Communicators blocked for receiving on @e target as we are waiting
1321 * on the @e core_recv_window to increase.
1322 */
1323 struct CommunicatorMessageContext *cmc_head;
1324
1325 /**
1326 * Communicators blocked for receiving on @e target as we are waiting
1327 * on the @e core_recv_window to increase.
1328 */
1329 struct CommunicatorMessageContext *cmc_tail;
1330
1331 /**
1332 * Head of list of messages pending for this VL.
1333 */
1334 struct PendingMessage *pending_msg_head;
1335
1336 /**
1337 * Tail of list of messages pending for this VL.
1338 */
1339 struct PendingMessage *pending_msg_tail;
1340
1341 /**
1342 * Kept in a DLL to clear @e vl in case @e vl is lost.
1343 */
1344 struct CoreSentContext *csc_tail;
1345
1346 /**
1347 * Kept in a DLL to clear @e vl in case @e vl is lost.
1348 */
1349 struct CoreSentContext *csc_head;
1350
1351 /**
1352 * Task scheduled to possibly notfiy core that this peer is no
1353 * longer counting as confirmed. Runs the #core_visibility_check(),
1354 * which checks that some DV-path or a queue exists that is still
1355 * considered confirmed.
1356 */
1357 struct GNUNET_SCHEDULER_Task *visibility_task;
1358
1359 /**
1360 * Task scheduled to periodically retransmit FC messages (in
1361 * case one got lost).
1362 */
1363 struct GNUNET_SCHEDULER_Task *fc_retransmit_task;
1364
1365 /**
1366 * Number of FC retransmissions for this running task.
1367 */
1368 unsigned int fc_retransmit_count;
1369
1370 /**
1371 * Is this VirtualLink confirmed.
1372 * A unconfirmed VirtualLink might exist, if we got a FC from that target.
1373 */
1374 unsigned int confirmed;
1375
1376 /**
1377 * Neighbour used by this virtual link, NULL if @e dv is used.
1378 */
1379 struct Neighbour *n;
1380
1381 /**
1382 * Distance vector used by this virtual link, NULL if @e n is used.
1383 */
1384 struct DistanceVector *dv;
1385
1386 /**
1387 * Sender timestamp of @e n_challenge, used to generate out-of-order
1388 * challenges (as sender's timestamps must be monotonically
1389 * increasing). FIXME: where do we need this?
1390 */
1391 struct GNUNET_TIME_Absolute n_challenge_time;
1392
1393 /**
1394 * When did we last send a
1395 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message?
1396 * Used to determine whether it is time to re-transmit the message.
1397 */
1398 struct GNUNET_TIME_Absolute last_fc_transmission;
1399
1400 /**
1401 * Sender timestamp of the last
1402 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1403 * received. Note that we do not persist this monotonic time as we
1404 * do not really have to worry about ancient flow control window
1405 * sizes after restarts.
1406 */
1407 struct GNUNET_TIME_Absolute last_fc_timestamp;
1408
1409 /**
1410 * Expected RTT from the last FC transmission. (Zero if the last
1411 * attempt failed, but could theoretically be zero even on success.)
1412 */
1413 struct GNUNET_TIME_Relative last_fc_rtt;
1414
1415 /**
1416 * Used to generate unique UUIDs for messages that are being
1417 * fragmented.
1418 */
1419 uint64_t message_uuid_ctr;
1420
1421 /**
1422 * Memory allocated for this virtual link. Expresses how much RAM
1423 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1424 * Can be adapted to dedicate more RAM to links that need it, while
1425 * sticking to some overall RAM limit. For now, set to
1426 * #DEFAULT_WINDOW_SIZE.
1427 */
1428 uint64_t available_fc_window_size;
1429
1430 /**
1431 * Memory actually used to buffer packets on this virtual link.
1432 * Expresses how much RAM we are currently using for virtual link.
1433 * Note that once CORE is done with a packet, we decrement the value
1434 * here.
1435 */
1436 uint64_t incoming_fc_window_size_ram;
1437
1438 /**
1439 * Last flow control window size we provided to the other peer, in
1440 * bytes. We are allowing the other peer to send this
1441 * many bytes.
1442 */
1443 uint64_t incoming_fc_window_size;
1444
1445 /**
1446 * How much of the window did the other peer successfully use (and
1447 * we already passed it on to CORE)? Must be below @e
1448 * incoming_fc_window_size. We should effectively signal the
1449 * other peer that the window is this much bigger at the next
1450 * opportunity / challenge.
1451 */
1452 uint64_t incoming_fc_window_size_used;
1453
1454 /**
1455 * What is our current estimate on the message loss rate for the sender?
1456 * Based on the difference between how much the sender sent according
1457 * to the last #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message
1458 * (@e outbound_sent field) and how much we actually received at that
1459 * time (@e incoming_fc_window_size_used). This delta is then
1460 * added onto the @e incoming_fc_window_size when determining the
1461 * @e outbound_window_size we send to the other peer. Initially zero.
1462 * May be negative if we (due to out-of-order delivery) actually received
1463 * more than the sender claims to have sent in its last FC message.
1464 */
1465 int64_t incoming_fc_window_size_loss;
1466
1467 /**
1468 * Our current flow control window size in bytes. We
1469 * are allowed to transmit this many bytes to @a n.
1470 */
1471 uint64_t outbound_fc_window_size;
1472
1473 /**
1474 * How much of our current flow control window size have we
1475 * used (in bytes). Must be below
1476 * @e outbound_fc_window_size.
1477 */
1478 uint64_t outbound_fc_window_size_used;
1479
1480 /**
1481 * What is the most recent FC window the other peer sent us
1482 * in `outbound_window_size`? This is basically the window
1483 * size value the other peer has definitively received from
1484 * us. If it matches @e incoming_fc_window_size, we should
1485 * not send a FC message to increase the FC window. However,
1486 * we may still send an FC message to notify the other peer
1487 * that we received the other peer's FC message.
1488 */
1489 uint64_t last_outbound_window_size_received;
1490
1491 /**
1492 * Generator for the sequence numbers of
1493 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1494 */
1495 uint32_t fc_seq_gen;
1496
1497 /**
1498 * Last sequence number of a
1499 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1500 * received.
1501 */
1502 uint32_t last_fc_seq;
1503
1504 /**
1505 * How many more messages can we send to CORE before we exhaust
1506 * the receive window of CORE for this peer? If this hits zero,
1507 * we must tell communicators to stop providing us more messages
1508 * for this peer. In fact, the window can go negative as we
1509 * have multiple communicators, so per communicator we can go
1510 * down by one into the negative range. Furthermore, we count
1511 * delivery per CORE client, so if we had multiple cores, that
1512 * might also cause a negative window size here (as one message
1513 * would decrement the window by one per CORE client).
1514 */
1515 int core_recv_window;
1516};
1517
1518
1519/**
1520 * Data structure kept when we are waiting for an acknowledgement.
1521 */
1522struct PendingAcknowledgement
1523{
1524 /**
1525 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1526 * is kept in relation to its pending message.
1527 */
1528 struct PendingAcknowledgement *next_pm;
1529
1530 /**
1531 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1532 * is kept in relation to its pending message.
1533 */
1534 struct PendingAcknowledgement *prev_pm;
1535
1536 /**
1537 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1538 * is kept in relation to the queue that was used to transmit the
1539 * @a pm.
1540 */
1541 struct PendingAcknowledgement *next_queue;
1542
1543 /**
1544 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1545 * is kept in relation to the queue that was used to transmit the
1546 * @a pm.
1547 */
1548 struct PendingAcknowledgement *prev_queue;
1549
1550 /**
1551 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1552 * is kept in relation to the DVH that was used to transmit the
1553 * @a pm.
1554 */
1555 struct PendingAcknowledgement *next_dvh;
1556
1557 /**
1558 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1559 * is kept in relation to the DVH that was used to transmit the
1560 * @a pm.
1561 */
1562 struct PendingAcknowledgement *prev_dvh;
1563
1564 /**
1565 * Pointers for the DLL of all pending acknowledgements.
1566 * This list is sorted by @e transmission time. If the list gets too
1567 * long, the oldest entries are discarded.
1568 */
1569 struct PendingAcknowledgement *next_pa;
1570
1571 /**
1572 * Pointers for the DLL of all pending acknowledgements.
1573 * This list is sorted by @e transmission time. If the list gets too
1574 * long, the oldest entries are discarded.
1575 */
1576 struct PendingAcknowledgement *prev_pa;
1577
1578 /**
1579 * Unique identifier for this transmission operation.
1580 */
1581 struct AcknowledgementUUIDP ack_uuid;
1582
1583 /**
1584 * Message that was transmitted, may be NULL if the message was ACKed
1585 * via another channel.
1586 */
1587 struct PendingMessage *pm;
1588
1589 /**
1590 * Distance vector path chosen for this transmission, NULL if transmission
1591 * was to a direct neighbour OR if the path was forgotten in the meantime.
1592 */
1593 struct DistanceVectorHop *dvh;
1594
1595 /**
1596 * Queue used for transmission, NULL if the queue has been destroyed
1597 * (which may happen before we get an acknowledgement).
1598 */
1599 struct Queue *queue;
1600
1601 /**
1602 * Time of the transmission, for RTT calculation.
1603 */
1604 struct GNUNET_TIME_Absolute transmission_time;
1605
1606 /**
1607 * Number of bytes of the original message (to calculate bandwidth).
1608 */
1609 uint16_t message_size;
1610};
1611
1612
1613/**
1614 * One possible hop towards a DV target.
1615 */
1616struct DistanceVectorHop
1617{
1618 /**
1619 * Kept in a MDLL, sorted by @e timeout.
1620 */
1621 struct DistanceVectorHop *next_dv;
1622
1623 /**
1624 * Kept in a MDLL, sorted by @e timeout.
1625 */
1626 struct DistanceVectorHop *prev_dv;
1627
1628 /**
1629 * Kept in a MDLL.
1630 */
1631 struct DistanceVectorHop *next_neighbour;
1632
1633 /**
1634 * Kept in a MDLL.
1635 */
1636 struct DistanceVectorHop *prev_neighbour;
1637
1638 /**
1639 * Head of DLL of PAs that used our @a path.
1640 */
1641 struct PendingAcknowledgement *pa_head;
1642
1643 /**
1644 * Tail of DLL of PAs that used our @a path.
1645 */
1646 struct PendingAcknowledgement *pa_tail;
1647
1648 /**
1649 * What would be the next hop to @e target?
1650 */
1651 struct Neighbour *next_hop;
1652
1653 /**
1654 * Distance vector entry this hop belongs with.
1655 */
1656 struct DistanceVector *dv;
1657
1658 /**
1659 * Array of @e distance hops to the target, excluding @e next_hop.
1660 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1661 * at the end of this struct. Excludes the target itself!
1662 */
1663 const struct GNUNET_PeerIdentity *path;
1664
1665 /**
1666 * At what time do we forget about this path unless we see it again
1667 * while learning?
1668 */
1669 struct GNUNET_TIME_Absolute timeout;
1670
1671 /**
1672 * For how long is the validation of this path considered
1673 * valid?
1674 * Set to ZERO if the path is learned by snooping on DV learn messages
1675 * initiated by other peers, and to the time at which we generated the
1676 * challenge for DV learn operations this peer initiated.
1677 */
1678 struct GNUNET_TIME_Absolute path_valid_until;
1679
1680 /**
1681 * Performance data for this transmission possibility.
1682 */
1683 struct PerformanceData pd;
1684
1685 /**
1686 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1687 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1688 * to `target`).
1689 */
1690 unsigned int distance;
1691};
1692
1693
1694/**
1695 * Entry in our #dv_routes table, representing a (set of) distance
1696 * vector routes to a particular peer.
1697 */
1698struct DistanceVector
1699{
1700 /**
1701 * To which peer is this a route?
1702 */
1703 struct GNUNET_PeerIdentity target;
1704
1705 /**
1706 * Known paths to @e target.
1707 */
1708 struct DistanceVectorHop *dv_head;
1709
1710 /**
1711 * Known paths to @e target.
1712 */
1713 struct DistanceVectorHop *dv_tail;
1714
1715 /**
1716 * Task scheduled to purge expired paths from @e dv_head MDLL.
1717 */
1718 struct GNUNET_SCHEDULER_Task *timeout_task;
1719
1720 /**
1721 * Do we have a confirmed working queue and are thus visible to
1722 * CORE? If so, this is the virtual link, otherwise NULL.
1723 */
1724 struct VirtualLink *vl;
1725
1726 /**
1727 * Signature affirming @e ephemeral_key of type
1728 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1729 */
1730 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1731
1732 /**
1733 * How long is @e sender_sig valid
1734 */
1735 struct GNUNET_TIME_Absolute ephemeral_validity;
1736
1737 /**
1738 * What time was @e sender_sig created
1739 */
1740 struct GNUNET_TIME_Absolute monotime;
1741
1742 /**
1743 * Our ephemeral key.
1744 */
1745 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1746
1747 /**
1748 * Our private ephemeral key.
1749 */
1750 struct GNUNET_CRYPTO_EcdhePrivateKey private_key;
1751};
1752
1753
1754/**
1755 * Entry identifying transmission in one of our `struct
1756 * Queue` which still awaits an ACK. This is used to
1757 * ensure we do not overwhelm a communicator and limit the number of
1758 * messages outstanding per communicator (say in case communicator is
1759 * CPU bound) and per queue (in case bandwidth allocation exceeds
1760 * what the communicator can actually provide towards a particular
1761 * peer/target).
1762 */
1763struct QueueEntry
1764{
1765 /**
1766 * Kept as a DLL.
1767 */
1768 struct QueueEntry *next;
1769
1770 /**
1771 * Kept as a DLL.
1772 */
1773 struct QueueEntry *prev;
1774
1775 /**
1776 * Queue this entry is queued with.
1777 */
1778 struct Queue *queue;
1779
1780 /**
1781 * Pending message this entry is for, or NULL for none.
1782 */
1783 struct PendingMessage *pm;
1784
1785 /**
1786 * Message ID used for this message with the queue used for transmission.
1787 */
1788 uint64_t mid;
1789};
1790
1791
1792/**
1793 * A queue is a message queue provided by a communicator
1794 * via which we can reach a particular neighbour.
1795 */
1796struct Queue
1797{
1798 /**
1799 * Kept in a MDLL.
1800 */
1801 struct Queue *next_neighbour;
1802
1803 /**
1804 * Kept in a MDLL.
1805 */
1806 struct Queue *prev_neighbour;
1807
1808 /**
1809 * Kept in a MDLL.
1810 */
1811 struct Queue *prev_client;
1812
1813 /**
1814 * Kept in a MDLL.
1815 */
1816 struct Queue *next_client;
1817
1818 /**
1819 * Head of DLL of PAs that used this queue.
1820 */
1821 struct PendingAcknowledgement *pa_head;
1822
1823 /**
1824 * Tail of DLL of PAs that used this queue.
1825 */
1826 struct PendingAcknowledgement *pa_tail;
1827
1828 /**
1829 * Head of DLL of unacked transmission requests.
1830 */
1831 struct QueueEntry *queue_head;
1832
1833 /**
1834 * End of DLL of unacked transmission requests.
1835 */
1836 struct QueueEntry *queue_tail;
1837
1838 /**
1839 * Which neighbour is this queue for?
1840 */
1841 struct Neighbour *neighbour;
1842
1843 /**
1844 * Which communicator offers this queue?
1845 */
1846 struct TransportClient *tc;
1847
1848 /**
1849 * Address served by the queue.
1850 */
1851 const char *address;
1852
1853 /**
1854 * Is this queue of unlimited length.
1855 */
1856 unsigned int unlimited_length;
1857
1858 /**
1859 * Task scheduled for the time when this queue can (likely) transmit the
1860 * next message.
1861 */
1862 struct GNUNET_SCHEDULER_Task *transmit_task;
1863
1864 /**
1865 * How long do *we* consider this @e address to be valid? In the past or
1866 * zero if we have not yet validated it. Can be updated based on
1867 * challenge-response validations (via address validation logic), or when we
1868 * receive ACKs that we can definitively map to transmissions via this
1869 * queue.
1870 */
1871 struct GNUNET_TIME_Absolute validated_until;
1872
1873 /**
1874 * Performance data for this queue.
1875 */
1876 struct PerformanceData pd;
1877
1878 /**
1879 * Message ID generator for transmissions on this queue to the
1880 * communicator.
1881 */
1882 uint64_t mid_gen;
1883
1884 /**
1885 * Unique identifier of this queue with the communicator.
1886 */
1887 uint32_t qid;
1888
1889 /**
1890 * Maximum transmission unit supported by this queue.
1891 */
1892 uint32_t mtu;
1893
1894 /**
1895 * Messages pending.
1896 */
1897 uint32_t num_msg_pending;
1898
1899 /**
1900 * Bytes pending.
1901 */
1902 uint32_t num_bytes_pending;
1903
1904 /**
1905 * Length of the DLL starting at @e queue_head.
1906 */
1907 unsigned int queue_length;
1908
1909 /**
1910 * Capacity of the queue.
1911 */
1912 uint64_t q_capacity;
1913
1914 /**
1915 * Queue priority
1916 */
1917 uint32_t priority;
1918
1919 /**
1920 * Network type offered by this queue.
1921 */
1922 enum GNUNET_NetworkType nt;
1923
1924 /**
1925 * Connection status for this queue.
1926 */
1927 enum GNUNET_TRANSPORT_ConnectionStatus cs;
1928
1929 /**
1930 * Set to #GNUNET_YES if this queue is idle waiting for some
1931 * virtual link to give it a pending message.
1932 */
1933 int idle;
1934};
1935
1936
1937
1938
1939
1940/**
1941 * A neighbour that at least one communicator is connected to.
1942 */
1943struct Neighbour
1944{
1945 /**
1946 * Which peer is this about?
1947 */
1948 struct GNUNET_PeerIdentity pid;
1949
1950 /**
1951 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
1952 * purged if this neighbour goes down.
1953 */
1954 struct DistanceVectorHop *dv_head;
1955
1956 /**
1957 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
1958 * purged if this neighbour goes down.
1959 */
1960 struct DistanceVectorHop *dv_tail;
1961
1962 /**
1963 * Head of DLL of queues to this peer.
1964 */
1965 struct Queue *queue_head;
1966
1967 /**
1968 * Tail of DLL of queues to this peer.
1969 */
1970 struct Queue *queue_tail;
1971
1972 /**
1973 * Handle for an operation to fetch @e last_dv_learn_monotime information from
1974 * the PEERSTORE, or NULL.
1975 */
1976 struct GNUNET_PEERSTORE_IterateContext *get;
1977
1978 /**
1979 * Handle to a PEERSTORE store operation to store this @e pid's @e
1980 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
1981 */
1982 struct GNUNET_PEERSTORE_StoreContext *sc;
1983
1984 /**
1985 * Do we have a confirmed working queue and are thus visible to
1986 * CORE? If so, this is the virtual link, otherwise NULL.
1987 */
1988 struct VirtualLink *vl;
1989
1990 /**
1991 * Latest DVLearn monotonic time seen from this peer. Initialized only
1992 * if @e dl_monotime_available is #GNUNET_YES.
1993 */
1994 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
1995
1996 /**
1997 * Do we have the latest value for @e last_dv_learn_monotime from
1998 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
1999 */
2000 int dv_monotime_available;
2001};
2002
2003
2004/**
2005 * Another peer attempted to talk to us, we should try to establish
2006 * a connection in the other direction.
2007 */
2008struct IncomingRequest
2009{
2010 /**
2011 * Kept in a DLL.
2012 */
2013 struct IncomingRequest *next;
2014
2015 /**
2016 * Kept in a DLL.
2017 */
2018 struct IncomingRequest *prev;
2019
2020 /**
2021 * Handle for watching the peerstore for HELLOs for this peer.
2022 */
2023 struct GNUNET_PEERSTORE_WatchContext *wc;
2024
2025 /**
2026 * Which peer is this about?
2027 */
2028 struct GNUNET_PeerIdentity pid;
2029};
2030
2031
2032/**
2033 * A peer that an application (client) would like us to talk to directly.
2034 */
2035struct PeerRequest
2036{
2037 /**
2038 * Which peer is this about?
2039 */
2040 struct GNUNET_PeerIdentity pid;
2041
2042 /**
2043 * Client responsible for the request.
2044 */
2045 struct TransportClient *tc;
2046
2047 /**
2048 * Handle for watching the peerstore for HELLOs for this peer.
2049 */
2050 struct GNUNET_PEERSTORE_WatchContext *wc;
2051
2052 /**
2053 * What kind of performance preference does this @e tc have?
2054 *
2055 * TODO: use this!
2056 */
2057 enum GNUNET_MQ_PriorityPreferences pk;
2058
2059 /**
2060 * How much bandwidth would this @e tc like to see?
2061 */
2062 struct GNUNET_BANDWIDTH_Value32NBO bw;
2063};
2064
2065
2066/**
2067 * Types of different pending messages.
2068 */
2069enum PendingMessageType
2070{
2071 /**
2072 * Ordinary message received from the CORE service.
2073 */
2074 PMT_CORE = 0,
2075
2076 /**
2077 * Fragment box.
2078 */
2079 PMT_FRAGMENT_BOX = 1,
2080
2081 /**
2082 * Reliability box.
2083 */
2084 PMT_RELIABILITY_BOX = 2,
2085
2086 /**
2087 * Pending message created during #forward_dv_box().
2088 */
2089 PMT_DV_BOX = 3
2090};
2091
2092
2093/**
2094 * Transmission request that is awaiting delivery. The original
2095 * transmission requests from CORE may be too big for some queues.
2096 * In this case, a *tree* of fragments is created. At each
2097 * level of the tree, fragments are kept in a DLL ordered by which
2098 * fragment should be sent next (at the head). The tree is searched
2099 * top-down, with the original message at the root.
2100 *
2101 * To select a node for transmission, first it is checked if the
2102 * current node's message fits with the MTU. If it does not, we
2103 * either calculate the next fragment (based on @e frag_off) from the
2104 * current node, or, if all fragments have already been created,
2105 * descend to the @e head_frag. Even though the node was already
2106 * fragmented, the fragment may be too big if the fragment was
2107 * generated for a queue with a larger MTU. In this case, the node
2108 * may be fragmented again, thus creating a tree.
2109 *
2110 * When acknowledgements for fragments are received, the tree
2111 * must be pruned, removing those parts that were already
2112 * acknowledged. When fragments are sent over a reliable
2113 * channel, they can be immediately removed.
2114 *
2115 * If a message is ever fragmented, then the original "full" message
2116 * is never again transmitted (even if it fits below the MTU), and
2117 * only (remaining) fragments are sent.
2118 */
2119struct PendingMessage
2120{
2121 /**
2122 * Kept in a MDLL of messages for this @a vl.
2123 */
2124 struct PendingMessage *next_vl;
2125
2126 /**
2127 * Kept in a MDLL of messages for this @a vl.
2128 */
2129 struct PendingMessage *prev_vl;
2130
2131 /**
2132 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2133 */
2134 struct PendingMessage *next_client;
2135
2136 /**
2137 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2138 */
2139 struct PendingMessage *prev_client;
2140
2141 /**
2142 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2143 * #PMT_FRAGMENT_BOx)
2144 */
2145 struct PendingMessage *next_frag;
2146
2147 /**
2148 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2149 * #PMT_FRAGMENT_BOX)
2150 */
2151 struct PendingMessage *prev_frag;
2152
2153 /**
2154 * Head of DLL of PAs for this pending message.
2155 */
2156 struct PendingAcknowledgement *pa_head;
2157
2158 /**
2159 * Tail of DLL of PAs for this pending message.
2160 */
2161 struct PendingAcknowledgement *pa_tail;
2162
2163 /**
2164 * This message, reliability *or* DV-boxed. Only possibly available
2165 * if @e pmt is #PMT_CORE.
2166 */
2167 struct PendingMessage *bpm;
2168
2169 /**
2170 * Target of the request (always the ultimate destination!).
2171 */
2172 struct VirtualLink *vl;
2173
2174 /**
2175 * Set to non-NULL value if this message is currently being given to a
2176 * communicator and we are awaiting that communicator's acknowledgement.
2177 * Note that we must not retransmit a pending message while we're still
2178 * in the process of giving it to a communicator. If a pending message
2179 * is free'd while this entry is non-NULL, the @e qe reference to us
2180 * should simply be set to NULL.
2181 */
2182 struct QueueEntry *qe;
2183
2184 /**
2185 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
2186 */
2187 struct TransportClient *client;
2188
2189 /**
2190 * Head of a MDLL of fragments created for this core message.
2191 */
2192 struct PendingMessage *head_frag;
2193
2194 /**
2195 * Tail of a MDLL of fragments created for this core message.
2196 */
2197 struct PendingMessage *tail_frag;
2198
2199 /**
2200 * Our parent in the fragmentation tree.
2201 */
2202 struct PendingMessage *frag_parent;
2203
2204 /**
2205 * At what time should we give up on the transmission (and no longer retry)?
2206 */
2207 struct GNUNET_TIME_Absolute timeout;
2208
2209 /**
2210 * What is the earliest time for us to retry transmission of this message?
2211 */
2212 struct GNUNET_TIME_Absolute next_attempt;
2213
2214 /**
2215 * UUID to use for this message (used for reassembly of fragments, only
2216 * initialized if @e msg_uuid_set is #GNUNET_YES).
2217 */
2218 struct MessageUUIDP msg_uuid;
2219
2220 /**
2221 * UUID we use to identify this message in our logs.
2222 * Generated by incrementing the "logging_uuid_gen".
2223 */
2224 unsigned long long logging_uuid;
2225
2226 /**
2227 * Type of the pending message.
2228 */
2229 enum PendingMessageType pmt;
2230
2231 /**
2232 * Preferences for this message.
2233 * TODO: actually use this!
2234 */
2235 enum GNUNET_MQ_PriorityPreferences prefs;
2236
2237 /**
2238 * If pmt is of type PMT_DV_BOX we store the used path here.
2239 */
2240 struct DistanceVectorHop *used_dvh;
2241
2242 /**
2243 * Size of the original message.
2244 */
2245 uint16_t bytes_msg;
2246
2247 /**
2248 * Offset at which we should generate the next fragment.
2249 */
2250 uint16_t frag_off;
2251
2252 /**
2253 * #GNUNET_YES once @e msg_uuid was initialized
2254 */
2255 int16_t msg_uuid_set;
2256
2257 /* Followed by @e bytes_msg to transmit */
2258};
2259
2260
2261/**
2262 * Acknowledgement payload.
2263 */
2264struct TransportCummulativeAckPayload
2265{
2266 /**
2267 * When did we receive the message we are ACKing? Used to calculate
2268 * the delay we introduced by cummulating ACKs.
2269 */
2270 struct GNUNET_TIME_Absolute receive_time;
2271
2272 /**
2273 * UUID of a message being acknowledged.
2274 */
2275 struct AcknowledgementUUIDP ack_uuid;
2276};
2277
2278
2279/**
2280 * Data structure in which we track acknowledgements still to
2281 * be sent to the
2282 */
2283struct AcknowledgementCummulator
2284{
2285 /**
2286 * Target peer for which we are accumulating ACKs here.
2287 */
2288 struct GNUNET_PeerIdentity target;
2289
2290 /**
2291 * ACK data being accumulated. Only @e num_acks slots are valid.
2292 */
2293 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2294
2295 /**
2296 * Task scheduled either to transmit the cumulative ACK message,
2297 * or to clean up this data structure after extended periods of
2298 * inactivity (if @e num_acks is zero).
2299 */
2300 struct GNUNET_SCHEDULER_Task *task;
2301
2302 /**
2303 * When is @e task run (only used if @e num_acks is non-zero)?
2304 */
2305 struct GNUNET_TIME_Absolute min_transmission_time;
2306
2307 /**
2308 * Counter to produce the `ack_counter` in the `struct
2309 * TransportReliabilityAckMessage`. Allows the receiver to detect
2310 * lost ACK messages. Incremented by @e num_acks upon transmission.
2311 */
2312 uint32_t ack_counter;
2313
2314 /**
2315 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2316 */
2317 unsigned int num_acks;
2318};
2319
2320
2321/**
2322 * One of the addresses of this peer.
2323 */
2324struct AddressListEntry
2325{
2326 /**
2327 * Kept in a DLL.
2328 */
2329 struct AddressListEntry *next;
2330
2331 /**
2332 * Kept in a DLL.
2333 */
2334 struct AddressListEntry *prev;
2335
2336 /**
2337 * Which communicator provides this address?
2338 */
2339 struct TransportClient *tc;
2340
2341 /**
2342 * The actual address.
2343 */
2344 const char *address;
2345
2346 /**
2347 * Current context for storing this address in the peerstore.
2348 */
2349 struct GNUNET_PEERSTORE_StoreContext *sc;
2350
2351 /**
2352 * Task to periodically do @e st operation.
2353 */
2354 struct GNUNET_SCHEDULER_Task *st;
2355
2356 /**
2357 * What is a typical lifetime the communicator expects this
2358 * address to have? (Always from now.)
2359 */
2360 struct GNUNET_TIME_Relative expiration;
2361
2362 /**
2363 * Address identifier used by the communicator.
2364 */
2365 uint32_t aid;
2366
2367 /**
2368 * Network type offered by this address.
2369 */
2370 enum GNUNET_NetworkType nt;
2371};
2372
2373
2374/**
2375 * Client connected to the transport service.
2376 */
2377struct TransportClient
2378{
2379 /**
2380 * Kept in a DLL.
2381 */
2382 struct TransportClient *next;
2383
2384 /**
2385 * Kept in a DLL.
2386 */
2387 struct TransportClient *prev;
2388
2389 /**
2390 * Handle to the client.
2391 */
2392 struct GNUNET_SERVICE_Client *client;
2393
2394 /**
2395 * Message queue to the client.
2396 */
2397 struct GNUNET_MQ_Handle *mq;
2398
2399 /**
2400 * What type of client is this?
2401 */
2402 enum ClientType type;
2403
2404 union
2405 {
2406 /**
2407 * Information for @e type #CT_CORE.
2408 */
2409 struct
2410 {
2411 /**
2412 * Head of list of messages pending for this client, sorted by
2413 * transmission time ("next_attempt" + possibly internal prioritization).
2414 */
2415 struct PendingMessage *pending_msg_head;
2416
2417 /**
2418 * Tail of list of messages pending for this client.
2419 */
2420 struct PendingMessage *pending_msg_tail;
2421 } core;
2422
2423 /**
2424 * Information for @e type #CT_MONITOR.
2425 */
2426 struct
2427 {
2428 /**
2429 * Peer identity to monitor the addresses of.
2430 * Zero to monitor all neighbours. Valid if
2431 * @e type is #CT_MONITOR.
2432 */
2433 struct GNUNET_PeerIdentity peer;
2434
2435 /**
2436 * Is this a one-shot monitor?
2437 */
2438 int one_shot;
2439 } monitor;
2440
2441
2442 /**
2443 * Information for @e type #CT_COMMUNICATOR.
2444 */
2445 struct
2446 {
2447 /**
2448 * If @e type is #CT_COMMUNICATOR, this communicator
2449 * supports communicating using these addresses.
2450 */
2451 char *address_prefix;
2452
2453 /**
2454 * Head of DLL of queues offered by this communicator.
2455 */
2456 struct Queue *queue_head;
2457
2458 /**
2459 * Tail of DLL of queues offered by this communicator.
2460 */
2461 struct Queue *queue_tail;
2462
2463 /**
2464 * Head of list of the addresses of this peer offered by this
2465 * communicator.
2466 */
2467 struct AddressListEntry *addr_head;
2468
2469 /**
2470 * Tail of list of the addresses of this peer offered by this
2471 * communicator.
2472 */
2473 struct AddressListEntry *addr_tail;
2474
2475 /**
2476 * Number of queue entries in all queues to this communicator. Used
2477 * throttle sending to a communicator if we see that the communicator
2478 * is globally unable to keep up.
2479 */
2480 unsigned int total_queue_length;
2481
2482 /**
2483 * Characteristics of this communicator.
2484 */
2485 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2486 } communicator;
2487
2488 /**
2489 * Information for @e type #CT_APPLICATION
2490 */
2491 struct
2492 {
2493 /**
2494 * Map of requests for peers the given client application would like to
2495 * see connections for. Maps from PIDs to `struct PeerRequest`.
2496 */
2497 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2498 } application;
2499 } details;
2500};
2501
2502
2503/**
2504 * State we keep for validation activities. Each of these
2505 * is both in the #validation_heap and the #validation_map.
2506 */
2507struct ValidationState
2508{
2509 /**
2510 * For which peer is @a address to be validated (or possibly valid)?
2511 * Serves as key in the #validation_map.
2512 */
2513 struct GNUNET_PeerIdentity pid;
2514
2515 /**
2516 * How long did the peer claim this @e address to be valid? Capped at
2517 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2518 * were told about the address and the value claimed by the other peer at
2519 * that time. May be updated similarly when validation succeeds.
2520 */
2521 struct GNUNET_TIME_Absolute valid_until;
2522
2523 /**
2524 * How long do *we* consider this @e address to be valid?
2525 * In the past or zero if we have not yet validated it.
2526 */
2527 struct GNUNET_TIME_Absolute validated_until;
2528
2529 /**
2530 * When did we FIRST use the current @e challenge in a message?
2531 * Used to sanity-check @code{origin_time} in the response when
2532 * calculating the RTT. If the @code{origin_time} is not in
2533 * the expected range, the response is discarded as malicious.
2534 */
2535 struct GNUNET_TIME_Absolute first_challenge_use;
2536
2537 /**
2538 * When did we LAST use the current @e challenge in a message?
2539 * Used to sanity-check @code{origin_time} in the response when
2540 * calculating the RTT. If the @code{origin_time} is not in
2541 * the expected range, the response is discarded as malicious.
2542 */
2543 struct GNUNET_TIME_Absolute last_challenge_use;
2544
2545 /**
2546 * Next time we will send the @e challenge to the peer, if this time is past
2547 * @e valid_until, this validation state is released at this time. If the
2548 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2549 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2550 * to re-validate before the validity actually expires.
2551 */
2552 struct GNUNET_TIME_Absolute next_challenge;
2553
2554 /**
2555 * Current backoff factor we're applying for sending the @a challenge.
2556 * Reset to 0 if the @a challenge is confirmed upon validation.
2557 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2558 * existing value if we receive an unvalidated address again over
2559 * another channel (and thus should consider the information "fresh").
2560 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2561 */
2562 struct GNUNET_TIME_Relative challenge_backoff;
2563
2564 /**
2565 * Initially set to "forever". Once @e validated_until is set, this value is
2566 * set to the RTT that tells us how long it took to receive the validation.
2567 */
2568 struct GNUNET_TIME_Relative validation_rtt;
2569
2570 /**
2571 * The challenge we sent to the peer to get it to validate the address. Note
2572 * that we rotate the challenge whenever we update @e validated_until to
2573 * avoid attacks where a peer simply replays an old challenge in the future.
2574 * (We must not rotate more often as otherwise we may discard valid answers
2575 * due to packet losses, latency and reorderings on the network).
2576 */
2577 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
2578
2579 /**
2580 * Claimed address of the peer.
2581 */
2582 char *address;
2583
2584 /**
2585 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2586 * heap is used to figure out when the next validation activity should be
2587 * run.
2588 */
2589 struct GNUNET_CONTAINER_HeapNode *hn;
2590
2591 /**
2592 * Handle to a PEERSTORE store operation for this @e address. NULL if
2593 * no PEERSTORE operation is pending.
2594 */
2595 struct GNUNET_PEERSTORE_StoreContext *sc;
2596
2597 /**
2598 * Self-imposed limit on the previous flow control window. (May be zero,
2599 * if we never used data from the previous window or are establishing the
2600 * connection for the first time).
2601 */
2602 uint32_t last_window_consum_limit;
2603
2604 /**
2605 * We are technically ready to send the challenge, but we are waiting for
2606 * the respective queue to become available for transmission.
2607 */
2608 int awaiting_queue;
2609};
2610
2611
2612/**
2613 * A Backtalker is a peer sending us backchannel messages. We use this
2614 * struct to detect monotonic time violations, cache ephemeral key
2615 * material (to avoid repeatedly checking signatures), and to synchronize
2616 * monotonic time with the PEERSTORE.
2617 */
2618struct Backtalker
2619{
2620 /**
2621 * Peer this is about.
2622 */
2623 struct GNUNET_PeerIdentity pid;
2624
2625 /**
2626 * Last (valid) monotonic time received from this sender.
2627 */
2628 struct GNUNET_TIME_Absolute monotonic_time;
2629
2630 /**
2631 * When will this entry time out?
2632 */
2633 struct GNUNET_TIME_Absolute timeout;
2634
2635 /**
2636 * Last (valid) ephemeral key received from this sender.
2637 */
2638 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2639
2640 /**
2641 * Task associated with this backtalker. Can be for timeout,
2642 * or other asynchronous operations.
2643 */
2644 struct GNUNET_SCHEDULER_Task *task;
2645
2646 /**
2647 * Communicator context waiting on this backchannel's @e get, or NULL.
2648 */
2649 struct CommunicatorMessageContext *cmc;
2650
2651 /**
2652 * Handle for an operation to fetch @e monotonic_time information from the
2653 * PEERSTORE, or NULL.
2654 */
2655 struct GNUNET_PEERSTORE_IterateContext *get;
2656
2657 /**
2658 * Handle to a PEERSTORE store operation for this @e pid's @e
2659 * monotonic_time. NULL if no PEERSTORE operation is pending.
2660 */
2661 struct GNUNET_PEERSTORE_StoreContext *sc;
2662
2663 /**
2664 * Number of bytes of the original message body that follows after this
2665 * struct.
2666 */
2667 size_t body_size;
2668};
2669
2670
2671/**
2672 * Head of linked list of all clients to this service.
2673 */
2674static struct TransportClient *clients_head;
2675
2676/**
2677 * Tail of linked list of all clients to this service.
2678 */
2679static struct TransportClient *clients_tail;
2680
2681/**
2682 * Statistics handle.
2683 */
2684static struct GNUNET_STATISTICS_Handle *GST_stats;
2685
2686/**
2687 * Configuration handle.
2688 */
2689static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2690
2691/**
2692 * Our public key.
2693 */
2694static struct GNUNET_PeerIdentity GST_my_identity;
2695
2696/**
2697 * Our private key.
2698 */
2699static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2700
2701/**
2702 * Map from PIDs to `struct Neighbour` entries. A peer is
2703 * a neighbour if we have an MQ to it from some communicator.
2704 */
2705static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2706
2707/**
2708 * Map from PIDs to `struct Backtalker` entries. A peer is
2709 * a backtalker if it recently send us backchannel messages.
2710 */
2711static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2712
2713/**
2714 * Map from PIDs to `struct AcknowledgementCummulator`s.
2715 * Here we track the cumulative ACKs for transmission.
2716 */
2717static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2718
2719/**
2720 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2721 * a `struct PendingAcknowledgement`.
2722 */
2723static struct GNUNET_CONTAINER_MultiUuidmap *pending_acks;
2724
2725/**
2726 * Map from PIDs to `struct DistanceVector` entries describing
2727 * known paths to the peer.
2728 */
2729static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2730
2731/**
2732 * Map from PIDs to `struct ValidationState` entries describing
2733 * addresses we are aware of and their validity state.
2734 */
2735static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2736
2737/**
2738 * Map from PIDs to `struct VirtualLink` entries describing
2739 * links CORE knows to exist.
2740 */
2741static struct GNUNET_CONTAINER_MultiPeerMap *links;
2742
2743/**
2744 * Map from challenges to `struct LearnLaunchEntry` values.
2745 */
2746static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2747
2748/**
2749 * Head of a DLL sorted by launch time.
2750 */
2751static struct LearnLaunchEntry *lle_head = NULL;
2752
2753/**
2754 * Tail of a DLL sorted by launch time.
2755 */
2756static struct LearnLaunchEntry *lle_tail = NULL;
2757
2758/**
2759 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2760 * sorting addresses we are aware of by when we should next try to (re)validate
2761 * (or expire) them.
2762 */
2763static struct GNUNET_CONTAINER_Heap *validation_heap;
2764
2765/**
2766 * Database for peer's HELLOs.
2767 */
2768static struct GNUNET_PEERSTORE_Handle *peerstore;
2769
2770/**
2771 * Task run to initiate DV learning.
2772 */
2773static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2774
2775/**
2776 * Task to run address validation.
2777 */
2778static struct GNUNET_SCHEDULER_Task *validation_task;
2779
2780/**
2781 * The most recent PA we have created, head of DLL.
2782 * The length of the DLL is kept in #pa_count.
2783 */
2784static struct PendingAcknowledgement *pa_head;
2785
2786/**
2787 * The oldest PA we have created, tail of DLL.
2788 * The length of the DLL is kept in #pa_count.
2789 */
2790static struct PendingAcknowledgement *pa_tail;
2791
2792/**
2793 * List of incoming connections where we are trying
2794 * to get a connection back established. Length
2795 * kept in #ir_total.
2796 */
2797static struct IncomingRequest *ir_head;
2798
2799/**
2800 * Tail of DLL starting at #ir_head.
2801 */
2802static struct IncomingRequest *ir_tail;
2803
2804/**
2805 * Length of the DLL starting at #ir_head.
2806 */
2807static unsigned int ir_total;
2808
2809/**
2810 * Generator of `logging_uuid` in `struct PendingMessage`.
2811 */
2812static unsigned long long logging_uuid_gen;
2813
2814/**
2815 * Number of entries in the #pa_head/#pa_tail DLL. Used to
2816 * limit the size of the data structure.
2817 */
2818static unsigned int pa_count;
2819
2820/**
2821 * Monotonic time we use for HELLOs generated at this time. TODO: we
2822 * should increase this value from time to time (i.e. whenever a
2823 * `struct AddressListEntry` actually expires), but IF we do this, we
2824 * must also update *all* (remaining) addresses in the PEERSTORE at
2825 * that time! (So for now only increased when the peer is restarted,
2826 * which hopefully roughly matches whenever our addresses change.)
2827 */
2828static struct GNUNET_TIME_Absolute hello_mono_time;
2829
2830/**
2831 * Indication if we have received a shutdown signal
2832 * and are in the process of cleaning up.
2833 */
2834static int in_shutdown;
2835
2836/**
2837 * Get an offset into the transmission history buffer for `struct
2838 * PerformanceData`. Note that the caller must perform the required
2839 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
2840 * array!
2841 *
2842 * An 'age' lasts 15 minute slots.
2843 *
2844 * @return current age of the world
2845 */
2846static unsigned int
2847get_age ()
2848{
2849 struct GNUNET_TIME_Absolute now;
2850
2851 now = GNUNET_TIME_absolute_get ();
2852 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
2853}
2854
2855
2856/**
2857 * Release @a ir data structure.
2858 *
2859 * @param ir data structure to release
2860 */
2861static void
2862free_incoming_request (struct IncomingRequest *ir)
2863{
2864 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
2865 GNUNET_assert (ir_total > 0);
2866 ir_total--;
2867 GNUNET_PEERSTORE_watch_cancel (ir->wc);
2868 ir->wc = NULL;
2869 GNUNET_free (ir);
2870}
2871
2872
2873/**
2874 * Release @a pa data structure.
2875 *
2876 * @param pa data structure to release
2877 */
2878static void
2879free_pending_acknowledgement (struct PendingAcknowledgement *pa)
2880{
2881 struct Queue *q = pa->queue;
2882 struct PendingMessage *pm = pa->pm;
2883 struct DistanceVectorHop *dvh = pa->dvh;
2884
2885 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2886 "free_pending_acknowledgement\n");
2887 if (NULL != q)
2888 {
2889 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
2890 pa->queue = NULL;
2891 }
2892 if (NULL != pm)
2893 {
2894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2895 "remove pa from message\n");
2896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2897 "remove pa from message %llu\n",
2898 pm->logging_uuid);
2899 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2900 "remove pa from message %u\n",
2901 pm->pmt);
2902 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2903 "remove pa from message %s\n",
2904 GNUNET_uuid2s (&pa->ack_uuid.value));
2905 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
2906 pa->pm = NULL;
2907 }
2908 if (NULL != dvh)
2909 {
2910 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
2911 pa->queue = NULL;
2912 }
2913 GNUNET_assert (GNUNET_YES ==
2914 GNUNET_CONTAINER_multiuuidmap_remove (pending_acks,
2915 &pa->ack_uuid.value,
2916 pa));
2917 GNUNET_free (pa);
2918}
2919
2920
2921/**
2922 * Free fragment tree below @e root, excluding @e root itself.
2923 * FIXME: this does NOT seem to have the intended semantics
2924 * based on how this is called. Seems we generally DO expect
2925 * @a root to be free'ed itself as well!
2926 *
2927 * @param root root of the tree to free
2928 */
2929static void
2930free_fragment_tree (struct PendingMessage *root)
2931{
2932 struct PendingMessage *frag;
2933
2934 while (NULL != (frag = root->head_frag))
2935 {
2936 struct PendingAcknowledgement *pa;
2937
2938 free_fragment_tree (frag);
2939 while (NULL != (pa = frag->pa_head))
2940 {
2941 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
2942 pa->pm = NULL;
2943 }
2944 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
2945 if (NULL != frag->qe)
2946 {
2947 GNUNET_assert (frag == frag->qe->pm);
2948 frag->qe->pm = NULL;
2949 GNUNET_CONTAINER_DLL_remove (frag->qe->queue->queue_head,
2950 frag->qe->queue->queue_tail,
2951 frag->qe);
2952 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2953 "Removing QueueEntry MID %llu from queue\n",
2954 frag->qe->mid);
2955 GNUNET_free (frag->qe);
2956 }
2957 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2958 "Free frag %p\n",
2959 frag);
2960 GNUNET_free (frag);
2961 }
2962}
2963
2964
2965/**
2966 * Release memory associated with @a pm and remove @a pm from associated
2967 * data structures. @a pm must be a top-level pending message and not
2968 * a fragment in the tree. The entire tree is freed (if applicable).
2969 *
2970 * @param pm the pending message to free
2971 */
2972static void
2973free_pending_message (struct PendingMessage *pm)
2974{
2975 struct TransportClient *tc = pm->client;
2976 struct VirtualLink *vl = pm->vl;
2977 struct PendingAcknowledgement *pa;
2978
2979 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2980 "Freeing pm %p\n",
2981 pm);
2982 if (NULL != tc)
2983 {
2984 GNUNET_CONTAINER_MDLL_remove (client,
2985 tc->details.core.pending_msg_head,
2986 tc->details.core.pending_msg_tail,
2987 pm);
2988 }
2989 if ((NULL != vl) && (NULL == pm->frag_parent))
2990 {
2991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2992 "Removing pm %lu\n",
2993 pm->logging_uuid);
2994 GNUNET_CONTAINER_MDLL_remove (vl,
2995 vl->pending_msg_head,
2996 vl->pending_msg_tail,
2997 pm);
2998 }
2999 while (NULL != (pa = pm->pa_head))
3000 {
3001 if (NULL == pa)
3002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3003 "free pending pa null\n");
3004 if (NULL == pm->pa_tail)
3005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3006 "free pending pa_tail null\n");
3007 if (NULL == pa->prev_pa)
3008 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3009 "free pending pa prev null\n");
3010 if (NULL == pa->next_pa)
3011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3012 "free pending pa next null\n");
3013 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3014 pa->pm = NULL;
3015 }
3016
3017 free_fragment_tree (pm);
3018 if (NULL != pm->qe)
3019 {
3020 GNUNET_assert (pm == pm->qe->pm);
3021 pm->qe->pm = NULL;
3022 GNUNET_CONTAINER_DLL_remove (pm->qe->queue->queue_head,
3023 pm->qe->queue->queue_tail,
3024 pm->qe);
3025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3026 "Removing QueueEntry MID %llu from queue\n",
3027 pm->qe->mid);
3028 GNUNET_free (pm->qe);
3029 }
3030 if (NULL != pm->bpm)
3031 {
3032 free_fragment_tree (pm->bpm);
3033 GNUNET_free (pm->bpm);
3034 }
3035 if (NULL == pm)
3036 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3037 "free pending pm null\n");
3038 GNUNET_free (pm);
3039}
3040
3041
3042/**
3043 * Free @a rc
3044 *
3045 * @param rc data structure to free
3046 */
3047static void
3048free_reassembly_context (struct ReassemblyContext *rc)
3049{
3050 struct VirtualLink *vl = rc->virtual_link;
3051
3052 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
3053 GNUNET_assert (GNUNET_OK ==
3054 GNUNET_CONTAINER_multihashmap32_remove (vl->reassembly_map,
3055 rc->msg_uuid.uuid,
3056 rc));
3057 GNUNET_free (rc);
3058}
3059
3060
3061/**
3062 * Task run to clean up reassembly context of a neighbour that have expired.
3063 *
3064 * @param cls a `struct Neighbour`
3065 */
3066static void
3067reassembly_cleanup_task (void *cls)
3068{
3069 struct VirtualLink *vl = cls;
3070 struct ReassemblyContext *rc;
3071
3072 vl->reassembly_timeout_task = NULL;
3073 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3074 {
3075 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
3076 .rel_value_us)
3077 {
3078 free_reassembly_context (rc);
3079 continue;
3080 }
3081 GNUNET_assert (NULL == vl->reassembly_timeout_task);
3082 vl->reassembly_timeout_task =
3083 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
3084 &reassembly_cleanup_task,
3085 vl);
3086 return;
3087 }
3088}
3089
3090
3091/**
3092 * function called to #free_reassembly_context().
3093 *
3094 * @param cls NULL
3095 * @param key unused
3096 * @param value a `struct ReassemblyContext` to free
3097 * @return #GNUNET_OK (continue iteration)
3098 */
3099static int
3100free_reassembly_cb (void *cls, uint32_t key, void *value)
3101{
3102 struct ReassemblyContext *rc = value;
3103
3104 (void) cls;
3105 (void) key;
3106 free_reassembly_context (rc);
3107 return GNUNET_OK;
3108}
3109
3110
3111/**
3112 * Free virtual link.
3113 *
3114 * @param vl link data to free
3115 */
3116static void
3117free_virtual_link (struct VirtualLink *vl)
3118{
3119 struct PendingMessage *pm;
3120 struct CoreSentContext *csc;
3121
3122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3123 "free virtual link %p\n",
3124 vl);
3125
3126 if (NULL != vl->reassembly_map)
3127 {
3128 GNUNET_CONTAINER_multihashmap32_iterate (vl->reassembly_map,
3129 &free_reassembly_cb,
3130 NULL);
3131 GNUNET_CONTAINER_multihashmap32_destroy (vl->reassembly_map);
3132 vl->reassembly_map = NULL;
3133 GNUNET_CONTAINER_heap_destroy (vl->reassembly_heap);
3134 vl->reassembly_heap = NULL;
3135 }
3136 if (NULL != vl->reassembly_timeout_task)
3137 {
3138 GNUNET_SCHEDULER_cancel (vl->reassembly_timeout_task);
3139 vl->reassembly_timeout_task = NULL;
3140 }
3141 while (NULL != (pm = vl->pending_msg_head))
3142 free_pending_message (pm);
3143 GNUNET_assert (GNUNET_YES ==
3144 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl));
3145 if (NULL != vl->visibility_task)
3146 {
3147 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3148 vl->visibility_task = NULL;
3149 }
3150 if (NULL != vl->fc_retransmit_task)
3151 {
3152 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
3153 vl->fc_retransmit_task = NULL;
3154 }
3155 while (NULL != (csc = vl->csc_head))
3156 {
3157 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
3158 GNUNET_assert (vl == csc->vl);
3159 csc->vl = NULL;
3160 }
3161 GNUNET_break (NULL == vl->n);
3162 GNUNET_break (NULL == vl->dv);
3163 GNUNET_free (vl);
3164}
3165
3166
3167/**
3168 * Free validation state.
3169 *
3170 * @param vs validation state to free
3171 */
3172static void
3173free_validation_state (struct ValidationState *vs)
3174{
3175 GNUNET_assert (
3176 GNUNET_YES ==
3177 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs));
3178 GNUNET_CONTAINER_heap_remove_node (vs->hn);
3179 vs->hn = NULL;
3180 if (NULL != vs->sc)
3181 {
3182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3183 "store cancel\n");
3184 GNUNET_PEERSTORE_store_cancel (vs->sc);
3185 vs->sc = NULL;
3186 }
3187 GNUNET_free (vs->address);
3188 GNUNET_free (vs);
3189}
3190
3191
3192/**
3193 * Lookup neighbour for peer @a pid.
3194 *
3195 * @param pid neighbour to look for
3196 * @return NULL if we do not have this peer as a neighbour
3197 */
3198static struct Neighbour *
3199lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
3200{
3201 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
3202}
3203
3204
3205/**
3206 * Lookup virtual link for peer @a pid.
3207 *
3208 * @param pid virtual link to look for
3209 * @return NULL if we do not have this peer as a virtual link
3210 */
3211static struct VirtualLink *
3212lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3213{
3214 return GNUNET_CONTAINER_multipeermap_get (links, pid);
3215}
3216
3217
3218/**
3219 * Details about what to notify monitors about.
3220 */
3221struct MonitorEvent
3222{
3223 /**
3224 * @deprecated To be discussed if we keep these...
3225 */
3226 struct GNUNET_TIME_Absolute last_validation;
3227 struct GNUNET_TIME_Absolute valid_until;
3228 struct GNUNET_TIME_Absolute next_validation;
3229
3230 /**
3231 * Current round-trip time estimate.
3232 */
3233 struct GNUNET_TIME_Relative rtt;
3234
3235 /**
3236 * Connection status.
3237 */
3238 enum GNUNET_TRANSPORT_ConnectionStatus cs;
3239
3240 /**
3241 * Messages pending.
3242 */
3243 uint32_t num_msg_pending;
3244
3245 /**
3246 * Bytes pending.
3247 */
3248 uint32_t num_bytes_pending;
3249};
3250
3251
3252/**
3253 * Free a @dvh. Callers MAY want to check if this was the last path to the
3254 * `target`, and if so call #free_dv_route to also free the associated DV
3255 * entry in #dv_routes (if not, the associated scheduler job should eventually
3256 * take care of it).
3257 *
3258 * @param dvh hop to free
3259 */
3260static void
3261free_distance_vector_hop (struct DistanceVectorHop *dvh)
3262{
3263 struct Neighbour *n = dvh->next_hop;
3264 struct DistanceVector *dv = dvh->dv;
3265 struct PendingAcknowledgement *pa;
3266
3267 while (NULL != (pa = dvh->pa_head))
3268 {
3269 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3270 pa->dvh = NULL;
3271 }
3272 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3273 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
3274 GNUNET_free (dvh);
3275}
3276
3277
3278/**
3279 * Task run to check whether the hops of the @a cls still
3280 * are validated, or if we need to core about disconnection.
3281 *
3282 * @param cls a `struct VirtualLink`
3283 */
3284static void
3285check_link_down (void *cls);
3286
3287
3288/**
3289 * Send message to CORE clients that we lost a connection.
3290 *
3291 * @param pid peer the connection was for
3292 */
3293static void
3294cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3295{
3296 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3297 "Informing CORE clients about disconnect from %s\n",
3298 GNUNET_i2s (pid));
3299 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3300 {
3301 struct GNUNET_MQ_Envelope *env;
3302 struct DisconnectInfoMessage *dim;
3303
3304 if (CT_CORE != tc->type)
3305 continue;
3306 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3307 dim->peer = *pid;
3308 GNUNET_MQ_send (tc->mq, env);
3309 }
3310}
3311
3312
3313/**
3314 * Free entry in #dv_routes. First frees all hops to the target, and
3315 * if there are no entries left, frees @a dv as well.
3316 *
3317 * @param dv route to free
3318 */
3319static void
3320free_dv_route (struct DistanceVector *dv)
3321{
3322 struct DistanceVectorHop *dvh;
3323
3324 while (NULL != (dvh = dv->dv_head))
3325 free_distance_vector_hop (dvh);
3326 if (NULL == dv->dv_head)
3327 {
3328 struct VirtualLink *vl;
3329
3330 GNUNET_assert (
3331 GNUNET_YES ==
3332 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
3333 if (NULL != (vl = dv->vl))
3334 {
3335 GNUNET_assert (dv == vl->dv);
3336 vl->dv = NULL;
3337 if (NULL == vl->n)
3338 {
3339 cores_send_disconnect_info (&dv->target);
3340 free_virtual_link (vl);
3341 }
3342 else
3343 {
3344 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3345 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3346 }
3347 dv->vl = NULL;
3348 }
3349
3350 if (NULL != dv->timeout_task)
3351 {
3352 GNUNET_SCHEDULER_cancel (dv->timeout_task);
3353 dv->timeout_task = NULL;
3354 }
3355 GNUNET_free (dv);
3356 }
3357}
3358
3359
3360/**
3361 * Notify monitor @a tc about an event. That @a tc
3362 * cares about the event has already been checked.
3363 *
3364 * Send @a tc information in @a me about a @a peer's status with
3365 * respect to some @a address to all monitors that care.
3366 *
3367 * @param tc monitor to inform
3368 * @param peer peer the information is about
3369 * @param address address the information is about
3370 * @param nt network type associated with @a address
3371 * @param me detailed information to transmit
3372 */
3373static void
3374notify_monitor (struct TransportClient *tc,
3375 const struct GNUNET_PeerIdentity *peer,
3376 const char *address,
3377 enum GNUNET_NetworkType nt,
3378 const struct MonitorEvent *me)
3379{
3380 struct GNUNET_MQ_Envelope *env;
3381 struct GNUNET_TRANSPORT_MonitorData *md;
3382 size_t addr_len = strlen (address) + 1;
3383
3384 env = GNUNET_MQ_msg_extra (md,
3385 addr_len,
3386 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
3387 md->nt = htonl ((uint32_t) nt);
3388 md->peer = *peer;
3389 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
3390 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
3391 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
3392 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
3393 md->cs = htonl ((uint32_t) me->cs);
3394 md->num_msg_pending = htonl (me->num_msg_pending);
3395 md->num_bytes_pending = htonl (me->num_bytes_pending);
3396 memcpy (&md[1], address, addr_len);
3397 GNUNET_MQ_send (tc->mq, env);
3398}
3399
3400
3401/**
3402 * Send information in @a me about a @a peer's status with respect
3403 * to some @a address to all monitors that care.
3404 *
3405 * @param peer peer the information is about
3406 * @param address address the information is about
3407 * @param nt network type associated with @a address
3408 * @param me detailed information to transmit
3409 */
3410static void
3411notify_monitors (const struct GNUNET_PeerIdentity *peer,
3412 const char *address,
3413 enum GNUNET_NetworkType nt,
3414 const struct MonitorEvent *me)
3415{
3416 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3417 {
3418 if (CT_MONITOR != tc->type)
3419 continue;
3420 if (tc->details.monitor.one_shot)
3421 continue;
3422 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
3423 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
3424 continue;
3425 notify_monitor (tc, peer, address, nt, me);
3426 }
3427}
3428
3429
3430/**
3431 * Called whenever a client connects. Allocates our
3432 * data structures associated with that client.
3433 *
3434 * @param cls closure, NULL
3435 * @param client identification of the client
3436 * @param mq message queue for the client
3437 * @return our `struct TransportClient`
3438 */
3439static void *
3440client_connect_cb (void *cls,
3441 struct GNUNET_SERVICE_Client *client,
3442 struct GNUNET_MQ_Handle *mq)
3443{
3444 struct TransportClient *tc;
3445
3446 (void) cls;
3447 tc = GNUNET_new (struct TransportClient);
3448 tc->client = client;
3449 tc->mq = mq;
3450 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
3451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3452 "Client %p of type %u connected\n",
3453 tc,
3454 tc->type);
3455 return tc;
3456}
3457
3458
3459/**
3460 * Release memory used by @a neighbour.
3461 *
3462 * @param neighbour neighbour entry to free
3463 */
3464static void
3465free_neighbour (struct Neighbour *neighbour)
3466{
3467 struct DistanceVectorHop *dvh;
3468 struct VirtualLink *vl;
3469
3470 GNUNET_assert (NULL == neighbour->queue_head);
3471 GNUNET_assert (GNUNET_YES ==
3472 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3473 &neighbour->pid,
3474 neighbour));
3475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3476 "Freeing neighbour\n");
3477 while (NULL != (dvh = neighbour->dv_head))
3478 {
3479 struct DistanceVector *dv = dvh->dv;
3480
3481 free_distance_vector_hop (dvh);
3482 if (NULL == dv->dv_head)
3483 free_dv_route (dv);
3484 }
3485 if (NULL != neighbour->get)
3486 {
3487 GNUNET_PEERSTORE_iterate_cancel (neighbour->get);
3488 neighbour->get = NULL;
3489 }
3490 if (NULL != neighbour->sc)
3491 {
3492 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3493 "store cancel\n");
3494 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3495 neighbour->sc = NULL;
3496 }
3497 if (NULL != (vl = neighbour->vl))
3498 {
3499 GNUNET_assert (neighbour == vl->n);
3500 vl->n = NULL;
3501 if (NULL == vl->dv)
3502 {
3503 cores_send_disconnect_info (&vl->target);
3504 free_virtual_link (vl);
3505 }
3506 else
3507 {
3508 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3509 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3510 }
3511 neighbour->vl = NULL;
3512 }
3513 GNUNET_free (neighbour);
3514}
3515
3516
3517/**
3518 * Send message to CORE clients that we lost a connection.
3519 *
3520 * @param tc client to inform (must be CORE client)
3521 * @param pid peer the connection is for
3522 */
3523static void
3524core_send_connect_info (struct TransportClient *tc,
3525 const struct GNUNET_PeerIdentity *pid)
3526{
3527 struct GNUNET_MQ_Envelope *env;
3528 struct ConnectInfoMessage *cim;
3529
3530 GNUNET_assert (CT_CORE == tc->type);
3531 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3532 cim->id = *pid;
3533 GNUNET_MQ_send (tc->mq, env);
3534}
3535
3536
3537/**
3538 * Send message to CORE clients that we gained a connection
3539 *
3540 * @param pid peer the queue was for
3541 */
3542static void
3543cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3544{
3545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3546 "Informing CORE clients about connection to %s\n",
3547 GNUNET_i2s (pid));
3548 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3549 {
3550 if (CT_CORE != tc->type)
3551 continue;
3552 core_send_connect_info (tc, pid);
3553 }
3554}
3555
3556
3557/**
3558 * We believe we are ready to transmit a message on a queue. Gives the
3559 * message to the communicator for transmission (updating the tracker,
3560 * and re-scheduling itself if applicable).
3561 *
3562 * @param cls the `struct Queue` to process transmissions for
3563 */
3564static void
3565transmit_on_queue (void *cls);
3566
3567
3568/**
3569 * Check if the communicator has another queue with higher prio ready for sending.
3570 */
3571static unsigned int
3572check_for_queue_with_higher_prio (struct Queue *queue, struct Queue *queue_head)
3573{
3574 for (struct Queue *s = queue_head; NULL != s;
3575 s = s->next_client)
3576 {
3577 if (s->tc->details.communicator.address_prefix !=
3578 queue->tc->details.communicator.address_prefix)
3579 {
3580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3581 "queue address %s qid %u compare with queue: address %s qid %u\n",
3582 queue->address,
3583 queue->qid,
3584 s->address,
3585 s->qid);
3586 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
3587 (QUEUE_LENGTH_LIMIT > s->queue_length) )
3588 return GNUNET_YES;
3589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3590 "Lower prio\n");
3591 }
3592 }
3593 return GNUNET_NO;
3594}
3595
3596
3597/**
3598 * Called whenever something changed that might effect when we
3599 * try to do the next transmission on @a queue using #transmit_on_queue().
3600 *
3601 * @param queue the queue to do scheduling for
3602 * @param p task priority to use, if @a queue is scheduled
3603 */
3604static void
3605schedule_transmit_on_queue (struct GNUNET_TIME_Relative delay,
3606 struct Queue *queue,
3607 enum GNUNET_SCHEDULER_Priority p)
3608{
3609 if (check_for_queue_with_higher_prio (queue,
3610 queue->tc->details.communicator.
3611 queue_head))
3612 return;
3613
3614 if (queue->tc->details.communicator.total_queue_length >=
3615 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3616 {
3617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3618 "Transmission throttled due to communicator queue limit\n");
3619 GNUNET_STATISTICS_update (
3620 GST_stats,
3621 "# Transmission throttled due to communicator queue limit",
3622 1,
3623 GNUNET_NO);
3624 queue->idle = GNUNET_NO;
3625 return;
3626 }
3627 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3628 {
3629 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3630 "Transmission throttled due to communicator queue length limit\n");
3631 GNUNET_STATISTICS_update (GST_stats,
3632 "# Transmission throttled due to queue queue limit",
3633 1,
3634 GNUNET_NO);
3635 queue->idle = GNUNET_NO;
3636 return;
3637 }
3638 if (0 == queue->q_capacity)
3639 {
3640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3641 "Transmission throttled due to communicator message queue qid %u has capacity %lu.\n",
3642 queue->qid,
3643 queue->q_capacity);
3644 GNUNET_STATISTICS_update (GST_stats,
3645 "# Transmission throttled due to message queue capacity",
3646 1,
3647 GNUNET_NO);
3648 queue->idle = GNUNET_NO;
3649 return;
3650 }
3651 /* queue might indeed be ready, schedule it */
3652 if (NULL != queue->transmit_task)
3653 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3654 queue->transmit_task =
3655 GNUNET_SCHEDULER_add_delayed_with_priority (delay, p, &transmit_on_queue,
3656 queue);
3657 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3658 "Considering transmission on queue `%s' QID %llu to %s\n",
3659 queue->address,
3660 (unsigned long long) queue->qid,
3661 GNUNET_i2s (&queue->neighbour->pid));
3662}
3663
3664
3665/**
3666 * Task run to check whether the hops of the @a cls still
3667 * are validated, or if we need to core about disconnection.
3668 *
3669 * @param cls a `struct VirtualLink`
3670 */
3671static void
3672check_link_down (void *cls)
3673{
3674 struct VirtualLink *vl = cls;
3675 struct DistanceVector *dv = vl->dv;
3676 struct Neighbour *n = vl->n;
3677 struct GNUNET_TIME_Absolute dvh_timeout;
3678 struct GNUNET_TIME_Absolute q_timeout;
3679
3680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3681 "Checking if link is down\n");
3682 vl->visibility_task = NULL;
3683 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3684 if (NULL != dv)
3685 {
3686 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3687 pos = pos->next_dv)
3688 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
3689 pos->path_valid_until);
3690 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3691 {
3692 vl->dv->vl = NULL;
3693 vl->dv = NULL;
3694 }
3695 }
3696 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3697 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3698 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3699 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3700 {
3701 vl->n->vl = NULL;
3702 vl->n = NULL;
3703 }
3704 if ((NULL == vl->n) && (NULL == vl->dv))
3705 {
3706 cores_send_disconnect_info (&vl->target);
3707 free_virtual_link (vl);
3708 return;
3709 }
3710 vl->visibility_task =
3711 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3712 &check_link_down,
3713 vl);
3714}
3715
3716
3717/**
3718 * Free @a queue.
3719 *
3720 * @param queue the queue to free
3721 */
3722static void
3723free_queue (struct Queue *queue)
3724{
3725 struct Neighbour *neighbour = queue->neighbour;
3726 struct TransportClient *tc = queue->tc;
3727 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
3728 .rtt = GNUNET_TIME_UNIT_FOREVER_REL };
3729 struct QueueEntry *qe;
3730 int maxxed;
3731 struct PendingAcknowledgement *pa;
3732 struct VirtualLink *vl;
3733
3734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3735 "Cleaning up queue %u\n", queue->qid);
3736 if (NULL != queue->transmit_task)
3737 {
3738 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3739 queue->transmit_task = NULL;
3740 }
3741 while (NULL != (pa = queue->pa_head))
3742 {
3743 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3744 pa->queue = NULL;
3745 }
3746
3747 GNUNET_CONTAINER_MDLL_remove (neighbour,
3748 neighbour->queue_head,
3749 neighbour->queue_tail,
3750 queue);
3751 GNUNET_CONTAINER_MDLL_remove (client,
3752 tc->details.communicator.queue_head,
3753 tc->details.communicator.queue_tail,
3754 queue);
3755 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT <=
3756 tc->details.communicator.
3757 total_queue_length);
3758 while (NULL != (qe = queue->queue_head))
3759 {
3760 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3761 queue->queue_length--;
3762 tc->details.communicator.total_queue_length--;
3763 if (NULL != qe->pm)
3764 {
3765 GNUNET_assert (qe == qe->pm->qe);
3766 qe->pm->qe = NULL;
3767 }
3768 GNUNET_free (qe);
3769 }
3770 GNUNET_assert (0 == queue->queue_length);
3771 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
3772 tc->details.communicator.total_queue_length))
3773 {
3774 /* Communicator dropped below threshold, resume all _other_ queues */
3775 GNUNET_STATISTICS_update (
3776 GST_stats,
3777 "# Transmission throttled due to communicator queue limit",
3778 -1,
3779 GNUNET_NO);
3780 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
3781 s = s->next_client)
3782 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
3783 s,
3784 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
3785 }
3786 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
3787 GNUNET_free (queue);
3788
3789 vl = lookup_virtual_link (&neighbour->pid);
3790 if ((NULL != vl) && (GNUNET_YES == vl->confirmed) && (neighbour == vl->n))
3791 {
3792 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3793 check_link_down (vl);
3794 }
3795 if (NULL == neighbour->queue_head)
3796 {
3797 free_neighbour (neighbour);
3798 }
3799}
3800
3801
3802/**
3803 * Free @a ale
3804 *
3805 * @param ale address list entry to free
3806 */
3807static void
3808free_address_list_entry (struct AddressListEntry *ale)
3809{
3810 struct TransportClient *tc = ale->tc;
3811
3812 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
3813 tc->details.communicator.addr_tail,
3814 ale);
3815 if (NULL != ale->sc)
3816 {
3817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3818 "store cancel\n");
3819 GNUNET_PEERSTORE_store_cancel (ale->sc);
3820 ale->sc = NULL;
3821 }
3822 if (NULL != ale->st)
3823 {
3824 GNUNET_SCHEDULER_cancel (ale->st);
3825 ale->st = NULL;
3826 }
3827 GNUNET_free (ale);
3828}
3829
3830
3831/**
3832 * Stop the peer request in @a value.
3833 *
3834 * @param cls a `struct TransportClient` that no longer makes the request
3835 * @param pid the peer's identity
3836 * @param value a `struct PeerRequest`
3837 * @return #GNUNET_YES (always)
3838 */
3839static int
3840stop_peer_request (void *cls,
3841 const struct GNUNET_PeerIdentity *pid,
3842 void *value)
3843{
3844 struct TransportClient *tc = cls;
3845 struct PeerRequest *pr = value;
3846
3847 GNUNET_PEERSTORE_watch_cancel (pr->wc);
3848 pr->wc = NULL;
3849 GNUNET_assert (
3850 GNUNET_YES ==
3851 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
3852 pid,
3853 pr));
3854 GNUNET_free (pr);
3855
3856 return GNUNET_OK;
3857}
3858
3859
3860static void
3861do_shutdown (void *cls);
3862
3863/**
3864 * Called whenever a client is disconnected. Frees our
3865 * resources associated with that client.
3866 *
3867 * @param cls closure, NULL
3868 * @param client identification of the client
3869 * @param app_ctx our `struct TransportClient`
3870 */
3871static void
3872client_disconnect_cb (void *cls,
3873 struct GNUNET_SERVICE_Client *client,
3874 void *app_ctx)
3875{
3876 struct TransportClient *tc = app_ctx;
3877
3878 (void) cls;
3879 (void) client;
3880 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
3881 switch (tc->type)
3882 {
3883 case CT_NONE:
3884 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3885 "Unknown Client %p disconnected, cleaning up.\n",
3886 tc);
3887 break;
3888
3889 case CT_CORE: {
3890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3891 "CORE Client %p disconnected, cleaning up.\n",
3892 tc);
3893
3894 struct PendingMessage *pm;
3895
3896 while (NULL != (pm = tc->details.core.pending_msg_head))
3897 {
3898 GNUNET_CONTAINER_MDLL_remove (client,
3899 tc->details.core.pending_msg_head,
3900 tc->details.core.pending_msg_tail,
3901 pm);
3902 pm->client = NULL;
3903 }
3904 }
3905 break;
3906
3907 case CT_MONITOR:
3908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3909 "MONITOR Client %p disconnected, cleaning up.\n",
3910 tc);
3911
3912 break;
3913
3914 case CT_COMMUNICATOR: {
3915 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3916 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
3917 tc);
3918
3919 struct Queue *q;
3920 struct AddressListEntry *ale;
3921
3922 while (NULL != (q = tc->details.communicator.queue_head))
3923 free_queue (q);
3924 while (NULL != (ale = tc->details.communicator.addr_head))
3925 free_address_list_entry (ale);
3926 GNUNET_free (tc->details.communicator.address_prefix);
3927 }
3928 break;
3929
3930 case CT_APPLICATION:
3931 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3932 "APPLICATION Client %p disconnected, cleaning up.\n",
3933 tc);
3934
3935 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
3936 &stop_peer_request,
3937 tc);
3938 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
3939 break;
3940 }
3941 GNUNET_free (tc);
3942 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
3943 {
3944 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3945 "Our last client disconnected\n");
3946 do_shutdown (cls);
3947 }
3948}
3949
3950
3951/**
3952 * Iterator telling new CORE client about all existing
3953 * connections to peers.
3954 *
3955 * @param cls the new `struct TransportClient`
3956 * @param pid a connected peer
3957 * @param value the `struct Neighbour` with more information
3958 * @return #GNUNET_OK (continue to iterate)
3959 */
3960static int
3961notify_client_connect_info (void *cls,
3962 const struct GNUNET_PeerIdentity *pid,
3963 void *value)
3964{
3965 struct TransportClient *tc = cls;
3966
3967 (void) value;
3968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3969 "Telling new CORE client about existing connection to %s\n",
3970 GNUNET_i2s (pid));
3971 core_send_connect_info (tc, pid);
3972 return GNUNET_OK;
3973}
3974
3975
3976/**
3977 * Initialize a "CORE" client. We got a start message from this
3978 * client, so add it to the list of clients for broadcasting of
3979 * inbound messages.
3980 *
3981 * @param cls the client
3982 * @param start the start message that was sent
3983 */
3984static void
3985handle_client_start (void *cls, const struct StartMessage *start)
3986{
3987 struct TransportClient *tc = cls;
3988 uint32_t options;
3989
3990 options = ntohl (start->options);
3991 if ((0 != (1 & options)) &&
3992 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
3993 {
3994 /* client thinks this is a different peer, reject */
3995 GNUNET_break (0);
3996 GNUNET_SERVICE_client_drop (tc->client);
3997 return;
3998 }
3999 if (CT_NONE != tc->type)
4000 {
4001 GNUNET_break (0);
4002 GNUNET_SERVICE_client_drop (tc->client);
4003 return;
4004 }
4005 tc->type = CT_CORE;
4006 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4007 "New CORE client with PID %s registered\n",
4008 GNUNET_i2s (&start->self));
4009 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
4010 &notify_client_connect_info,
4011 tc);
4012 GNUNET_SERVICE_client_continue (tc->client);
4013}
4014
4015
4016/**
4017 * Client asked for transmission to a peer. Process the request.
4018 *
4019 * @param cls the client
4020 * @param obm the send message that was sent
4021 */
4022static int
4023check_client_send (void *cls, const struct OutboundMessage *obm)
4024{
4025 struct TransportClient *tc = cls;
4026 uint16_t size;
4027 const struct GNUNET_MessageHeader *obmm;
4028
4029 if (CT_CORE != tc->type)
4030 {
4031 GNUNET_break (0);
4032 return GNUNET_SYSERR;
4033 }
4034 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
4035 if (size < sizeof(struct GNUNET_MessageHeader))
4036 {
4037 GNUNET_break (0);
4038 return GNUNET_SYSERR;
4039 }
4040 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4041 if (size != ntohs (obmm->size))
4042 {
4043 GNUNET_break (0);
4044 return GNUNET_SYSERR;
4045 }
4046 return GNUNET_OK;
4047}
4048
4049
4050/**
4051 * Send a response to the @a pm that we have processed a "send"
4052 * request. Sends a confirmation to the "core" client responsible for
4053 * the original request and free's @a pm.
4054 *
4055 * @param pm handle to the original pending message
4056 */
4057static void
4058client_send_response (struct PendingMessage *pm)
4059{
4060 struct TransportClient *tc = pm->client;
4061 struct VirtualLink *vl = pm->vl;
4062
4063 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4064 "client send response\n");
4065 if (NULL != tc)
4066 {
4067 struct GNUNET_MQ_Envelope *env;
4068 struct SendOkMessage *so_msg;
4069
4070 env = GNUNET_MQ_msg (so_msg, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
4071 so_msg->peer = vl->target;
4072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4073 "Confirming transmission of <%llu> to %s\n",
4074 pm->logging_uuid,
4075 GNUNET_i2s (&vl->target));
4076 GNUNET_MQ_send (tc->mq, env);
4077 }
4078 free_pending_message (pm);
4079}
4080
4081
4082/**
4083 * Pick @a hops_array_length random DV paths satisfying @a options
4084 *
4085 * @param dv data structure to pick paths from
4086 * @param options constraints to satisfy
4087 * @param hops_array[out] set to the result
4088 * @param hops_array_length length of the @a hops_array
4089 * @return number of entries set in @a hops_array
4090 */
4091static unsigned int
4092pick_random_dv_hops (const struct DistanceVector *dv,
4093 enum RouteMessageOptions options,
4094 struct DistanceVectorHop **hops_array,
4095 unsigned int hops_array_length)
4096{
4097 uint64_t choices[hops_array_length];
4098 uint64_t num_dv;
4099 unsigned int dv_count;
4100
4101 /* Pick random vectors, but weighted by distance, giving more weight
4102 to shorter vectors */
4103 num_dv = 0;
4104 dv_count = 0;
4105 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4106 pos = pos->next_dv)
4107 {
4108 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4109 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4110 .rel_value_us == 0))
4111 continue; /* pos unconfirmed and confirmed required */
4112 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
4113 dv_count++;
4114 }
4115 if (0 == dv_count)
4116 return 0;
4117 if (dv_count <= hops_array_length)
4118 {
4119 dv_count = 0;
4120 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4121 pos = pos->next_dv)
4122 hops_array[dv_count++] = pos;
4123 return dv_count;
4124 }
4125 for (unsigned int i = 0; i < hops_array_length; i++)
4126 {
4127 int ok = GNUNET_NO;
4128 while (GNUNET_NO == ok)
4129 {
4130 choices[i] =
4131 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
4132 ok = GNUNET_YES;
4133 for (unsigned int j = 0; j < i; j++)
4134 if (choices[i] == choices[j])
4135 {
4136 ok = GNUNET_NO;
4137 break;
4138 }
4139 }
4140 }
4141 dv_count = 0;
4142 num_dv = 0;
4143 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4144 pos = pos->next_dv)
4145 {
4146 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
4147
4148 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4149 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4150 .rel_value_us == 0))
4151 continue; /* pos unconfirmed and confirmed required */
4152 for (unsigned int i = 0; i < hops_array_length; i++)
4153 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
4154 hops_array[dv_count++] = pos;
4155 num_dv += delta;
4156 }
4157 return dv_count;
4158}
4159
4160
4161/**
4162 * Communicator started. Test message is well-formed.
4163 *
4164 * @param cls the client
4165 * @param cam the send message that was sent
4166 */
4167static int
4168check_communicator_available (
4169 void *cls,
4170 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4171{
4172 struct TransportClient *tc = cls;
4173 uint16_t size;
4174
4175 if (CT_NONE != tc->type)
4176 {
4177 GNUNET_break (0);
4178 return GNUNET_SYSERR;
4179 }
4180 tc->type = CT_COMMUNICATOR;
4181 size = ntohs (cam->header.size) - sizeof(*cam);
4182 if (0 == size)
4183 return GNUNET_OK; /* receive-only communicator */
4184 GNUNET_MQ_check_zero_termination (cam);
4185 return GNUNET_OK;
4186}
4187
4188
4189/**
4190 * Send ACK to communicator (if requested) and free @a cmc.
4191 *
4192 * @param cmc context for which we are done handling the message
4193 */
4194static void
4195finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4196{
4197 if (0 != ntohl (cmc->im.fc_on))
4198 {
4199 /* send ACK when done to communicator for flow control! */
4200 struct GNUNET_MQ_Envelope *env;
4201 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4202
4203 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4204 ack->reserved = htonl (0);
4205 ack->fc_id = cmc->im.fc_id;
4206 ack->sender = cmc->im.sender;
4207 GNUNET_MQ_send (cmc->tc->mq, env);
4208 }
4209 GNUNET_SERVICE_client_continue (cmc->tc->client);
4210 GNUNET_free (cmc);
4211}
4212
4213
4214/**
4215 * Client confirms that it is done handling message(s) to a particular
4216 * peer. We may now provide more messages to CORE for this peer.
4217 *
4218 * Notifies the respective queues that more messages can now be received.
4219 *
4220 * @param cls the client
4221 * @param rom the message that was sent
4222 */
4223static void
4224handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4225{
4226 struct TransportClient *tc = cls;
4227 struct VirtualLink *vl;
4228 uint32_t delta;
4229 struct CommunicatorMessageContext *cmc;
4230
4231 if (CT_CORE != tc->type)
4232 {
4233 GNUNET_break (0);
4234 GNUNET_SERVICE_client_drop (tc->client);
4235 return;
4236 }
4237 vl = lookup_virtual_link (&rom->peer);
4238 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4239 {
4240 GNUNET_STATISTICS_update (GST_stats,
4241 "# RECV_OK dropped: virtual link unknown",
4242 1,
4243 GNUNET_NO);
4244 GNUNET_SERVICE_client_continue (tc->client);
4245 return;
4246 }
4247 delta = ntohl (rom->increase_window_delta);
4248 vl->core_recv_window += delta;
4249 if (vl->core_recv_window <= 0)
4250 return;
4251 /* resume communicators */
4252 while (NULL != (cmc = vl->cmc_tail))
4253 {
4254 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4255 finish_cmc_handling (cmc);
4256 }
4257}
4258
4259
4260/**
4261 * Communicator started. Process the request.
4262 *
4263 * @param cls the client
4264 * @param cam the send message that was sent
4265 */
4266static void
4267handle_communicator_available (
4268 void *cls,
4269 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4270{
4271 struct TransportClient *tc = cls;
4272 uint16_t size;
4273
4274 size = ntohs (cam->header.size) - sizeof(*cam);
4275 if (0 == size)
4276 {
4277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4278 "Receive-only communicator connected\n");
4279 return; /* receive-only communicator */
4280 }
4281 tc->details.communicator.address_prefix =
4282 GNUNET_strdup ((const char *) &cam[1]);
4283 tc->details.communicator.cc =
4284 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4286 "Communicator with prefix `%s' connected\n",
4287 tc->details.communicator.address_prefix);
4288 GNUNET_SERVICE_client_continue (tc->client);
4289}
4290
4291
4292/**
4293 * Communicator requests backchannel transmission. Check the request.
4294 *
4295 * @param cls the client
4296 * @param cb the send message that was sent
4297 * @return #GNUNET_OK if message is well-formed
4298 */
4299static int
4300check_communicator_backchannel (
4301 void *cls,
4302 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4303{
4304 const struct GNUNET_MessageHeader *inbox;
4305 const char *is;
4306 uint16_t msize;
4307 uint16_t isize;
4308
4309 (void) cls;
4310 msize = ntohs (cb->header.size) - sizeof(*cb);
4311 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4312 isize = ntohs (inbox->size);
4313 if (isize >= msize)
4314 {
4315 GNUNET_break (0);
4316 return GNUNET_SYSERR;
4317 }
4318 is = (const char *) inbox;
4319 is += isize;
4320 msize -= isize;
4321 GNUNET_assert (0 < msize);
4322 if ('\0' != is[msize - 1])
4323 {
4324 GNUNET_break (0);
4325 return GNUNET_SYSERR;
4326 }
4327 return GNUNET_OK;
4328}
4329
4330
4331/**
4332 * Ensure ephemeral keys in our @a dv are current. If no current one exists,
4333 * set it up.
4334 *
4335 * @param dv[in,out] virtual link to update ephemeral for
4336 */
4337static void
4338update_ephemeral (struct DistanceVector *dv)
4339{
4340 struct EphemeralConfirmationPS ec;
4341
4342 if (0 !=
4343 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
4344 return;
4345 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4346 dv->ephemeral_validity =
4347 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4348 GNUNET_CRYPTO_ecdhe_key_create (&dv->private_key);
4349 GNUNET_CRYPTO_ecdhe_key_get_public (&dv->private_key, &dv->ephemeral_key);
4350 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4351 ec.target = dv->target;
4352 ec.ephemeral_key = dv->ephemeral_key;
4353 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4354 ec.purpose.size = htonl (sizeof(ec));
4355 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4356 &ec,
4357 &dv->sender_sig);
4358}
4359
4360
4361/**
4362 * Send the message @a payload on @a queue.
4363 *
4364 * @param queue the queue to use for transmission
4365 * @param pm pending message to update once transmission is done, may be NULL!
4366 * @param payload the payload to send (encapsulated in a
4367 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4368 * @param payload_size number of bytes in @a payload
4369 */
4370static void
4371queue_send_msg (struct Queue *queue,
4372 struct PendingMessage *pm,
4373 const void *payload,
4374 size_t payload_size)
4375{
4376 struct Neighbour *n = queue->neighbour;
4377 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4378 struct GNUNET_MQ_Envelope *env;
4379
4380 GNUNET_log (
4381 GNUNET_ERROR_TYPE_DEBUG,
4382 "Queueing %u bytes of payload for transmission <%llu> on queue %llu to %s\n",
4383 (unsigned int) payload_size,
4384 (NULL == pm) ? 0 : pm->logging_uuid,
4385 (unsigned long long) queue->qid,
4386 GNUNET_i2s (&queue->neighbour->pid));
4387 env = GNUNET_MQ_msg_extra (smt,
4388 payload_size,
4389 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4390 smt->qid = queue->qid;
4391 smt->mid = queue->mid_gen;
4392 smt->receiver = n->pid;
4393 memcpy (&smt[1], payload, payload_size);
4394 {
4395 /* Pass the env to the communicator of queue for transmission. */
4396 struct QueueEntry *qe;
4397
4398 qe = GNUNET_new (struct QueueEntry);
4399 qe->mid = queue->mid_gen++;
4400 qe->queue = queue;
4401 if (NULL != pm)
4402 {
4403 qe->pm = pm;
4404 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
4405 // GNUNET_assert (NULL == pm->qe);
4406 /*if (NULL != pm->qe)
4407 {
4408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4409 "Retransmitting message <%llu> remove pm from qe with MID: %llu \n",
4410 pm->logging_uuid,
4411 (unsigned long long) pm->qe->mid);
4412 pm->qe->pm = NULL;
4413 }*/
4414 pm->qe = qe;
4415 }
4416 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4417 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4418 queue->queue_length++;
4419 queue->tc->details.communicator.total_queue_length++;
4420 if (0 == queue->q_capacity)
4421 return;
4422 if (GNUNET_NO == queue->unlimited_length)
4423 queue->q_capacity--;
4424 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4425 "Queue %s with qid %u has capacity %lu\n",
4426 queue->address,
4427 queue->qid,
4428 queue->q_capacity);
4429 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4430 queue->tc->details.communicator.total_queue_length)
4431 queue->idle = GNUNET_NO;
4432 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4433 queue->idle = GNUNET_NO;
4434 if (0 == queue->q_capacity)
4435 queue->idle = GNUNET_NO;
4436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4437 "Sending message MID %llu of type %u (%u) and size %u with MQ %p\n",
4438 smt->mid,
4439 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
4440 ntohs (smt->header.size),
4441 payload_size,
4442 queue->tc->mq);
4443 GNUNET_MQ_send (queue->tc->mq, env);
4444 }
4445}
4446
4447
4448/**
4449 * Pick a queue of @a n under constraints @a options and schedule
4450 * transmission of @a hdr.
4451 *
4452 * @param n neighbour to send to
4453 * @param hdr message to send as payload
4454 * @param options whether queues must be confirmed or not,
4455 * and whether we may pick multiple (2) queues
4456 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4457 */
4458static struct GNUNET_TIME_Relative
4459route_via_neighbour (const struct Neighbour *n,
4460 const struct GNUNET_MessageHeader *hdr,
4461 enum RouteMessageOptions options)
4462{
4463 struct GNUNET_TIME_Absolute now;
4464 unsigned int candidates;
4465 unsigned int sel1;
4466 unsigned int sel2;
4467 struct GNUNET_TIME_Relative rtt;
4468
4469 /* Pick one or two 'random' queues from n (under constraints of options) */
4470 now = GNUNET_TIME_absolute_get ();
4471 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4472 weight in the future; weight could be assigned by observed
4473 bandwidth (note: not sure if we should do this for this type
4474 of control traffic though). */
4475 candidates = 0;
4476 for (struct Queue *pos = n->queue_head; NULL != pos;
4477 pos = pos->next_neighbour)
4478 {
4479 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4480 (pos->validated_until.abs_value_us > now.abs_value_us))
4481 candidates++;
4482 }
4483 if (0 == candidates)
4484 {
4485 /* This can happen rarely if the last confirmed queue timed
4486 out just as we were beginning to process this message. */
4487 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4488 "Could not route message of type %u to %s: no valid queue\n",
4489 ntohs (hdr->type),
4490 GNUNET_i2s (&n->pid));
4491 GNUNET_STATISTICS_update (GST_stats,
4492 "# route selection failed (all no valid queue)",
4493 1,
4494 GNUNET_NO);
4495 return GNUNET_TIME_UNIT_FOREVER_REL;
4496 }
4497
4498 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4499 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4500 if (0 == (options & RMO_REDUNDANT))
4501 sel2 = candidates; /* picks none! */
4502 else
4503 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4504 candidates = 0;
4505 for (struct Queue *pos = n->queue_head; NULL != pos;
4506 pos = pos->next_neighbour)
4507 {
4508 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4509 (pos->validated_until.abs_value_us > now.abs_value_us))
4510 {
4511 if ((sel1 == candidates) || (sel2 == candidates))
4512 {
4513 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4514 "Routing message of type %u to %s using %s (#%u)\n",
4515 ntohs (hdr->type),
4516 GNUNET_i2s (&n->pid),
4517 pos->address,
4518 (sel1 == candidates) ? 1 : 2);
4519 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4520 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4521 }
4522 candidates++;
4523 }
4524 }
4525 return rtt;
4526}
4527
4528
4529/**
4530 * Structure of the key material used to encrypt backchannel messages.
4531 */
4532struct DVKeyState
4533{
4534 /**
4535 * State of our block cipher.
4536 */
4537 gcry_cipher_hd_t cipher;
4538
4539 /**
4540 * Actual key material.
4541 */
4542 struct
4543 {
4544 /**
4545 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4546 */
4547 struct GNUNET_CRYPTO_AuthKey hmac_key;
4548
4549 /**
4550 * Symmetric key to use for encryption.
4551 */
4552 char aes_key[256 / 8];
4553
4554 /**
4555 * Counter value to use during setup.
4556 */
4557 char aes_ctr[128 / 8];
4558 } material;
4559};
4560
4561
4562/**
4563 * Given the key material in @a km and the initialization vector
4564 * @a iv, setup the key material for the backchannel in @a key.
4565 *
4566 * @param km raw master secret
4567 * @param iv initialization vector
4568 * @param key[out] symmetric cipher and HMAC state to generate
4569 */
4570static void
4571dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4572 const struct GNUNET_ShortHashCode *iv,
4573 struct DVKeyState *key)
4574{
4575 /* must match #dh_key_derive_eph_pub */
4576 GNUNET_assert (GNUNET_YES ==
4577 GNUNET_CRYPTO_kdf (&key->material,
4578 sizeof(key->material),
4579 "transport-backchannel-key",
4580 strlen ("transport-backchannel-key"),
4581 km,
4582 sizeof(*km),
4583 iv,
4584 sizeof(*iv),
4585 NULL));
4586 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4587 "Deriving backchannel key based on KM %s and IV %s\n",
4588 GNUNET_h2s (km),
4589 GNUNET_sh2s (iv));
4590 GNUNET_assert (0 == gcry_cipher_open (&key->cipher,
4591 GCRY_CIPHER_AES256 /* low level: go for speed */,
4592 GCRY_CIPHER_MODE_CTR,
4593 0 /* flags */));
4594 GNUNET_assert (0 == gcry_cipher_setkey (key->cipher,
4595 &key->material.aes_key,
4596 sizeof(key->material.aes_key)));
4597 gcry_cipher_setctr (key->cipher,
4598 &key->material.aes_ctr,
4599 sizeof(key->material.aes_ctr));
4600}
4601
4602
4603/**
4604 * Derive backchannel encryption key material from @a priv_ephemeral
4605 * and @a target and @a iv.
4606 *
4607 * @param priv_ephemeral ephemeral private key to use
4608 * @param target the target peer to encrypt to
4609 * @param iv unique IV to use
4610 * @param key[out] set to the key material
4611 */
4612static void
4613dh_key_derive_eph_pid (
4614 const struct GNUNET_CRYPTO_EcdhePrivateKey *priv_ephemeral,
4615 const struct GNUNET_PeerIdentity *target,
4616 const struct GNUNET_ShortHashCode *iv,
4617 struct DVKeyState *key)
4618{
4619 struct GNUNET_HashCode km;
4620
4621 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_ecdh_eddsa (priv_ephemeral,
4622 &target->public_key,
4623 &km));
4624 dv_setup_key_state_from_km (&km, iv, key);
4625}
4626
4627
4628/**
4629 * Derive backchannel encryption key material from #GST_my_private_key
4630 * and @a pub_ephemeral and @a iv.
4631 *
4632 * @param priv_ephemeral ephemeral private key to use
4633 * @param target the target peer to encrypt to
4634 * @param iv unique IV to use
4635 * @param key[out] set to the key material
4636 */
4637static void
4638dh_key_derive_eph_pub (const struct GNUNET_CRYPTO_EcdhePublicKey *pub_ephemeral,
4639 const struct GNUNET_ShortHashCode *iv,
4640 struct DVKeyState *key)
4641{
4642 struct GNUNET_HashCode km;
4643
4644 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_eddsa_ecdh (GST_my_private_key,
4645 pub_ephemeral,
4646 &km));
4647 dv_setup_key_state_from_km (&km, iv, key);
4648}
4649
4650
4651/**
4652 * Do HMAC calculation for backchannel messages over @a data using key
4653 * material from @a key.
4654 *
4655 * @param key key material (from DH)
4656 * @param hmac[out] set to the HMAC
4657 * @param data data to perform HMAC calculation over
4658 * @param data_size number of bytes in @a data
4659 */
4660static void
4661dv_hmac (const struct DVKeyState *key,
4662 struct GNUNET_HashCode *hmac,
4663 const void *data,
4664 size_t data_size)
4665{
4666 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4667}
4668
4669
4670/**
4671 * Perform backchannel encryption using symmetric secret in @a key
4672 * to encrypt data from @a in to @a dst.
4673 *
4674 * @param key[in,out] key material to use
4675 * @param dst where to write the result
4676 * @param in input data to encrypt (plaintext)
4677 * @param in_size number of bytes of input in @a in and available at @a dst
4678 */
4679static void
4680dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
4681{
4682 GNUNET_assert (0 ==
4683 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
4684}
4685
4686
4687/**
4688 * Perform backchannel encryption using symmetric secret in @a key
4689 * to encrypt data from @a in to @a dst.
4690 *
4691 * @param key[in,out] key material to use
4692 * @param ciph cipher text to decrypt
4693 * @param out[out] output data to generate (plaintext)
4694 * @param out_size number of bytes of input in @a ciph and available in @a out
4695 */
4696static void
4697dv_decrypt (struct DVKeyState *key,
4698 void *out,
4699 const void *ciph,
4700 size_t out_size)
4701{
4702 GNUNET_assert (
4703 0 == gcry_cipher_decrypt (key->cipher, out, out_size, ciph, out_size));
4704}
4705
4706
4707/**
4708 * Clean up key material in @a key.
4709 *
4710 * @param key key material to clean up (memory must not be free'd!)
4711 */
4712static void
4713dv_key_clean (struct DVKeyState *key)
4714{
4715 gcry_cipher_close (key->cipher);
4716 GNUNET_CRYPTO_zero_keys (&key->material, sizeof(key->material));
4717}
4718
4719
4720/**
4721 * Function to call to further operate on the now DV encapsulated
4722 * message @a hdr, forwarding it via @a next_hop under respect of
4723 * @a options.
4724 *
4725 * @param cls closure
4726 * @param next_hop next hop of the DV path
4727 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
4728 * @param options options of the original message
4729 */
4730typedef void (*DVMessageHandler) (void *cls,
4731 struct Neighbour *next_hop,
4732 const struct GNUNET_MessageHeader *hdr,
4733 enum RouteMessageOptions options);
4734
4735/**
4736 * Pick a path of @a dv under constraints @a options and schedule
4737 * transmission of @a hdr.
4738 *
4739 * @param target neighbour to ultimately send to
4740 * @param num_dvhs length of the @a dvhs array
4741 * @param dvhs array of hops to send the message to
4742 * @param hdr message to send as payload
4743 * @param use function to call with the encapsulated message
4744 * @param use_cls closure for @a use
4745 * @param options whether path must be confirmed or not, to be passed to @a use
4746 * @param shall this TransportDVBoxMessage be forwarded without flow control.
4747 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4748 */
4749static struct GNUNET_TIME_Relative
4750encapsulate_for_dv (struct DistanceVector *dv,
4751 unsigned int num_dvhs,
4752 struct DistanceVectorHop **dvhs,
4753 const struct GNUNET_MessageHeader *hdr,
4754 DVMessageHandler use,
4755 void *use_cls,
4756 enum RouteMessageOptions options,
4757 enum GNUNET_GenericReturnValue without_fc)
4758{
4759 struct TransportDVBoxMessage box_hdr;
4760 struct TransportDVBoxPayloadP payload_hdr;
4761 uint16_t enc_body_size = ntohs (hdr->size);
4762 char enc[sizeof(struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
4763 struct TransportDVBoxPayloadP *enc_payload_hdr =
4764 (struct TransportDVBoxPayloadP *) enc;
4765 struct DVKeyState *key;
4766 struct GNUNET_TIME_Relative rtt;
4767
4768 key = GNUNET_new (struct DVKeyState);
4769 /* Encrypt payload */
4770 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
4771 box_hdr.total_hops = htons (0);
4772 box_hdr.without_fc = htons (without_fc);
4773 update_ephemeral (dv);
4774 box_hdr.ephemeral_key = dv->ephemeral_key;
4775 payload_hdr.sender_sig = dv->sender_sig;
4776
4777 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
4778 &box_hdr.iv,
4779 sizeof(box_hdr.iv));
4780 dh_key_derive_eph_pid (&dv->private_key, &dv->target, &box_hdr.iv, key);
4781 payload_hdr.sender = GST_my_identity;
4782 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4783 dv_encrypt (key, &payload_hdr, enc_payload_hdr, sizeof(payload_hdr));
4784 dv_encrypt (key,
4785 hdr,
4786 &enc[sizeof(struct TransportDVBoxPayloadP)],
4787 enc_body_size);
4788 dv_hmac (key, &box_hdr.hmac, enc, sizeof(enc));
4789 dv_key_clean (key);
4790 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4791 /* For each selected path, take the pre-computed header and body
4792 and add the path in the middle of the message; then send it. */
4793 for (unsigned int i = 0; i < num_dvhs; i++)
4794 {
4795 struct DistanceVectorHop *dvh = dvhs[i];
4796 unsigned int num_hops = dvh->distance + 1;
4797 char buf[sizeof(struct TransportDVBoxMessage)
4798 + sizeof(struct GNUNET_PeerIdentity) * num_hops
4799 + sizeof(struct TransportDVBoxPayloadP)
4800 + enc_body_size] GNUNET_ALIGN;
4801 struct GNUNET_PeerIdentity *dhops;
4802
4803 box_hdr.header.size = htons (sizeof(buf));
4804 box_hdr.orig_size = htons (sizeof(buf));
4805 box_hdr.num_hops = htons (num_hops);
4806 memcpy (buf, &box_hdr, sizeof(box_hdr));
4807 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
4808 memcpy (dhops,
4809 dvh->path,
4810 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
4811 dhops[dvh->distance] = dv->target;
4812 if (GNUNET_EXTRA_LOGGING > 0)
4813 {
4814 char *path;
4815
4816 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
4817 for (unsigned int j = 0; j < num_hops; j++)
4818 {
4819 char *tmp;
4820
4821 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
4822 GNUNET_free (path);
4823 path = tmp;
4824 }
4825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4826 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
4827 ntohs (hdr->type),
4828 GNUNET_i2s (&dv->target),
4829 i + 1,
4830 num_dvhs,
4831 path);
4832 GNUNET_free (path);
4833 }
4834 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
4835 memcpy (&dhops[num_hops], enc, sizeof(enc));
4836 use (use_cls,
4837 dvh->next_hop,
4838 (const struct GNUNET_MessageHeader *) buf,
4839 options);
4840 GNUNET_free (key);
4841 }
4842 return rtt;
4843}
4844
4845
4846/**
4847 * Wrapper around #route_via_neighbour() that matches the
4848 * #DVMessageHandler structure.
4849 *
4850 * @param cls unused
4851 * @param next_hop where to send next
4852 * @param hdr header of the message to send
4853 * @param options message options for queue selection
4854 */
4855static void
4856send_dv_to_neighbour (void *cls,
4857 struct Neighbour *next_hop,
4858 const struct GNUNET_MessageHeader *hdr,
4859 enum RouteMessageOptions options)
4860{
4861 (void) cls;
4862 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
4863}
4864
4865
4866/**
4867 * We need to transmit @a hdr to @a target. If necessary, this may
4868 * involve DV routing. This function routes without applying flow
4869 * control or congestion control and should only be used for control
4870 * traffic.
4871 *
4872 * @param target peer to receive @a hdr
4873 * @param hdr header of the message to route and #GNUNET_free()
4874 * @param options which transmission channels are allowed
4875 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4876 */
4877static struct GNUNET_TIME_Relative
4878route_control_message_without_fc (struct VirtualLink *vl,
4879// route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
4880 const struct GNUNET_MessageHeader *hdr,
4881 enum RouteMessageOptions options)
4882{
4883 // struct VirtualLink *vl;
4884 struct Neighbour *n;
4885 struct DistanceVector *dv;
4886 struct GNUNET_TIME_Relative rtt1;
4887 struct GNUNET_TIME_Relative rtt2;
4888 const struct GNUNET_PeerIdentity *target = &vl->target;
4889
4890 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4891 "Trying to route message of type %u to %s without fc\n",
4892 ntohs (hdr->type),
4893 GNUNET_i2s (target));
4894
4895 // TODO Do this elsewhere. vl should be given as parameter to method.
4896 // vl = lookup_virtual_link (target);
4897 GNUNET_assert (NULL != vl && GNUNET_YES == vl->confirmed);
4898 if (NULL == vl)
4899 return GNUNET_TIME_UNIT_FOREVER_REL;
4900 n = vl->n;
4901 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
4902 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
4903 {
4904 /* if confirmed is required, and we do not have anything
4905 confirmed, drop respective options */
4906 if (NULL == n)
4907 n = lookup_neighbour (target);
4908 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
4909 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
4910 }
4911 if ((NULL == n) && (NULL == dv))
4912 {
4913 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4914 "Cannot route message of type %u to %s: no route\n",
4915 ntohs (hdr->type),
4916 GNUNET_i2s (target));
4917 GNUNET_STATISTICS_update (GST_stats,
4918 "# Messages dropped in routing: no acceptable method",
4919 1,
4920 GNUNET_NO);
4921 return GNUNET_TIME_UNIT_FOREVER_REL;
4922 }
4923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4924 "Routing message of type %u to %s with options %X\n",
4925 ntohs (hdr->type),
4926 GNUNET_i2s (target),
4927 (unsigned int) options);
4928 /* If both dv and n are possible and we must choose:
4929 flip a coin for the choice between the two; for now 50/50 */
4930 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
4931 {
4932 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
4933 n = NULL;
4934 else
4935 dv = NULL;
4936 }
4937 if ((NULL != n) && (NULL != dv))
4938 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
4939 enough for redundancy, so clear the flag. */
4940 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
4941 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
4942 if (NULL != n)
4943 {
4944 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4945 "Try to route message of type %u to %s without fc via neighbour\n",
4946 ntohs (hdr->type),
4947 GNUNET_i2s (target));
4948 rtt1 = route_via_neighbour (n, hdr, options);
4949 }
4950 if (NULL != dv)
4951 {
4952 struct DistanceVectorHop *hops[2];
4953 unsigned int res;
4954
4955 res = pick_random_dv_hops (dv,
4956 options,
4957 hops,
4958 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
4959 if (0 == res)
4960 {
4961 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4962 "Failed to route message, could not determine DV path\n");
4963 return rtt1;
4964 }
4965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4966 "encapsulate_for_dv 1\n");
4967 rtt2 = encapsulate_for_dv (dv,
4968 res,
4969 hops,
4970 hdr,
4971 &send_dv_to_neighbour,
4972 NULL,
4973 options & (~RMO_REDUNDANT),
4974 GNUNET_YES);
4975 }
4976 return GNUNET_TIME_relative_min (rtt1, rtt2);
4977}
4978
4979
4980static void
4981consider_sending_fc (void *cls);
4982
4983/**
4984 * Something changed on the virtual link with respect to flow
4985 * control. Consider retransmitting the FC window size.
4986 *
4987 * @param cls a `struct VirtualLink` to work with
4988 */
4989static void
4990task_consider_sending_fc (void *cls)
4991{
4992 struct VirtualLink *vl = cls;
4993 vl->fc_retransmit_task = NULL;
4994 consider_sending_fc (cls);
4995}
4996
4997
4998/**
4999 * Something changed on the virtual link with respect to flow
5000 * control. Consider retransmitting the FC window size.
5001 *
5002 * @param cls a `struct VirtualLink` to work with
5003 */
5004static void
5005consider_sending_fc (void *cls)
5006{
5007 struct VirtualLink *vl = cls;
5008 struct GNUNET_TIME_Absolute monotime;
5009 struct TransportFlowControlMessage fc;
5010 struct GNUNET_TIME_Relative duration;
5011 struct GNUNET_TIME_Relative rtt;
5012
5013 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
5014 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
5015 it always! */
5016 /* For example, we should probably ONLY do this if a bit more than
5017 an RTT has passed, or if the window changed "significantly" since
5018 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
5019 need an estimate for the bandwidth-delay-product for the entire
5020 VL, as that determines "significantly". We have the delay, but
5021 the bandwidth statistics need to be added for the VL!*/(void) duration;
5022
5023 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5024 "Sending FC seq %u to %s with new window %llu\n",
5025 (unsigned int) vl->fc_seq_gen,
5026 GNUNET_i2s (&vl->target),
5027 (unsigned long long) vl->incoming_fc_window_size);
5028 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
5029 vl->last_fc_transmission = monotime;
5030 fc.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
5031 fc.header.size = htons (sizeof(fc));
5032 fc.seq = htonl (vl->fc_seq_gen++);
5033 fc.inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size);
5034 fc.outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
5035 fc.outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
5036 fc.sender_time = GNUNET_TIME_absolute_hton (monotime);
5037 rtt = route_control_message_without_fc (vl, &fc.header, RMO_DV_ALLOWED);
5038 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
5039 {
5040 rtt = GNUNET_TIME_UNIT_SECONDS;
5041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5042 "FC retransmission to %s failed, will retry in %s\n",
5043 GNUNET_i2s (&vl->target),
5044 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
5045 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
5046 }
5047 else
5048 {
5049 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
5050 vl->last_fc_rtt = rtt;
5051 }
5052 if (NULL != vl->fc_retransmit_task)
5053 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
5054 if (MAX_FC_RETRANSMIT_COUNT == vl->fc_retransmit_count)
5055 {
5056 rtt = GNUNET_TIME_UNIT_MINUTES;
5057 vl->fc_retransmit_count = 0;
5058 }
5059 vl->fc_retransmit_task =
5060 GNUNET_SCHEDULER_add_delayed (rtt, &task_consider_sending_fc, vl);
5061 vl->fc_retransmit_count++;
5062}
5063
5064
5065/**
5066 * There is a message at the head of the pending messages for @a vl
5067 * which may be ready for transmission. Check if a queue is ready to
5068 * take it.
5069 *
5070 * This function must (1) check for flow control to ensure that we can
5071 * right now send to @a vl, (2) check that the pending message in the
5072 * queue is actually eligible, (3) determine if any applicable queue
5073 * (direct neighbour or DVH path) is ready to accept messages, and
5074 * (4) prioritize based on the preferences associated with the
5075 * pending message.
5076 *
5077 * So yeah, easy.
5078 *
5079 * @param vl virtual link where we should check for transmission
5080 */
5081static void
5082check_vl_transmission (struct VirtualLink *vl)
5083{
5084 struct Neighbour *n = vl->n;
5085 struct DistanceVector *dv = vl->dv;
5086 struct GNUNET_TIME_Absolute now;
5087 struct VirtualLink *vl_next_hop;
5088 int elig;
5089
5090 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5091 "check_vl_transmission to target %s\n",
5092 GNUNET_i2s (&vl->target));
5093 /* Check that we have an eligible pending message!
5094 (cheaper than having #transmit_on_queue() find out!) */
5095 elig = GNUNET_NO;
5096 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
5097 pm = pm->next_vl)
5098 {
5099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5100 "check_vl_transmission loop\n");
5101 if (NULL != pm->qe)
5102 continue; /* not eligible, is in a queue! */
5103 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
5104 vl->outbound_fc_window_size)
5105 {
5106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5107 "Stalled message %lu transmission on VL %s due to flow control: %llu < %llu\n",
5108 pm->logging_uuid,
5109 GNUNET_i2s (&vl->target),
5110 (unsigned long long) vl->outbound_fc_window_size,
5111 (unsigned long long) (pm->bytes_msg
5112 + vl->outbound_fc_window_size_used));
5113 consider_sending_fc (vl);
5114 return; /* We have a message, but flow control says "nope" */
5115 }
5116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5117 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
5118 GNUNET_i2s (&vl->target));
5119 /* Notify queues at direct neighbours that we are interested */
5120 now = GNUNET_TIME_absolute_get ();
5121 if (NULL != n)
5122 {
5123 for (struct Queue *queue = n->queue_head; NULL != queue;
5124 queue = queue->next_neighbour)
5125 {
5126 if ((GNUNET_YES == queue->idle) &&
5127 (queue->validated_until.abs_value_us > now.abs_value_us))
5128 {
5129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5130 "Direct neighbour %s not stalled\n",
5131 GNUNET_i2s (&n->pid));
5132 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5133 queue,
5134 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
5135 elig = GNUNET_YES;
5136 }
5137 else
5138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5139 "Neighbour Queue QID: %u (%u) busy or invalid\n",
5140 queue->qid,
5141 queue->idle);
5142 }
5143 }
5144 /* Notify queues via DV that we are interested */
5145 if (NULL != dv)
5146 {
5147 /* Do DV with lower scheduler priority, which effectively means that
5148 IF a neighbour exists and is available, we prefer it. */
5149 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5150 pos = pos->next_dv)
5151 {
5152 struct Neighbour *nh = pos->next_hop;
5153
5154
5155 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
5156 continue; /* skip this one: path not validated */
5157 else
5158 {
5159 vl_next_hop = lookup_virtual_link (&nh->pid);
5160 if (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
5161 vl_next_hop->outbound_fc_window_size)
5162 {
5163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5164 "Stalled message %lu transmission on next hop %s due to flow control: %llu < %llu\n",
5165 pm->logging_uuid,
5166 GNUNET_i2s (&vl_next_hop->target),
5167 (unsigned long
5168 long) vl_next_hop->outbound_fc_window_size,
5169 (unsigned long long) (pm->bytes_msg
5170 + vl_next_hop->
5171 outbound_fc_window_size_used));
5172 consider_sending_fc (vl_next_hop);
5173 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
5174 }
5175 for (struct Queue *queue = nh->queue_head; NULL != queue;
5176 queue = queue->next_neighbour)
5177 if ((GNUNET_YES == queue->idle) &&
5178 (queue->validated_until.abs_value_us > now.abs_value_us))
5179 {
5180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5181 "Next hop neighbour %s not stalled\n",
5182 GNUNET_i2s (&nh->pid));
5183 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5184 queue,
5185 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
5186 elig = GNUNET_YES;
5187 }
5188 else
5189 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5190 "DV Queue QID: %u (%u) busy or invalid\n",
5191 queue->qid,
5192 queue->idle);
5193 }
5194 }
5195 }
5196 if (GNUNET_YES == elig)
5197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5198 "Eligible message %lu of size %llu to %s: %llu/%llu\n",
5199 pm->logging_uuid,
5200 pm->bytes_msg,
5201 GNUNET_i2s (&vl->target),
5202 (unsigned long long) vl->outbound_fc_window_size,
5203 (unsigned long long) (pm->bytes_msg
5204 + vl->outbound_fc_window_size_used));
5205 break;
5206 }
5207}
5208
5209
5210/**
5211 * Client asked for transmission to a peer. Process the request.
5212 *
5213 * @param cls the client
5214 * @param obm the send message that was sent
5215 */
5216static void
5217handle_client_send (void *cls, const struct OutboundMessage *obm)
5218{
5219 struct TransportClient *tc = cls;
5220 struct PendingMessage *pm;
5221 const struct GNUNET_MessageHeader *obmm;
5222 uint32_t bytes_msg;
5223 struct VirtualLink *vl;
5224 enum GNUNET_MQ_PriorityPreferences pp;
5225
5226 GNUNET_assert (CT_CORE == tc->type);
5227 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5228 bytes_msg = ntohs (obmm->size);
5229 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
5230 vl = lookup_virtual_link (&obm->peer);
5231 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5232 {
5233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5234 "Don't have %s as a neighbour (anymore).\n",
5235 GNUNET_i2s (&obm->peer));
5236 /* Failure: don't have this peer as a neighbour (anymore).
5237 Might have gone down asynchronously, so this is NOT
5238 a protocol violation by CORE. Still count the event,
5239 as this should be rare. */
5240 GNUNET_SERVICE_client_continue (tc->client);
5241 GNUNET_STATISTICS_update (GST_stats,
5242 "# messages dropped (neighbour unknown)",
5243 1,
5244 GNUNET_NO);
5245 return;
5246 }
5247
5248 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
5249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5250 "1 created pm %p storing vl %p\n",
5251 pm,
5252 vl);
5253 pm->logging_uuid = logging_uuid_gen++;
5254 pm->prefs = pp;
5255 pm->client = tc;
5256 pm->vl = vl;
5257 pm->bytes_msg = bytes_msg;
5258 memcpy (&pm[1], obmm, bytes_msg);
5259 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5260 "Sending %u bytes as <%llu> to %s\n",
5261 bytes_msg,
5262 pm->logging_uuid,
5263 GNUNET_i2s (&obm->peer));
5264 GNUNET_CONTAINER_MDLL_insert (client,
5265 tc->details.core.pending_msg_head,
5266 tc->details.core.pending_msg_tail,
5267 pm);
5268 GNUNET_CONTAINER_MDLL_insert (vl,
5269 vl->pending_msg_head,
5270 vl->pending_msg_tail,
5271 pm);
5272 check_vl_transmission (vl);
5273 GNUNET_SERVICE_client_continue (tc->client);
5274}
5275
5276
5277/**
5278 * Communicator requests backchannel transmission. Process the request.
5279 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
5280 * (which for now has exactly the same format, only a different message type)
5281 * and passes it on for routing.
5282 *
5283 * @param cls the client
5284 * @param cb the send message that was sent
5285 */
5286static void
5287handle_communicator_backchannel (
5288 void *cls,
5289 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
5290{
5291 struct Neighbour *n;
5292 struct VirtualLink *vl;
5293 struct TransportClient *tc = cls;
5294 const struct GNUNET_MessageHeader *inbox =
5295 (const struct GNUNET_MessageHeader *) &cb[1];
5296 uint16_t isize = ntohs (inbox->size);
5297 const char *is = ((const char *) &cb[1]) + isize;
5298 size_t slen = strlen (is) + 1;
5299 char
5300 mbuf[slen + isize
5301 + sizeof(struct
5302 TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
5303 struct TransportBackchannelEncapsulationMessage *be =
5304 (struct TransportBackchannelEncapsulationMessage *) mbuf;
5305
5306 /* 0-termination of 'is' was checked already in
5307 #check_communicator_backchannel() */
5308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5309 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
5310 GNUNET_i2s (&cb->pid),
5311 is,
5312 ntohs (inbox->type),
5313 ntohs (inbox->size));
5314 /* encapsulate and encrypt message */
5315 be->header.type =
5316 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
5317 be->header.size = htons (sizeof(mbuf));
5318 memcpy (&be[1], inbox, isize);
5319 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
5320 + isize],
5321 is,
5322 strlen (is) + 1);
5323 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
5324 vl = lookup_virtual_link (&cb->pid);
5325 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
5326 {
5327 route_control_message_without_fc (vl, &be->header, RMO_DV_ALLOWED);
5328 }
5329 else
5330 {
5331 /* Use route via neighbour */
5332 n = lookup_neighbour (&cb->pid);
5333 if (NULL != n)
5334 route_via_neighbour (
5335 n,
5336 &be->header,
5337 RMO_NONE);
5338 }
5339 GNUNET_SERVICE_client_continue (tc->client);
5340}
5341
5342
5343/**
5344 * Address of our peer added. Test message is well-formed.
5345 *
5346 * @param cls the client
5347 * @param aam the send message that was sent
5348 * @return #GNUNET_OK if message is well-formed
5349 */
5350static int
5351check_add_address (void *cls,
5352 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5353{
5354 struct TransportClient *tc = cls;
5355
5356 if (CT_COMMUNICATOR != tc->type)
5357 {
5358 GNUNET_break (0);
5359 return GNUNET_SYSERR;
5360 }
5361 GNUNET_MQ_check_zero_termination (aam);
5362 return GNUNET_OK;
5363}
5364
5365
5366/**
5367 * Ask peerstore to store our address.
5368 *
5369 * @param cls an `struct AddressListEntry *`
5370 */
5371static void
5372store_pi (void *cls);
5373
5374
5375/**
5376 * Function called when peerstore is done storing our address.
5377 *
5378 * @param cls a `struct AddressListEntry`
5379 * @param success #GNUNET_YES if peerstore was successful
5380 */
5381static void
5382peerstore_store_own_cb (void *cls, int success)
5383{
5384 struct AddressListEntry *ale = cls;
5385
5386 ale->sc = NULL;
5387 if (GNUNET_YES != success)
5388 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5389 "Failed to store our own address `%s' in peerstore!\n",
5390 ale->address);
5391 else
5392 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5393 "Successfully stored our own address `%s' in peerstore!\n",
5394 ale->address);
5395 /* refresh period is 1/4 of expiration time, that should be plenty
5396 without being excessive. */
5397 ale->st =
5398 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5399 4ULL),
5400 &store_pi,
5401 ale);
5402}
5403
5404
5405/**
5406 * Ask peerstore to store our address.
5407 *
5408 * @param cls an `struct AddressListEntry *`
5409 */
5410static void
5411store_pi (void *cls)
5412{
5413 struct AddressListEntry *ale = cls;
5414 void *addr;
5415 size_t addr_len;
5416 struct GNUNET_TIME_Absolute expiration;
5417
5418 ale->st = NULL;
5419 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5420 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5421 "Storing our address `%s' in peerstore until %s!\n",
5422 ale->address,
5423 GNUNET_STRINGS_absolute_time_to_string (expiration));
5424 GNUNET_HELLO_sign_address (ale->address,
5425 ale->nt,
5426 hello_mono_time,
5427 GST_my_private_key,
5428 &addr,
5429 &addr_len);
5430 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5431 "transport",
5432 &GST_my_identity,
5433 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5434 addr,
5435 addr_len,
5436 expiration,
5437 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5438 &peerstore_store_own_cb,
5439 ale);
5440 GNUNET_free (addr);
5441 if (NULL == ale->sc)
5442 {
5443 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5444 "Failed to store our address `%s' with peerstore\n",
5445 ale->address);
5446 ale->st =
5447 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &store_pi, ale);
5448 }
5449}
5450
5451
5452/**
5453 * Address of our peer added. Process the request.
5454 *
5455 * @param cls the client
5456 * @param aam the send message that was sent
5457 */
5458static void
5459handle_add_address (void *cls,
5460 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5461{
5462 struct TransportClient *tc = cls;
5463 struct AddressListEntry *ale;
5464 size_t slen;
5465
5466 /* 0-termination of &aam[1] was checked in #check_add_address */
5467 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5468 "Communicator added address `%s'!\n",
5469 (const char *) &aam[1]);
5470 slen = ntohs (aam->header.size) - sizeof(*aam);
5471 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
5472 ale->tc = tc;
5473 ale->address = (const char *) &ale[1];
5474 ale->expiration = GNUNET_TIME_relative_ntoh (aam->expiration);
5475 ale->aid = aam->aid;
5476 ale->nt = (enum GNUNET_NetworkType) ntohl (aam->nt);
5477 memcpy (&ale[1], &aam[1], slen);
5478 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5479 tc->details.communicator.addr_tail,
5480 ale);
5481 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5482 GNUNET_SERVICE_client_continue (tc->client);
5483}
5484
5485
5486/**
5487 * Address of our peer deleted. Process the request.
5488 *
5489 * @param cls the client
5490 * @param dam the send message that was sent
5491 */
5492static void
5493handle_del_address (void *cls,
5494 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5495{
5496 struct TransportClient *tc = cls;
5497 struct AddressListEntry *alen;
5498
5499 if (CT_COMMUNICATOR != tc->type)
5500 {
5501 GNUNET_break (0);
5502 GNUNET_SERVICE_client_drop (tc->client);
5503 return;
5504 }
5505 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5506 NULL != ale;
5507 ale = alen)
5508 {
5509 alen = ale->next;
5510 if (dam->aid != ale->aid)
5511 continue;
5512 GNUNET_assert (ale->tc == tc);
5513 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5514 "Communicator deleted address `%s'!\n",
5515 ale->address);
5516 free_address_list_entry (ale);
5517 GNUNET_SERVICE_client_continue (tc->client);
5518 return;
5519 }
5520 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5521 "Communicator removed address we did not even have.\n");
5522 GNUNET_SERVICE_client_continue (tc->client);
5523 // GNUNET_SERVICE_client_drop (tc->client);
5524}
5525
5526
5527/**
5528 * Given an inbound message @a msg from a communicator @a cmc,
5529 * demultiplex it based on the type calling the right handler.
5530 *
5531 * @param cmc context for demultiplexing
5532 * @param msg message to demultiplex
5533 */
5534static void
5535demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
5536 const struct GNUNET_MessageHeader *msg);
5537
5538
5539/**
5540 * Function called when we are done giving a message of a certain
5541 * size to CORE and should thus decrement the number of bytes of
5542 * RAM reserved for that peer's MQ.
5543 *
5544 * @param cls a `struct CoreSentContext`
5545 */
5546static void
5547core_env_sent_cb (void *cls)
5548{
5549 struct CoreSentContext *ctx = cls;
5550 struct VirtualLink *vl = ctx->vl;
5551
5552 if (NULL == vl)
5553 {
5554 /* lost the link in the meantime, ignore */
5555 GNUNET_free (ctx);
5556 return;
5557 }
5558 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
5559 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
5560 vl->incoming_fc_window_size_ram -= ctx->size;
5561 vl->incoming_fc_window_size_used += ctx->isize;
5562 consider_sending_fc (vl);
5563 GNUNET_free (ctx);
5564}
5565
5566
5567/**
5568 * Communicator gave us an unencapsulated message to pass as-is to
5569 * CORE. Process the request.
5570 *
5571 * @param cls a `struct CommunicatorMessageContext` (must call
5572 * #finish_cmc_handling() when done)
5573 * @param mh the message that was received
5574 */
5575static void
5576handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
5577{
5578 struct CommunicatorMessageContext *cmc = cls;
5579 struct VirtualLink *vl;
5580 uint16_t size = ntohs (mh->size);
5581 int have_core;
5582
5583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5584 "Handling raw message of type %u with %u bytes\n",
5585 (unsigned int) ntohs (mh->type),
5586 (unsigned int) ntohs (mh->size));
5587
5588 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
5589 (size < sizeof(struct GNUNET_MessageHeader)))
5590 {
5591 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5592
5593 GNUNET_break (0);
5594 finish_cmc_handling (cmc);
5595 GNUNET_SERVICE_client_drop (client);
5596 return;
5597 }
5598 vl = lookup_virtual_link (&cmc->im.sender);
5599 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5600 {
5601 /* FIXME: sender is giving us messages for CORE but we don't have
5602 the link up yet! I *suspect* this can happen right now (i.e.
5603 sender has verified us, but we didn't verify sender), but if
5604 we pass this on, CORE would be confused (link down, messages
5605 arrive). We should investigate more if this happens often,
5606 or in a persistent manner, and possibly do "something" about
5607 it. Thus logging as error for now. */
5608 GNUNET_break_op (0);
5609 GNUNET_STATISTICS_update (GST_stats,
5610 "# CORE messages dropped (virtual link still down)",
5611 1,
5612 GNUNET_NO);
5613
5614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5615 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
5616 (unsigned int) ntohs (mh->type),
5617 (unsigned int) ntohs (mh->size));
5618 finish_cmc_handling (cmc);
5619 return;
5620 }
5621 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
5622 {
5623 GNUNET_STATISTICS_update (GST_stats,
5624 "# CORE messages dropped (FC arithmetic overflow)",
5625 1,
5626 GNUNET_NO);
5627 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5628 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
5629 (unsigned int) ntohs (mh->type),
5630 (unsigned int) ntohs (mh->size));
5631 finish_cmc_handling (cmc);
5632 return;
5633 }
5634 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
5635 {
5636 GNUNET_STATISTICS_update (GST_stats,
5637 "# CORE messages dropped (FC window overflow)",
5638 1,
5639 GNUNET_NO);
5640 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5641 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
5642 (unsigned int) ntohs (mh->type),
5643 (unsigned int) ntohs (mh->size));
5644 finish_cmc_handling (cmc);
5645 return;
5646 }
5647
5648 /* Forward to all CORE clients */
5649 have_core = GNUNET_NO;
5650 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
5651 {
5652 struct GNUNET_MQ_Envelope *env;
5653 struct InboundMessage *im;
5654 struct CoreSentContext *ctx;
5655
5656 if (CT_CORE != tc->type)
5657 continue;
5658 vl->incoming_fc_window_size_ram += size;
5659 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
5660 ctx = GNUNET_new (struct CoreSentContext);
5661 ctx->vl = vl;
5662 ctx->size = size;
5663 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
5664 have_core = GNUNET_YES;
5665 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
5666 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
5667 im->peer = cmc->im.sender;
5668 memcpy (&im[1], mh, size);
5669 GNUNET_MQ_send (tc->mq, env);
5670 vl->core_recv_window--;
5671 }
5672 if (GNUNET_NO == have_core)
5673 {
5674 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5675 "Dropped message to CORE: no CORE client connected!\n");
5676 /* Nevertheless, count window as used, as it is from the
5677 perspective of the other peer! */
5678 vl->incoming_fc_window_size_used += size;
5679 /* TODO-M1 */
5680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5681 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
5682 (unsigned int) ntohs (mh->type),
5683 (unsigned int) ntohs (mh->size));
5684 finish_cmc_handling (cmc);
5685 return;
5686 }
5687 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5688 "Delivered message from %s of type %u to CORE\n",
5689 GNUNET_i2s (&cmc->im.sender),
5690 ntohs (mh->type));
5691 if (vl->core_recv_window > 0)
5692 {
5693 finish_cmc_handling (cmc);
5694 return;
5695 }
5696 /* Wait with calling #finish_cmc_handling(cmc) until the message
5697 was processed by CORE MQs (for CORE flow control)! */
5698 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
5699}
5700
5701
5702/**
5703 * Communicator gave us a fragment box. Check the message.
5704 *
5705 * @param cls a `struct CommunicatorMessageContext`
5706 * @param fb the send message that was sent
5707 * @return #GNUNET_YES if message is well-formed
5708 */
5709static int
5710check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5711{
5712 uint16_t size = ntohs (fb->header.size);
5713 uint16_t bsize = size - sizeof(*fb);
5714
5715 (void) cls;
5716 if (0 == bsize)
5717 {
5718 GNUNET_break_op (0);
5719 return GNUNET_SYSERR;
5720 }
5721 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
5722 {
5723 GNUNET_break_op (0);
5724 return GNUNET_SYSERR;
5725 }
5726 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
5727 {
5728 GNUNET_break_op (0);
5729 return GNUNET_SYSERR;
5730 }
5731 return GNUNET_YES;
5732}
5733
5734
5735/**
5736 * Clean up an idle cumulative acknowledgement data structure.
5737 *
5738 * @param cls a `struct AcknowledgementCummulator *`
5739 */
5740static void
5741destroy_ack_cummulator (void *cls)
5742{
5743 struct AcknowledgementCummulator *ac = cls;
5744
5745 ac->task = NULL;
5746 GNUNET_assert (0 == ac->num_acks);
5747 GNUNET_assert (
5748 GNUNET_YES ==
5749 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
5750 GNUNET_free (ac);
5751}
5752
5753
5754/**
5755 * Do the transmission of a cumulative acknowledgement now.
5756 *
5757 * @param cls a `struct AcknowledgementCummulator *`
5758 */
5759static void
5760transmit_cummulative_ack_cb (void *cls)
5761{
5762 struct Neighbour *n;
5763 struct VirtualLink *vl;
5764 struct AcknowledgementCummulator *ac = cls;
5765 char buf[sizeof(struct TransportReliabilityAckMessage)
5766 + ac->num_acks
5767 * sizeof(struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
5768 struct TransportReliabilityAckMessage *ack =
5769 (struct TransportReliabilityAckMessage *) buf;
5770 struct TransportCummulativeAckPayloadP *ap;
5771
5772 ac->task = NULL;
5773 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5774 "Sending ACK with %u components to %s\n",
5775 ac->num_acks,
5776 GNUNET_i2s (&ac->target));
5777 GNUNET_assert (0 < ac->num_acks);
5778 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
5779 ack->header.size =
5780 htons (sizeof(*ack)
5781 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
5782 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
5783 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
5784 for (unsigned int i = 0; i < ac->num_acks; i++)
5785 {
5786 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
5787 ap[i].ack_delay = GNUNET_TIME_relative_hton (
5788 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
5789 }
5790 /*route_control_message_without_fc (
5791 &ac->target,
5792 &ack->header,
5793 RMO_DV_ALLOWED);*/
5794 vl = lookup_virtual_link (&ac->target);
5795 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
5796 {
5797 route_control_message_without_fc (
5798 vl,
5799 &ack->header,
5800 RMO_DV_ALLOWED);
5801 }
5802 else
5803 {
5804 /* Use route via neighbour */
5805 n = lookup_neighbour (&ac->target);
5806 if (NULL != n)
5807 route_via_neighbour (
5808 n,
5809 &ack->header,
5810 RMO_NONE);
5811 }
5812 ac->num_acks = 0;
5813 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
5814 &destroy_ack_cummulator,
5815 ac);
5816}
5817
5818
5819/**
5820 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
5821 * transmission by at most @a ack_delay.
5822 *
5823 * @param pid target peer
5824 * @param ack_uuid UUID to ack
5825 * @param max_delay how long can the ACK wait
5826 */
5827static void
5828cummulative_ack (const struct GNUNET_PeerIdentity *pid,
5829 const struct AcknowledgementUUIDP *ack_uuid,
5830 struct GNUNET_TIME_Absolute max_delay)
5831{
5832 struct AcknowledgementCummulator *ac;
5833
5834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5835 "Scheduling ACK %s for transmission to %s\n",
5836 GNUNET_uuid2s (&ack_uuid->value),
5837 GNUNET_i2s (pid));
5838 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
5839 if (NULL == ac)
5840 {
5841 ac = GNUNET_new (struct AcknowledgementCummulator);
5842 ac->target = *pid;
5843 ac->min_transmission_time = max_delay;
5844 GNUNET_assert (GNUNET_YES ==
5845 GNUNET_CONTAINER_multipeermap_put (
5846 ack_cummulators,
5847 &ac->target,
5848 ac,
5849 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
5850 }
5851 else
5852 {
5853 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
5854 {
5855 /* must run immediately, ack buffer full! */
5856 transmit_cummulative_ack_cb (ac);
5857 }
5858 GNUNET_SCHEDULER_cancel (ac->task);
5859 ac->min_transmission_time =
5860 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
5861 }
5862 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
5863 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
5864 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
5865 ac->num_acks++;
5866 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
5867 &transmit_cummulative_ack_cb,
5868 ac);
5869}
5870
5871
5872/**
5873 * Closure for #find_by_message_uuid.
5874 */
5875struct FindByMessageUuidContext
5876{
5877 /**
5878 * UUID to look for.
5879 */
5880 struct MessageUUIDP message_uuid;
5881
5882 /**
5883 * Set to the reassembly context if found.
5884 */
5885 struct ReassemblyContext *rc;
5886};
5887
5888
5889/**
5890 * Iterator called to find a reassembly context by the message UUID in the
5891 * multihashmap32.
5892 *
5893 * @param cls a `struct FindByMessageUuidContext`
5894 * @param key a key (unused)
5895 * @param value a `struct ReassemblyContext`
5896 * @return #GNUNET_YES if not found, #GNUNET_NO if found
5897 */
5898static int
5899find_by_message_uuid (void *cls, uint32_t key, void *value)
5900{
5901 struct FindByMessageUuidContext *fc = cls;
5902 struct ReassemblyContext *rc = value;
5903
5904 (void) key;
5905 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
5906 {
5907 fc->rc = rc;
5908 return GNUNET_NO;
5909 }
5910 return GNUNET_YES;
5911}
5912
5913
5914/**
5915 * Communicator gave us a fragment. Process the request.
5916 *
5917 * @param cls a `struct CommunicatorMessageContext` (must call
5918 * #finish_cmc_handling() when done)
5919 * @param fb the message that was received
5920 */
5921static void
5922handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
5923{
5924 struct CommunicatorMessageContext *cmc = cls;
5925 struct VirtualLink *vl;
5926 struct ReassemblyContext *rc;
5927 const struct GNUNET_MessageHeader *msg;
5928 uint16_t msize;
5929 uint16_t fsize;
5930 uint16_t frag_off;
5931 char *target;
5932 struct GNUNET_TIME_Relative cdelay;
5933 struct FindByMessageUuidContext fc;
5934
5935 vl = lookup_virtual_link (&cmc->im.sender);
5936 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5937 {
5938 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
5939
5940 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5941 "No virtual link for %s to handle fragment\n",
5942 GNUNET_i2s (&cmc->im.sender));
5943 GNUNET_break (0);
5944 finish_cmc_handling (cmc);
5945 GNUNET_SERVICE_client_drop (client);
5946 return;
5947 }
5948 if (NULL == vl->reassembly_map)
5949 {
5950 vl->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
5951 vl->reassembly_heap =
5952 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
5953 vl->reassembly_timeout_task =
5954 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
5955 &reassembly_cleanup_task,
5956 vl);
5957 }
5958 msize = ntohs (fb->msg_size);
5959 fc.message_uuid = fb->msg_uuid;
5960 fc.rc = NULL;
5961 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (vl->reassembly_map,
5962 fb->msg_uuid.uuid,
5963 &find_by_message_uuid,
5964 &fc);
5965 fsize = ntohs (fb->header.size) - sizeof(*fb);
5966 if (NULL == (rc = fc.rc))
5967 {
5968 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
5969 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
5970 rc->msg_uuid = fb->msg_uuid;
5971 rc->virtual_link = vl;
5972 rc->msg_size = msize;
5973 rc->reassembly_timeout =
5974 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
5975 rc->last_frag = GNUNET_TIME_absolute_get ();
5976 rc->hn = GNUNET_CONTAINER_heap_insert (vl->reassembly_heap,
5977 rc,
5978 rc->reassembly_timeout.abs_value_us);
5979 GNUNET_assert (GNUNET_OK ==
5980 GNUNET_CONTAINER_multihashmap32_put (
5981 vl->reassembly_map,
5982 rc->msg_uuid.uuid,
5983 rc,
5984 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
5985 target = (char *) &rc[1];
5986 rc->bitfield = (uint8_t *) (target + rc->msg_size);
5987 if (fsize != rc->msg_size)
5988 rc->msg_missing = rc->msg_size;
5989 else
5990 rc->msg_missing = 0;
5991 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5992 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %u\n",
5993 fsize,
5994 ntohs (fb->frag_off),
5995 msize,
5996 rc->msg_missing,
5997 GNUNET_i2s (&cmc->im.sender),
5998 (unsigned int) fb->msg_uuid.uuid);
5999 }
6000 else
6001 {
6002 target = (char *) &rc[1];
6003 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6004 "Received fragment at offset %u/%u from %s for message %u\n",
6005 ntohs (fb->frag_off),
6006 msize,
6007 GNUNET_i2s (&cmc->im.sender),
6008 (unsigned int) fb->msg_uuid.uuid);
6009 }
6010 if (msize != rc->msg_size)
6011 {
6012 GNUNET_break (0);
6013 finish_cmc_handling (cmc);
6014 return;
6015 }
6016
6017 /* reassemble */
6018 if (0 == fsize)
6019 {
6020 GNUNET_break (0);
6021 finish_cmc_handling (cmc);
6022 return;
6023 }
6024 frag_off = ntohs (fb->frag_off);
6025 if (frag_off + fsize > msize)
6026 {
6027 /* Fragment (plus fragment size) exceeds message size! */
6028 GNUNET_break_op (0);
6029 finish_cmc_handling (cmc);
6030 return;
6031 }
6032 memcpy (&target[frag_off], &fb[1], fsize);
6033 /* update bitfield and msg_missing */
6034 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
6035 {
6036 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
6037 {
6038 rc->bitfield[i / 8] |= (1 << (i % 8));
6039 rc->msg_missing--;
6040 }
6041 }
6042
6043 /* Compute cumulative ACK */
6044 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
6045 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
6046 if (0 == rc->msg_missing)
6047 cdelay = GNUNET_TIME_UNIT_ZERO;
6048 cummulative_ack (&cmc->im.sender,
6049 &fb->ack_uuid,
6050 GNUNET_TIME_relative_to_absolute (cdelay));
6051 rc->last_frag = GNUNET_TIME_absolute_get ();
6052 /* is reassembly complete? */
6053 if (0 != rc->msg_missing)
6054 {
6055 finish_cmc_handling (cmc);
6056 return;
6057 }
6058 /* reassembly is complete, verify result */
6059 msg = (const struct GNUNET_MessageHeader *) &rc[1];
6060 if (ntohs (msg->size) != rc->msg_size)
6061 {
6062 GNUNET_break (0);
6063 free_reassembly_context (rc);
6064 finish_cmc_handling (cmc);
6065 return;
6066 }
6067 /* successful reassembly */
6068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6069 "Fragment reassembly complete for message %u\n",
6070 (unsigned int) fb->msg_uuid.uuid);
6071 /* FIXME: check that the resulting msg is NOT a
6072 DV Box or Reliability Box, as that is NOT allowed! */
6073 demultiplex_with_cmc (cmc, msg);
6074 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
6075 en-route and we forget that we finished this reassembly immediately!
6076 -> keep around until timeout?
6077 -> shorten timeout based on ACK? */
6078 free_reassembly_context (rc);
6079}
6080
6081
6082/**
6083 * Communicator gave us a reliability box. Check the message.
6084 *
6085 * @param cls a `struct CommunicatorMessageContext`
6086 * @param rb the send message that was sent
6087 * @return #GNUNET_YES if message is well-formed
6088 */
6089static int
6090check_reliability_box (void *cls,
6091 const struct TransportReliabilityBoxMessage *rb)
6092{
6093 (void) cls;
6094 const struct GNUNET_MessageHeader *inbox = (const struct
6095 GNUNET_MessageHeader *) &rb[1];
6096
6097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6098 "check_send_msg with size %u: inner msg type %u and size %u (%u %u)\n",
6099 ntohs (rb->header.size),
6100 ntohs (inbox->type),
6101 ntohs (inbox->size),
6102 sizeof (struct TransportReliabilityBoxMessage),
6103 sizeof (struct GNUNET_MessageHeader));
6104 GNUNET_MQ_check_boxed_message (rb);
6105 return GNUNET_YES;
6106}
6107
6108
6109/**
6110 * Communicator gave us a reliability box. Process the request.
6111 *
6112 * @param cls a `struct CommunicatorMessageContext` (must call
6113 * #finish_cmc_handling() when done)
6114 * @param rb the message that was received
6115 */
6116static void
6117handle_reliability_box (void *cls,
6118 const struct TransportReliabilityBoxMessage *rb)
6119{
6120 struct CommunicatorMessageContext *cmc = cls;
6121 const struct GNUNET_MessageHeader *inbox =
6122 (const struct GNUNET_MessageHeader *) &rb[1];
6123 struct GNUNET_TIME_Relative rtt;
6124
6125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6126 "Received reliability box from %s with UUID %s of type %u\n",
6127 GNUNET_i2s (&cmc->im.sender),
6128 GNUNET_uuid2s (&rb->ack_uuid.value),
6129 (unsigned int) ntohs (inbox->type));
6130 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
6131 do not really have an RTT for the
6132 * incoming* queue (should we have
6133 the sender add it to the rb message?) */
6134 cummulative_ack (
6135 &cmc->im.sender,
6136 &rb->ack_uuid,
6137 (0 == ntohl (rb->ack_countdown))
6138 ? GNUNET_TIME_UNIT_ZERO_ABS
6139 : GNUNET_TIME_relative_to_absolute (
6140 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
6141 /* continue with inner message */
6142 /* FIXME: check that inbox is NOT a DV Box, fragment or another
6143 reliability box (not allowed!) */
6144 demultiplex_with_cmc (cmc, inbox);
6145}
6146
6147
6148/**
6149 * Check if we have advanced to another age since the last time. If
6150 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
6151 * the current age)
6152 *
6153 * @param pd[in,out] data to update
6154 * @param age current age
6155 */
6156static void
6157update_pd_age (struct PerformanceData *pd, unsigned int age)
6158{
6159 unsigned int sage;
6160
6161 if (age == pd->last_age)
6162 return; /* nothing to do */
6163 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
6164 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
6165 {
6166 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
6167
6168 the->bytes_sent = 0;
6169 the->bytes_received = 0;
6170 }
6171 pd->last_age = age;
6172}
6173
6174
6175/**
6176 * Update @a pd based on the latest @a rtt and the number of bytes
6177 * that were confirmed to be successfully transmitted.
6178 *
6179 * @param pd[in,out] data to update
6180 * @param rtt latest round-trip time
6181 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
6182 */
6183static void
6184update_performance_data (struct PerformanceData *pd,
6185 struct GNUNET_TIME_Relative rtt,
6186 uint16_t bytes_transmitted_ok)
6187{
6188 uint64_t nval = rtt.rel_value_us;
6189 uint64_t oval = pd->aged_rtt.rel_value_us;
6190 unsigned int age = get_age ();
6191 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
6192
6193 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
6194 pd->aged_rtt = rtt;
6195 else
6196 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
6197 update_pd_age (pd, age);
6198 the->bytes_received += bytes_transmitted_ok;
6199}
6200
6201
6202/**
6203 * We have successfully transmitted data via @a q, update metrics.
6204 *
6205 * @param q queue to update
6206 * @param rtt round trip time observed
6207 * @param bytes_transmitted_ok number of bytes successfully transmitted
6208 */
6209static void
6210update_queue_performance (struct Queue *q,
6211 struct GNUNET_TIME_Relative rtt,
6212 uint16_t bytes_transmitted_ok)
6213{
6214 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
6215}
6216
6217
6218/**
6219 * We have successfully transmitted data via @a dvh, update metrics.
6220 *
6221 * @param dvh distance vector path data to update
6222 * @param rtt round trip time observed
6223 * @param bytes_transmitted_ok number of bytes successfully transmitted
6224 */
6225static void
6226update_dvh_performance (struct DistanceVectorHop *dvh,
6227 struct GNUNET_TIME_Relative rtt,
6228 uint16_t bytes_transmitted_ok)
6229{
6230 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
6231}
6232
6233
6234/**
6235 * We have completed transmission of @a pm, remove it from
6236 * the transmission queues (and if it is a fragment, continue
6237 * up the tree as necessary).
6238 *
6239 * @param pm pending message that was transmitted
6240 */
6241static void
6242completed_pending_message (struct PendingMessage *pm)
6243{
6244 struct PendingMessage *pos;
6245
6246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6247 "Complete transmission of message %llu %u\n",
6248 pm->logging_uuid,
6249 pm->pmt);
6250 switch (pm->pmt)
6251 {
6252 case PMT_CORE:
6253 case PMT_RELIABILITY_BOX:
6254 /* Full message sent, we are done */
6255 client_send_response (pm);
6256 return;
6257
6258 case PMT_FRAGMENT_BOX:
6259 /* Fragment sent over reliable channel */
6260 pos = pm->frag_parent;
6261 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6262 free_pending_message (pm);
6263 /* check if subtree is done */
6264 while ((NULL == pos->head_frag) && (pos->frag_off == pos->bytes_msg) &&
6265 (NULL != pos->frag_parent))
6266 {
6267 pm = pos;
6268 pos = pm->frag_parent;
6269 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
6270 {
6271 client_send_response (pm);
6272 return;
6273 }
6274 else if (PMT_DV_BOX == pm->pmt)
6275 {
6276 client_send_response (pos);
6277 return;
6278 }
6279 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6280 free_pending_message (pm);
6281 }
6282
6283 /* Was this the last applicable fragment? */
6284 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent) &&
6285 (pos->frag_off == pos->bytes_msg))
6286 client_send_response (pos);
6287 return;
6288
6289 case PMT_DV_BOX:
6290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6291 "Completed transmission of message %llu (DV Box)\n",
6292 pm->logging_uuid);
6293 if (NULL != pm->frag_parent)
6294 {
6295 if (NULL != pm->bpm)
6296 {
6297 GNUNET_free (pm->bpm);
6298 }
6299 client_send_response (pm->frag_parent);
6300 }
6301 else
6302 client_send_response (pm);
6303 return;
6304 }
6305}
6306
6307
6308/**
6309 * The @a pa was acknowledged, process the acknowledgement.
6310 *
6311 * @param pa the pending acknowledgement that was satisfied
6312 * @param ack_delay artificial delay from cumulative acks created by the
6313 * other peer
6314 */
6315static void
6316handle_acknowledged (struct PendingAcknowledgement *pa,
6317 struct GNUNET_TIME_Relative ack_delay)
6318{
6319 struct GNUNET_TIME_Relative delay;
6320
6321 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
6322 if (delay.rel_value_us > ack_delay.rel_value_us)
6323 delay = GNUNET_TIME_UNIT_ZERO;
6324 else
6325 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
6326 if (NULL != pa->queue)
6327 update_queue_performance (pa->queue, delay, pa->message_size);
6328 if (NULL != pa->dvh)
6329 update_dvh_performance (pa->dvh, delay, pa->message_size);
6330 if (NULL != pa->pm)
6331 completed_pending_message (pa->pm);
6332 free_pending_acknowledgement (pa);
6333}
6334
6335
6336/**
6337 * Communicator gave us a reliability ack. Check it is well-formed.
6338 *
6339 * @param cls a `struct CommunicatorMessageContext` (unused)
6340 * @param ra the message that was received
6341 * @return #GNUNET_Ok if @a ra is well-formed
6342 */
6343static int
6344check_reliability_ack (void *cls,
6345 const struct TransportReliabilityAckMessage *ra)
6346{
6347 unsigned int n_acks;
6348
6349 (void) cls;
6350 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6351 / sizeof(struct TransportCummulativeAckPayloadP);
6352 if (0 == n_acks)
6353 {
6354 GNUNET_break_op (0);
6355 return GNUNET_SYSERR;
6356 }
6357 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
6358 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
6359 {
6360 GNUNET_break_op (0);
6361 return GNUNET_SYSERR;
6362 }
6363 return GNUNET_OK;
6364}
6365
6366
6367/**
6368 * Communicator gave us a reliability ack. Process the request.
6369 *
6370 * @param cls a `struct CommunicatorMessageContext` (must call
6371 * #finish_cmc_handling() when done)
6372 * @param ra the message that was received
6373 */
6374static void
6375handle_reliability_ack (void *cls,
6376 const struct TransportReliabilityAckMessage *ra)
6377{
6378 struct CommunicatorMessageContext *cmc = cls;
6379 const struct TransportCummulativeAckPayloadP *ack;
6380 unsigned int n_acks;
6381 uint32_t ack_counter;
6382
6383 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6384 / sizeof(struct TransportCummulativeAckPayloadP);
6385 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
6386 for (unsigned int i = 0; i < n_acks; i++)
6387 {
6388 struct PendingAcknowledgement *pa =
6389 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
6390 if (NULL == pa)
6391 {
6392 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6393 "Received ACK from %s with UUID %s which is unknown to us!\n",
6394 GNUNET_i2s (&cmc->im.sender),
6395 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6396 GNUNET_STATISTICS_update (
6397 GST_stats,
6398 "# FRAGMENT_ACKS dropped, no matching pending message",
6399 1,
6400 GNUNET_NO);
6401 continue;
6402 }
6403 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6404 "Received ACK from %s with UUID %s\n",
6405 GNUNET_i2s (&cmc->im.sender),
6406 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6407 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
6408 }
6409
6410 ack_counter = htonl (ra->ack_counter);
6411 (void) ack_counter; /* silence compiler warning for now */
6412 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
6413 // (DV and/or Neighbour?)
6414 finish_cmc_handling (cmc);
6415}
6416
6417
6418/**
6419 * Communicator gave us a backchannel encapsulation. Check the message.
6420 *
6421 * @param cls a `struct CommunicatorMessageContext`
6422 * @param be the send message that was sent
6423 * @return #GNUNET_YES if message is well-formed
6424 */
6425static int
6426check_backchannel_encapsulation (
6427 void *cls,
6428 const struct TransportBackchannelEncapsulationMessage *be)
6429{
6430 uint16_t size = ntohs (be->header.size) - sizeof(*be);
6431 const struct GNUNET_MessageHeader *inbox =
6432 (const struct GNUNET_MessageHeader *) &be[1];
6433 const char *is;
6434 uint16_t isize;
6435
6436 (void) cls;
6437 if (ntohs (inbox->size) >= size)
6438 {
6439 GNUNET_break_op (0);
6440 return GNUNET_SYSERR;
6441 }
6442 isize = ntohs (inbox->size);
6443 is = ((const char *) inbox) + isize;
6444 size -= isize;
6445 if ('\0' != is[size - 1])
6446 {
6447 GNUNET_break_op (0);
6448 return GNUNET_SYSERR;
6449 }
6450 return GNUNET_YES;
6451}
6452
6453
6454/**
6455 * Communicator gave us a backchannel encapsulation. Process the request.
6456 * (We are the destination of the backchannel here.)
6457 *
6458 * @param cls a `struct CommunicatorMessageContext` (must call
6459 * #finish_cmc_handling() when done)
6460 * @param be the message that was received
6461 */
6462static void
6463handle_backchannel_encapsulation (
6464 void *cls,
6465 const struct TransportBackchannelEncapsulationMessage *be)
6466{
6467 struct CommunicatorMessageContext *cmc = cls;
6468 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
6469 struct GNUNET_MQ_Envelope *env;
6470 struct TransportClient *tc;
6471 const struct GNUNET_MessageHeader *inbox =
6472 (const struct GNUNET_MessageHeader *) &be[1];
6473 uint16_t isize = ntohs (inbox->size);
6474 const char *target_communicator = ((const char *) inbox) + isize;
6475 char *sender;
6476 char *self;
6477
6478 GNUNET_asprintf (&sender,
6479 "%s",
6480 GNUNET_i2s (&cmc->im.sender));
6481 GNUNET_asprintf (&self,
6482 "%s",
6483 GNUNET_i2s (&GST_my_identity));
6484
6485 /* Find client providing this communicator */
6486 for (tc = clients_head; NULL != tc; tc = tc->next)
6487 if ((CT_COMMUNICATOR == tc->type) &&
6488 (0 ==
6489 strcmp (tc->details.communicator.address_prefix, target_communicator)))
6490 break;
6491 if (NULL == tc)
6492 {
6493 char *stastr;
6494
6495 GNUNET_asprintf (
6496 &stastr,
6497 "# Backchannel message dropped: target communicator `%s' unknown",
6498 target_communicator);
6499 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
6500 GNUNET_free (stastr);
6501 finish_cmc_handling (cmc);
6502 return;
6503 }
6504 /* Finally, deliver backchannel message to communicator */
6505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6506 "Delivering backchannel message from %s to %s of type %u to %s\n",
6507 sender,
6508 self,
6509 ntohs (inbox->type),
6510 target_communicator);
6511 env = GNUNET_MQ_msg_extra (
6512 cbi,
6513 isize,
6514 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
6515 cbi->pid = cmc->im.sender;
6516 memcpy (&cbi[1], inbox, isize);
6517 GNUNET_MQ_send (tc->mq, env);
6518 finish_cmc_handling (cmc);
6519}
6520
6521
6522/**
6523 * Task called when we should check if any of the DV paths
6524 * we have learned to a target are due for garbage collection.
6525 *
6526 * Collects stale paths, and possibly frees the entire DV
6527 * entry if no paths are left. Otherwise re-schedules itself.
6528 *
6529 * @param cls a `struct DistanceVector`
6530 */
6531static void
6532path_cleanup_cb (void *cls)
6533{
6534 struct DistanceVector *dv = cls;
6535 struct DistanceVectorHop *pos;
6536
6537 dv->timeout_task = NULL;
6538 while (NULL != (pos = dv->dv_head))
6539 {
6540 GNUNET_assert (dv == pos->dv);
6541 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
6542 break;
6543 free_distance_vector_hop (pos);
6544 }
6545 if (NULL == pos)
6546 {
6547 free_dv_route (dv);
6548 return;
6549 }
6550 dv->timeout_task =
6551 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
6552}
6553
6554
6555/**
6556 * The @a hop is a validated path to the respective target
6557 * peer and we should tell core about it -- and schedule
6558 * a job to revoke the state.
6559 *
6560 * @param hop a path to some peer that is the reason for activation
6561 */
6562static void
6563activate_core_visible_dv_path (struct DistanceVectorHop *hop)
6564{
6565 struct DistanceVector *dv = hop->dv;
6566 struct VirtualLink *vl;
6567
6568 vl = lookup_virtual_link (&dv->target);
6569 if (NULL == vl)
6570 {
6571
6572 vl = GNUNET_new (struct VirtualLink);
6573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6574 "Creating new virtual link %p to %s using DV!\n",
6575 vl,
6576 GNUNET_i2s (&dv->target));
6577 vl->confirmed = GNUNET_YES;
6578 vl->message_uuid_ctr =
6579 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
6580 vl->target = dv->target;
6581 vl->core_recv_window = RECV_WINDOW_SIZE;
6582 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
6583 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
6584 GNUNET_break (GNUNET_YES ==
6585 GNUNET_CONTAINER_multipeermap_put (
6586 links,
6587 &vl->target,
6588 vl,
6589 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6590 vl->dv = dv;
6591 dv->vl = vl;
6592 vl->visibility_task =
6593 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6594 consider_sending_fc (vl);
6595 /* We lacked a confirmed connection to the target
6596 before, so tell CORE about it (finally!) */
6597 cores_send_connect_info (&dv->target);
6598 }
6599 else
6600 {
6601 /* Link was already up, remember dv is also now available and we are done */
6602 vl->dv = dv;
6603 dv->vl = vl;
6604 if (GNUNET_NO == vl->confirmed)
6605 {
6606 vl->confirmed = GNUNET_YES;
6607 vl->visibility_task =
6608 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
6609 consider_sending_fc (vl);
6610 /* We lacked a confirmed connection to the target
6611 before, so tell CORE about it (finally!) */
6612 cores_send_connect_info (&dv->target);
6613 }
6614 else
6615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6616 "Virtual link to %s could now also use DV!\n",
6617 GNUNET_i2s (&dv->target));
6618 }
6619}
6620
6621
6622/**
6623 * We have learned a @a path through the network to some other peer, add it to
6624 * our DV data structure (returning #GNUNET_YES on success).
6625 *
6626 * We do not add paths if we have a sufficient number of shorter
6627 * paths to this target already (returning #GNUNET_NO).
6628 *
6629 * We also do not add problematic paths, like those where we lack the first
6630 * hop in our neighbour list (i.e. due to a topology change) or where some
6631 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
6632 *
6633 * @param path the path we learned, path[0] should be us,
6634 * and then path contains a valid path from us to
6635 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
6636 * @param path_len number of entries on the @a path, at least three!
6637 * @param network_latency how long does the message take from us to
6638 * `path[path_len-1]`? set to "forever" if unknown
6639 * @param path_valid_until how long is this path considered validated? Maybe
6640 * be zero.
6641 * @return #GNUNET_YES on success,
6642 * #GNUNET_NO if we have better path(s) to the target
6643 * #GNUNET_SYSERR if the path is useless and/or invalid
6644 * (i.e. path[1] not a direct neighbour
6645 * or path[i+1] is a direct neighbour for i>0)
6646 */
6647static int
6648learn_dv_path (const struct GNUNET_PeerIdentity *path,
6649 unsigned int path_len,
6650 struct GNUNET_TIME_Relative network_latency,
6651 struct GNUNET_TIME_Absolute path_valid_until)
6652{
6653 struct DistanceVectorHop *hop;
6654 struct DistanceVector *dv;
6655 struct Neighbour *next_hop;
6656 unsigned int shorter_distance;
6657
6658 if (path_len < 3)
6659 {
6660 /* what a boring path! not allowed! */
6661 GNUNET_break (0);
6662 return GNUNET_SYSERR;
6663 }
6664 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
6665 next_hop = lookup_neighbour (&path[1]);
6666 if (NULL == next_hop)
6667 {
6668 /* next hop must be a neighbour, otherwise this whole thing is useless! */
6669 GNUNET_break (0);
6670 return GNUNET_SYSERR;
6671 }
6672 for (unsigned int i = 2; i < path_len; i++)
6673 if (NULL != lookup_neighbour (&path[i]))
6674 {
6675 /* Useless path: we have a direct connection to some hop
6676 in the middle of the path, so this one is not even
6677 terribly useful for redundancy */
6678 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6679 "Path of %u hops useless: directly link to hop %u (%s)\n",
6680 path_len,
6681 i,
6682 GNUNET_i2s (&path[i]));
6683 GNUNET_STATISTICS_update (GST_stats,
6684 "# Useless DV path ignored: hop is neighbour",
6685 1,
6686 GNUNET_NO);
6687 return GNUNET_SYSERR;
6688 }
6689 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
6690 if (NULL == dv)
6691 {
6692 dv = GNUNET_new (struct DistanceVector);
6693 dv->target = path[path_len - 1];
6694 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
6695 &path_cleanup_cb,
6696 dv);
6697 GNUNET_assert (GNUNET_OK ==
6698 GNUNET_CONTAINER_multipeermap_put (
6699 dv_routes,
6700 &dv->target,
6701 dv,
6702 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6703 }
6704 /* Check if we have this path already! */
6705 shorter_distance = 0;
6706 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
6707 pos = pos->next_dv)
6708 {
6709 if (pos->distance < path_len - 3)
6710 shorter_distance++;
6711 /* Note that the distances in 'pos' excludes us (path[0]),
6712 the next_hop (path[1]) and the target so we need to subtract three
6713 and check next_hop explicitly */
6714 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
6715 {
6716 int match = GNUNET_YES;
6717
6718 for (unsigned int i = 0; i < pos->distance; i++)
6719 {
6720 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
6721 {
6722 match = GNUNET_NO;
6723 break;
6724 }
6725 }
6726 if (GNUNET_YES == match)
6727 {
6728 struct GNUNET_TIME_Relative last_timeout;
6729
6730 /* Re-discovered known path, update timeout */
6731 GNUNET_STATISTICS_update (GST_stats,
6732 "# Known DV path refreshed",
6733 1,
6734 GNUNET_NO);
6735 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
6736 pos->timeout =
6737 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6738 pos->path_valid_until =
6739 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
6740 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
6741 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
6742 if (0 <
6743 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6744 activate_core_visible_dv_path (pos);
6745 if (last_timeout.rel_value_us <
6746 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
6747 DV_PATH_DISCOVERY_FREQUENCY)
6748 .rel_value_us)
6749 {
6750 /* Some peer send DV learn messages too often, we are learning
6751 the same path faster than it would be useful; do not forward! */
6752 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6753 "Rediscovered path too quickly, not forwarding further\n");
6754 return GNUNET_NO;
6755 }
6756 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6757 "Refreshed known path to %s valid until %s, forwarding further\n",
6758 GNUNET_i2s (&dv->target),
6759 GNUNET_STRINGS_absolute_time_to_string (
6760 pos->path_valid_until));
6761 return GNUNET_YES;
6762 }
6763 }
6764 }
6765 /* Count how many shorter paths we have (incl. direct
6766 neighbours) before simply giving up on this one! */
6767 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
6768 {
6769 /* We have a shorter path already! */
6770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6771 "Have many shorter DV paths %s, not forwarding further\n",
6772 GNUNET_i2s (&dv->target));
6773 return GNUNET_NO;
6774 }
6775 /* create new DV path entry */
6776 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6777 "Discovered new DV path to %s valid until %s\n",
6778 GNUNET_i2s (&dv->target),
6779 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
6780 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
6781 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
6782 hop->next_hop = next_hop;
6783 hop->dv = dv;
6784 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
6785 memcpy (&hop[1],
6786 &path[2],
6787 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
6788 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
6789 hop->path_valid_until = path_valid_until;
6790 hop->distance = path_len - 3;
6791 hop->pd.aged_rtt = network_latency;
6792 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
6793 GNUNET_CONTAINER_MDLL_insert (neighbour,
6794 next_hop->dv_head,
6795 next_hop->dv_tail,
6796 hop);
6797 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
6798 activate_core_visible_dv_path (hop);
6799 return GNUNET_YES;
6800}
6801
6802
6803/**
6804 * Communicator gave us a DV learn message. Check the message.
6805 *
6806 * @param cls a `struct CommunicatorMessageContext`
6807 * @param dvl the send message that was sent
6808 * @return #GNUNET_YES if message is well-formed
6809 */
6810static int
6811check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
6812{
6813 uint16_t size = ntohs (dvl->header.size);
6814 uint16_t num_hops = ntohs (dvl->num_hops);
6815 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
6816
6817 (void) cls;
6818 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
6819 {
6820 GNUNET_break_op (0);
6821 return GNUNET_SYSERR;
6822 }
6823 if (num_hops > MAX_DV_HOPS_ALLOWED)
6824 {
6825 GNUNET_break_op (0);
6826 return GNUNET_SYSERR;
6827 }
6828 for (unsigned int i = 0; i < num_hops; i++)
6829 {
6830 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
6831 {
6832 GNUNET_break_op (0);
6833 return GNUNET_SYSERR;
6834 }
6835 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
6836 {
6837 GNUNET_break_op (0);
6838 return GNUNET_SYSERR;
6839 }
6840 }
6841 return GNUNET_YES;
6842}
6843
6844
6845/**
6846 * Build and forward a DV learn message to @a next_hop.
6847 *
6848 * @param next_hop peer to send the message to
6849 * @param msg message received
6850 * @param bi_history bitmask specifying hops on path that were bidirectional
6851 * @param nhops length of the @a hops array
6852 * @param hops path the message traversed so far
6853 * @param in_time when did we receive the message, used to calculate network
6854 * delay
6855 */
6856static void
6857forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
6858 const struct TransportDVLearnMessage *msg,
6859 uint16_t bi_history,
6860 uint16_t nhops,
6861 const struct DVPathEntryP *hops,
6862 struct GNUNET_TIME_Absolute in_time)
6863{
6864 struct Neighbour *n;
6865 struct VirtualLink *vl;
6866 struct DVPathEntryP *dhops;
6867 char buf[sizeof(struct TransportDVLearnMessage)
6868 + (nhops + 1) * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
6869 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
6870 struct GNUNET_TIME_Relative nnd;
6871
6872 /* compute message for forwarding */
6873 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6874 "Forwarding DV learn message originating from %s to %s\n",
6875 GNUNET_i2s (&msg->initiator),
6876 GNUNET_i2s2 (next_hop));
6877 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
6878 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
6879 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
6880 + (nhops + 1) * sizeof(struct DVPathEntryP));
6881 fwd->num_hops = htons (nhops + 1);
6882 fwd->bidirectional = htons (bi_history);
6883 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
6884 GNUNET_TIME_relative_ntoh (
6885 msg->non_network_delay));
6886 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
6887 fwd->init_sig = msg->init_sig;
6888 fwd->initiator = msg->initiator;
6889 fwd->challenge = msg->challenge;
6890 fwd->monotonic_time = msg->monotonic_time;
6891 dhops = (struct DVPathEntryP *) &fwd[1];
6892 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
6893 dhops[nhops].hop = GST_my_identity;
6894 {
6895 struct DvHopPS dhp = {
6896 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
6897 .purpose.size = htonl (sizeof(dhp)),
6898 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
6899 .succ = *next_hop,
6900 .challenge = msg->challenge
6901 };
6902 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
6903 &dhp,
6904 &dhops[nhops].hop_sig);
6905 }
6906 /*route_control_message_without_fc (next_hop,
6907 &fwd->header,
6908 RMO_UNCONFIRMED_ALLOWED);*/
6909 vl = lookup_virtual_link (next_hop);
6910 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6911 {
6912 route_control_message_without_fc (vl,
6913 &fwd->header,
6914 RMO_UNCONFIRMED_ALLOWED);
6915 }
6916 else
6917 {
6918 /* Use route via neighbour */
6919 n = lookup_neighbour (next_hop);
6920 if (NULL != n)
6921 route_via_neighbour (
6922 n,
6923 &fwd->header,
6924 RMO_UNCONFIRMED_ALLOWED);
6925 }
6926}
6927
6928
6929/**
6930 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
6931 *
6932 * @param sender_monotonic_time monotonic time of the initiator
6933 * @param init the signer
6934 * @param challenge the challenge that was signed
6935 * @param init_sig signature presumably by @a init
6936 * @return #GNUNET_OK if the signature is valid
6937 */
6938static int
6939validate_dv_initiator_signature (
6940 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
6941 const struct GNUNET_PeerIdentity *init,
6942 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge,
6943 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
6944{
6945 struct DvInitPS ip = { .purpose.purpose = htonl (
6946 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
6947 .purpose.size = htonl (sizeof(ip)),
6948 .monotonic_time = sender_monotonic_time,
6949 .challenge = *challenge };
6950
6951 if (
6952 GNUNET_OK !=
6953 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
6954 &ip,
6955 init_sig,
6956 &init->public_key))
6957 {
6958 GNUNET_break_op (0);
6959 return GNUNET_SYSERR;
6960 }
6961 return GNUNET_OK;
6962}
6963
6964
6965/**
6966 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
6967 */
6968struct NeighbourSelectionContext
6969{
6970 /**
6971 * Original message we received.
6972 */
6973 const struct TransportDVLearnMessage *dvl;
6974
6975 /**
6976 * The hops taken.
6977 */
6978 const struct DVPathEntryP *hops;
6979
6980 /**
6981 * Time we received the message.
6982 */
6983 struct GNUNET_TIME_Absolute in_time;
6984
6985 /**
6986 * Offsets of the selected peers.
6987 */
6988 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
6989
6990 /**
6991 * Number of peers eligible for selection.
6992 */
6993 unsigned int num_eligible;
6994
6995 /**
6996 * Number of peers that were selected for forwarding.
6997 */
6998 unsigned int num_selections;
6999
7000 /**
7001 * Number of hops in @e hops
7002 */
7003 uint16_t nhops;
7004
7005 /**
7006 * Bitmap of bidirectional connections encountered.
7007 */
7008 uint16_t bi_history;
7009};
7010
7011
7012/**
7013 * Function called for each neighbour during #handle_dv_learn.
7014 *
7015 * @param cls a `struct NeighbourSelectionContext *`
7016 * @param pid identity of the peer
7017 * @param value a `struct Neighbour`
7018 * @return #GNUNET_YES (always)
7019 */
7020static int
7021dv_neighbour_selection (void *cls,
7022 const struct GNUNET_PeerIdentity *pid,
7023 void *value)
7024{
7025 struct NeighbourSelectionContext *nsc = cls;
7026
7027 (void) value;
7028 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7029 return GNUNET_YES; /* skip initiator */
7030 for (unsigned int i = 0; i < nsc->nhops; i++)
7031 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7032 return GNUNET_YES;
7033 /* skip peers on path */
7034 nsc->num_eligible++;
7035 return GNUNET_YES;
7036}
7037
7038
7039/**
7040 * Function called for each neighbour during #handle_dv_learn.
7041 * We call #forward_dv_learn() on the neighbour(s) selected
7042 * during #dv_neighbour_selection().
7043 *
7044 * @param cls a `struct NeighbourSelectionContext *`
7045 * @param pid identity of the peer
7046 * @param value a `struct Neighbour`
7047 * @return #GNUNET_YES (always)
7048 */
7049static int
7050dv_neighbour_transmission (void *cls,
7051 const struct GNUNET_PeerIdentity *pid,
7052 void *value)
7053{
7054 struct NeighbourSelectionContext *nsc = cls;
7055
7056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7057 "transmission %s\n",
7058 GNUNET_i2s (pid));
7059 (void) value;
7060 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7061 return GNUNET_YES; /* skip initiator */
7062 for (unsigned int i = 0; i < nsc->nhops; i++)
7063 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7064 return GNUNET_YES;
7065 /* skip peers on path */
7066 for (unsigned int i = 0; i < nsc->num_selections; i++)
7067 {
7068 if (nsc->selections[i] == nsc->num_eligible)
7069 {
7070 forward_dv_learn (pid,
7071 nsc->dvl,
7072 nsc->bi_history,
7073 nsc->nhops,
7074 nsc->hops,
7075 nsc->in_time);
7076 break;
7077 }
7078 }
7079 nsc->num_eligible++;
7080 return GNUNET_YES;
7081}
7082
7083
7084/**
7085 * Computes the number of neighbours we should forward a DVInit
7086 * message to given that it has so far taken @a hops_taken hops
7087 * though the network and that the number of neighbours we have
7088 * in total is @a neighbour_count, out of which @a eligible_count
7089 * are not yet on the path.
7090 *
7091 * NOTE: technically we might want to include NSE in the formula to
7092 * get a better grip on the overall network size. However, for now
7093 * using NSE here would create a dependency issue in the build system.
7094 * => Left for later, hardcoded to 50 for now.
7095 *
7096 * The goal of the fomula is that we want to reach a total of LOG(NSE)
7097 * peers via DV (`target_total`). We want the reach to be spread out
7098 * over various distances to the origin, with a bias towards shorter
7099 * distances.
7100 *
7101 * We make the strong assumption that the network topology looks
7102 * "similar" at other hops, in particular the @a neighbour_count
7103 * should be comparable at other hops.
7104 *
7105 * If the local neighbourhood is densely connected, we expect that @a
7106 * eligible_count is close to @a neighbour_count minus @a hops_taken
7107 * as a lot of the path is already known. In that case, we should
7108 * forward to few(er) peers to try to find a path out of the
7109 * neighbourhood. OTOH, if @a eligible_count is close to @a
7110 * neighbour_count, we should forward to many peers as we are either
7111 * still close to the origin (i.e. @a hops_taken is small) or because
7112 * we managed to get beyond a local cluster. We express this as
7113 * the `boost_factor` using the square of the fraction of eligible
7114 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
7115 * 99% are eligible, the 'boost' will be almost 1).
7116 *
7117 * Second, the more hops we have taken, the larger the problem of an
7118 * exponential traffic explosion gets. So we take the `target_total`,
7119 * and compute our degree such that at each distance d 2^{-d} peers
7120 * are selected (corrected by the `boost_factor`).
7121 *
7122 * @param hops_taken number of hops DVInit has travelled so far
7123 * @param neighbour_count number of neighbours we have in total
7124 * @param eligible_count number of neighbours we could in
7125 * theory forward to
7126 */
7127static unsigned int
7128calculate_fork_degree (unsigned int hops_taken,
7129 unsigned int neighbour_count,
7130 unsigned int eligible_count)
7131{
7132 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
7133 double eligible_ratio =
7134 ((double) eligible_count) / ((double) neighbour_count);
7135 double boost_factor = eligible_ratio * eligible_ratio;
7136 unsigned int rnd;
7137 double left;
7138
7139 if (hops_taken >= 64)
7140 {
7141 GNUNET_break (0);
7142 return 0; /* precaution given bitshift below */
7143 }
7144 for (unsigned int i = 1; i < hops_taken; i++)
7145 {
7146 /* For each hop, subtract the expected number of targets
7147 reached at distance d (so what remains divided by 2^d) */
7148 target_total -= (target_total * boost_factor / (1LLU << i));
7149 }
7150 rnd =
7151 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
7152 /* round up or down probabilistically depending on how close we were
7153 when floor()ing to rnd */
7154 left = target_total - (double) rnd;
7155 if (UINT32_MAX * left >
7156 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
7157 rnd++; /* round up */
7158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7159 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
7160 hops_taken,
7161 rnd,
7162 eligible_count,
7163 neighbour_count);
7164 return rnd;
7165}
7166
7167
7168/**
7169 * Function called when peerstore is done storing a DV monotonic time.
7170 *
7171 * @param cls a `struct Neighbour`
7172 * @param success #GNUNET_YES if peerstore was successful
7173 */
7174static void
7175neighbour_store_dvmono_cb (void *cls, int success)
7176{
7177 struct Neighbour *n = cls;
7178
7179 n->sc = NULL;
7180 if (GNUNET_YES != success)
7181 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7182 "Failed to store other peer's monotonic time in peerstore!\n");
7183}
7184
7185
7186/**
7187 * Communicator gave us a DV learn message. Process the request.
7188 *
7189 * @param cls a `struct CommunicatorMessageContext` (must call
7190 * #finish_cmc_handling() when done)
7191 * @param dvl the message that was received
7192 */
7193static void
7194handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
7195{
7196 struct CommunicatorMessageContext *cmc = cls;
7197 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
7198 int bi_hop;
7199 uint16_t nhops;
7200 uint16_t bi_history;
7201 const struct DVPathEntryP *hops;
7202 int do_fwd;
7203 int did_initiator;
7204 struct GNUNET_TIME_Absolute in_time;
7205 struct Neighbour *n;
7206
7207 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
7208 bi_history = ntohs (dvl->bidirectional);
7209 hops = (const struct DVPathEntryP *) &dvl[1];
7210 if (0 == nhops)
7211 {
7212 /* sanity check */
7213 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
7214 {
7215 GNUNET_break (0);
7216 finish_cmc_handling (cmc);
7217 return;
7218 }
7219 }
7220 else
7221 {
7222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7223 "handle dv learn message last hop %s\n",
7224 GNUNET_i2s (&hops[nhops - 1].hop));
7225 /* sanity check */
7226 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
7227 {
7228 GNUNET_break (0);
7229 finish_cmc_handling (cmc);
7230 return;
7231 }
7232 }
7233
7234 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
7235 cc = cmc->tc->details.communicator.cc;
7236 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
7237 cc); // FIXME: add bi-directional flag to cc?
7238 in_time = GNUNET_TIME_absolute_get ();
7239
7240 /* continue communicator here, everything else can happen asynchronous! */
7241 finish_cmc_handling (cmc);
7242
7243 n = lookup_neighbour (&dvl->initiator);
7244 if (NULL != n)
7245 {
7246 if ((n->dv_monotime_available == GNUNET_YES) &&
7247 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
7248 n->last_dv_learn_monotime.abs_value_us))
7249 {
7250 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7251 "DV learn from %s discarded due to time travel",
7252 GNUNET_i2s (&dvl->initiator));
7253 GNUNET_STATISTICS_update (GST_stats,
7254 "# DV learn discarded due to time travel",
7255 1,
7256 GNUNET_NO);
7257 return;
7258 }
7259 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
7260 &dvl->initiator,
7261 &dvl->challenge,
7262 &dvl->init_sig))
7263 {
7264 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7265 "DV learn signature from %s invalid\n",
7266 GNUNET_i2s (&dvl->initiator));
7267 GNUNET_break_op (0);
7268 return;
7269 }
7270 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
7271 if (GNUNET_YES == n->dv_monotime_available)
7272 {
7273 if (NULL != n->sc)
7274 {
7275 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7276 "store cancel\n");
7277 GNUNET_PEERSTORE_store_cancel (n->sc);
7278 }
7279 n->sc =
7280 GNUNET_PEERSTORE_store (peerstore,
7281 "transport",
7282 &dvl->initiator,
7283 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
7284 &dvl->monotonic_time,
7285 sizeof(dvl->monotonic_time),
7286 GNUNET_TIME_UNIT_FOREVER_ABS,
7287 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7288 &neighbour_store_dvmono_cb,
7289 n);
7290 }
7291 }
7292 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
7293 If signature verification load too high, implement random drop strategy */
7294 for (unsigned int i = 0; i < nhops; i++)
7295 {
7296 struct DvHopPS dhp = { .purpose.purpose =
7297 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
7298 .purpose.size = htonl (sizeof(dhp)),
7299 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
7300 .succ = (nhops == i + 1) ? GST_my_identity
7301 : hops[i + 1].hop,
7302 .challenge = dvl->challenge };
7303
7304 if (GNUNET_OK !=
7305 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
7306 &dhp,
7307 &hops[i].hop_sig,
7308 &hops[i].hop.public_key))
7309 {
7310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7311 "DV learn from %s signature of hop %u invalid\n",
7312 GNUNET_i2s (&dvl->initiator),
7313 i);
7314 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7315 "signature of hop %s invalid\n",
7316 GNUNET_i2s (&hops[i].hop));
7317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7318 "pred %s\n",
7319 GNUNET_i2s (&dhp.pred));
7320 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7321 "succ %s\n",
7322 GNUNET_i2s (&dhp.succ));
7323 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7324 "hash %s\n",
7325 GNUNET_sh2s (&dhp.challenge.value));
7326 GNUNET_break_op (0);
7327 return;
7328 }
7329 }
7330 if (GNUNET_EXTRA_LOGGING > 0)
7331 {
7332 char *path;
7333
7334 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
7335 for (unsigned int i = 0; i < nhops; i++)
7336 {
7337 char *tmp;
7338
7339 GNUNET_asprintf (&tmp,
7340 "%s%s%s",
7341 path,
7342 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
7343 GNUNET_i2s (&hops[i].hop));
7344 GNUNET_free (path);
7345 path = tmp;
7346 }
7347 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7348 "Received DVInit via %s%s%s\n",
7349 path,
7350 bi_hop ? "<->" : "-->",
7351 GNUNET_i2s (&GST_my_identity));
7352 GNUNET_free (path);
7353 }
7354 do_fwd = GNUNET_YES;
7355 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
7356 {
7357 struct GNUNET_PeerIdentity path[nhops + 1];
7358 struct GNUNET_TIME_Relative host_latency_sum;
7359 struct GNUNET_TIME_Relative latency;
7360 struct GNUNET_TIME_Relative network_latency;
7361 struct GNUNET_TIME_Absolute now;
7362
7363 /* We initiated this, learn the forward path! */
7364 path[0] = GST_my_identity;
7365 path[1] = hops[0].hop;
7366 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
7367
7368 // Need also something to lookup initiation time
7369 // to compute RTT! -> add RTT argument here?
7370 now = GNUNET_TIME_absolute_get ();
7371 latency = GNUNET_TIME_absolute_get_duration (GNUNET_TIME_absolute_ntoh (
7372 dvl->monotonic_time));
7373 GNUNET_assert (latency.rel_value_us >= host_latency_sum.rel_value_us);
7374 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
7375 // (based on dvl->challenge, we can identify time of origin!)
7376
7377 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
7378 /* assumption: latency on all links is the same */
7379 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
7380
7381 for (unsigned int i = 2; i <= nhops; i++)
7382 {
7383 struct GNUNET_TIME_Relative ilat;
7384
7385 /* assumption: linear latency increase per hop */
7386 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
7387 path[i] = hops[i - 1].hop;
7388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7389 "Learned path with %u hops to %s with latency %s\n",
7390 i,
7391 GNUNET_i2s (&path[i]),
7392 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
7393 learn_dv_path (path,
7394 i + 1,
7395 ilat,
7396 GNUNET_TIME_relative_to_absolute (
7397 ADDRESS_VALIDATION_LIFETIME));
7398 }
7399 /* as we initiated, do not forward again (would be circular!) */
7400 do_fwd = GNUNET_NO;
7401 return;
7402 }
7403 if (bi_hop)
7404 {
7405 /* last hop was bi-directional, we could learn something here! */
7406 struct GNUNET_PeerIdentity path[nhops + 2];
7407
7408 path[0] = GST_my_identity;
7409 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
7410 for (unsigned int i = 0; i < nhops; i++)
7411 {
7412 int iret;
7413
7414 if (0 == (bi_history & (1 << i)))
7415 break; /* i-th hop not bi-directional, stop learning! */
7416 if (i == nhops - 1)
7417 {
7418 path[i + 2] = dvl->initiator;
7419 }
7420 else
7421 {
7422 path[i + 2] = hops[nhops - i - 2].hop;
7423 }
7424
7425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7426 "Learned inverse path with %u hops to %s\n",
7427 i + 2,
7428 GNUNET_i2s (&path[i + 2]));
7429 iret = learn_dv_path (path,
7430 i + 3,
7431 GNUNET_TIME_UNIT_FOREVER_REL,
7432 GNUNET_TIME_UNIT_ZERO_ABS);
7433 if (GNUNET_SYSERR == iret)
7434 {
7435 /* path invalid or too long to be interesting for US, thus should also
7436 not be interesting to our neighbours, cut path when forwarding to
7437 'i' hops, except of course for the one that goes back to the
7438 initiator */
7439 GNUNET_STATISTICS_update (GST_stats,
7440 "# DV learn not forwarded due invalidity of path",
7441 1,
7442 GNUNET_NO);
7443 do_fwd = GNUNET_NO;
7444 break;
7445 }
7446 if ((GNUNET_NO == iret) && (nhops == i + 1))
7447 {
7448 /* we have better paths, and this is the longest target,
7449 so there cannot be anything interesting later */
7450 GNUNET_STATISTICS_update (GST_stats,
7451 "# DV learn not forwarded, got better paths",
7452 1,
7453 GNUNET_NO);
7454 do_fwd = GNUNET_NO;
7455 break;
7456 }
7457 }
7458 }
7459 if (MAX_DV_HOPS_ALLOWED == nhops)
7460 {
7461 /* At limit, we're out of here! */
7462 return;
7463 }
7464
7465 /* Forward to initiator, if path non-trivial and possible */
7466 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
7467 did_initiator = GNUNET_NO;
7468 if ((1 <= nhops) &&
7469 (GNUNET_YES ==
7470 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
7471 {
7472 /* send back to origin! */
7473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7474 "Sending DVL back to initiator %s\n",
7475 GNUNET_i2s (&dvl->initiator));
7476 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
7477 did_initiator = GNUNET_YES;
7478 }
7479 /* We forward under two conditions: either we still learned something
7480 ourselves (do_fwd), or the path was darn short and thus the initiator is
7481 likely to still be very interested in this (and we did NOT already
7482 send it back to the initiator) */
7483 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
7484 (GNUNET_NO == did_initiator)))
7485 {
7486 /* Pick random neighbours that are not yet on the path */
7487 struct NeighbourSelectionContext nsc;
7488 unsigned int n_cnt;
7489
7490 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
7491 nsc.nhops = nhops;
7492 nsc.dvl = dvl;
7493 nsc.bi_history = bi_history;
7494 nsc.hops = hops;
7495 nsc.in_time = in_time;
7496 nsc.num_eligible = 0;
7497 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7498 &dv_neighbour_selection,
7499 &nsc);
7500 if (0 == nsc.num_eligible)
7501 return; /* done here, cannot forward to anyone else */
7502 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
7503 nsc.num_selections =
7504 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
7505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7506 "Forwarding DVL to %u other peers\n",
7507 nsc.num_selections);
7508 for (unsigned int i = 0; i < nsc.num_selections; i++)
7509 nsc.selections[i] =
7510 (nsc.num_selections == n_cnt)
7511 ? i /* all were selected, avoid collisions by chance */
7512 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
7513 nsc.num_eligible = 0;
7514 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
7515 &dv_neighbour_transmission,
7516 &nsc);
7517 }
7518}
7519
7520
7521/**
7522 * Communicator gave us a DV box. Check the message.
7523 *
7524 * @param cls a `struct CommunicatorMessageContext`
7525 * @param dvb the send message that was sent
7526 * @return #GNUNET_YES if message is well-formed
7527 */
7528static int
7529check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7530{
7531 uint16_t size = ntohs (dvb->header.size);
7532 uint16_t num_hops = ntohs (dvb->num_hops);
7533 const struct GNUNET_PeerIdentity *hops =
7534 (const struct GNUNET_PeerIdentity *) &dvb[1];
7535
7536 (void) cls;
7537 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
7538 + sizeof(struct GNUNET_MessageHeader))
7539 {
7540 GNUNET_break_op (0);
7541 return GNUNET_SYSERR;
7542 }
7543 /* This peer must not be on the path */
7544 for (unsigned int i = 0; i < num_hops; i++)
7545 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7546 {
7547 GNUNET_break_op (0);
7548 return GNUNET_SYSERR;
7549 }
7550 return GNUNET_YES;
7551}
7552
7553
7554/**
7555 * Create a DV Box message and queue it for transmission to
7556 * @ea next_hop.
7557 *
7558 * @param next_hop peer to receive the message next
7559 * @param total_hops how many hops did the message take so far
7560 * @param num_hops length of the @a hops array
7561 * @param origin origin of the message
7562 * @param hops next peer(s) to the destination, including destination
7563 * @param payload payload of the box
7564 * @param payload_size number of bytes in @a payload
7565 */
7566static void
7567forward_dv_box (struct Neighbour *next_hop,
7568 struct TransportDVBoxMessage *hdr,
7569 uint16_t total_hops,
7570 uint16_t num_hops,
7571 const struct GNUNET_PeerIdentity *hops,
7572 const void *enc_payload,
7573 uint16_t enc_payload_size)
7574{
7575 struct VirtualLink *vl = next_hop->vl;
7576 struct PendingMessage *pm;
7577 size_t msg_size = sizeof(struct TransportDVBoxMessage)
7578 + num_hops * sizeof(struct GNUNET_PeerIdentity)
7579 + enc_payload_size;
7580 char *buf;
7581 char msg_buf[msg_size] GNUNET_ALIGN;
7582 struct GNUNET_PeerIdentity *dhops;
7583
7584 hdr->num_hops = htons (num_hops);
7585 hdr->total_hops = htons (total_hops);
7586 hdr->header.size = htons (msg_size);
7587 memcpy (msg_buf, hdr, sizeof(*hdr));
7588 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
7589 TransportDVBoxMessage)];
7590 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
7591 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
7592
7593 if (GNUNET_YES == ntohs (hdr->without_fc))
7594 {
7595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7596 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
7597 enc_payload_size,
7598 GNUNET_i2s (&next_hop->pid),
7599 (unsigned int) num_hops,
7600 (unsigned int) total_hops);
7601 route_via_neighbour (next_hop, (const struct
7602 GNUNET_MessageHeader *) msg_buf,
7603 RMO_ANYTHING_GOES);
7604 }
7605 else if (NULL != vl)
7606 {
7607 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
7608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7609 "2 created pm %p storing vl %p \n",
7610 pm,
7611 vl);
7612 pm->pmt = PMT_DV_BOX;
7613 pm->vl = vl;
7614 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
7615 pm->logging_uuid = logging_uuid_gen++;
7616 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
7617 pm->bytes_msg = msg_size;
7618 buf = (char *) &pm[1];
7619 memcpy (buf, msg_buf, msg_size);
7620 GNUNET_CONTAINER_MDLL_insert (vl,
7621 vl->pending_msg_head,
7622 vl->pending_msg_tail,
7623 pm);
7624 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7625 "Created pending message %llu for DV Box with next hop %s (%u/%u)\n",
7626 pm->logging_uuid,
7627 GNUNET_i2s (&next_hop->pid),
7628 (unsigned int) num_hops,
7629 (unsigned int) total_hops);
7630 check_vl_transmission (vl);
7631 }
7632 else
7633 {
7634 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7635 "The virtual link is not ready for forwarding a DV Box with payload.\n");
7636 // FIXME The DV Box was send before the validation response. Shall we send a validation request for DV paths?
7637 }
7638}
7639
7640
7641/**
7642 * Free data structures associated with @a b.
7643 *
7644 * @param b data structure to release
7645 */
7646static void
7647free_backtalker (struct Backtalker *b)
7648{
7649 if (NULL != b->get)
7650 {
7651 GNUNET_PEERSTORE_iterate_cancel (b->get);
7652 b->get = NULL;
7653 GNUNET_assert (NULL != b->cmc);
7654 finish_cmc_handling (b->cmc);
7655 b->cmc = NULL;
7656 }
7657 if (NULL != b->task)
7658 {
7659 GNUNET_SCHEDULER_cancel (b->task);
7660 b->task = NULL;
7661 }
7662 if (NULL != b->sc)
7663 {
7664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7665 "store cancel\n");
7666 GNUNET_PEERSTORE_store_cancel (b->sc);
7667 b->sc = NULL;
7668 }
7669 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7670 "Removing backtalker for %s\n",
7671 GNUNET_i2s (&b->pid));
7672 GNUNET_assert (
7673 GNUNET_YES ==
7674 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
7675 GNUNET_free (b);
7676}
7677
7678
7679/**
7680 * Callback to free backtalker records.
7681 *
7682 * @param cls NULL
7683 * @param pid unused
7684 * @param value a `struct Backtalker`
7685 * @return #GNUNET_OK (always)
7686 */
7687static int
7688free_backtalker_cb (void *cls,
7689 const struct GNUNET_PeerIdentity *pid,
7690 void *value)
7691{
7692 struct Backtalker *b = value;
7693
7694 (void) cls;
7695 (void) pid;
7696 free_backtalker (b);
7697 return GNUNET_OK;
7698}
7699
7700
7701/**
7702 * Function called when it is time to clean up a backtalker.
7703 *
7704 * @param cls a `struct Backtalker`
7705 */
7706static void
7707backtalker_timeout_cb (void *cls)
7708{
7709 struct Backtalker *b = cls;
7710
7711 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7712 "backtalker timeout.\n");
7713 b->task = NULL;
7714 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
7715 {
7716 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7717 return;
7718 }
7719 GNUNET_assert (NULL == b->sc);
7720 free_backtalker (b);
7721}
7722
7723
7724/**
7725 * Function called with the monotonic time of a backtalker
7726 * by PEERSTORE. Updates the time and continues processing.
7727 *
7728 * @param cls a `struct Backtalker`
7729 * @param record the information found, NULL for the last call
7730 * @param emsg error message
7731 */
7732static void
7733backtalker_monotime_cb (void *cls,
7734 const struct GNUNET_PEERSTORE_Record *record,
7735 const char *emsg)
7736{
7737 struct Backtalker *b = cls;
7738 struct GNUNET_TIME_AbsoluteNBO *mtbe;
7739 struct GNUNET_TIME_Absolute mt;
7740
7741 (void) emsg;
7742 if (NULL == record)
7743 {
7744 /* we're done with #backtalker_monotime_cb() invocations,
7745 continue normal processing */
7746 b->get = NULL;
7747 GNUNET_assert (NULL != b->cmc);
7748 if (0 != b->body_size)
7749 demultiplex_with_cmc (b->cmc,
7750 (const struct GNUNET_MessageHeader *) &b[1]);
7751 else
7752 finish_cmc_handling (b->cmc);
7753 b->cmc = NULL;
7754 return;
7755 }
7756 if (sizeof(*mtbe) != record->value_size)
7757 {
7758 GNUNET_break (0);
7759 return;
7760 }
7761 mtbe = record->value;
7762 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
7763 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
7764 {
7765 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7766 "Backtalker message from %s dropped, monotime in the past\n",
7767 GNUNET_i2s (&b->pid));
7768 GNUNET_STATISTICS_update (
7769 GST_stats,
7770 "# Backchannel messages dropped: monotonic time not increasing",
7771 1,
7772 GNUNET_NO);
7773 b->monotonic_time = mt;
7774 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
7775 */
7776 b->body_size = 0;
7777 return;
7778 }
7779}
7780
7781
7782/**
7783 * Function called by PEERSTORE when the store operation of
7784 * a backtalker's monotonic time is complete.
7785 *
7786 * @param cls the `struct Backtalker`
7787 * @param success #GNUNET_OK on success
7788 */
7789static void
7790backtalker_monotime_store_cb (void *cls, int success)
7791{
7792 struct Backtalker *b = cls;
7793
7794 if (GNUNET_OK != success)
7795 {
7796 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7797 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
7798 }
7799 b->sc = NULL;
7800 if (NULL != b->task)
7801 {
7802 GNUNET_SCHEDULER_cancel (b->task);
7803 b->task = NULL;
7804 }
7805 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
7806}
7807
7808
7809/**
7810 * The backtalker @a b monotonic time changed. Update PEERSTORE.
7811 *
7812 * @param b a backtalker with updated monotonic time
7813 */
7814static void
7815update_backtalker_monotime (struct Backtalker *b)
7816{
7817 struct GNUNET_TIME_AbsoluteNBO mtbe;
7818
7819 if (NULL != b->sc)
7820 {
7821 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7822 "store cancel before store with sc %p\n",
7823 b->sc);
7824 /*GNUNET_PEERSTORE_store_cancel (b->sc);
7825 b->sc = NULL;*/
7826 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7827 "store cancel before store with sc %p is null\n",
7828 b->sc);
7829 }
7830 else
7831 {
7832 GNUNET_SCHEDULER_cancel (b->task);
7833 b->task = NULL;
7834 }
7835 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
7836 b->sc =
7837 GNUNET_PEERSTORE_store (peerstore,
7838 "transport",
7839 &b->pid,
7840 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
7841 &mtbe,
7842 sizeof(mtbe),
7843 GNUNET_TIME_UNIT_FOREVER_ABS,
7844 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7845 &backtalker_monotime_store_cb,
7846 b);
7847}
7848
7849
7850/**
7851 * Communicator gave us a DV box. Process the request.
7852 *
7853 * @param cls a `struct CommunicatorMessageContext` (must call
7854 * #finish_cmc_handling() when done)
7855 * @param dvb the message that was received
7856 */
7857static void
7858handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
7859{
7860 struct CommunicatorMessageContext *cmc = cls;
7861 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
7862 uint16_t num_hops = ntohs (dvb->num_hops);
7863 const struct GNUNET_PeerIdentity *hops =
7864 (const struct GNUNET_PeerIdentity *) &dvb[1];
7865 const char *enc_payload = (const char *) &hops[num_hops];
7866 uint16_t enc_payload_size =
7867 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
7868 char enc[enc_payload_size];
7869 struct DVKeyState *key;
7870 struct GNUNET_HashCode hmac;
7871 const char *hdr;
7872 size_t hdr_len;
7873
7874 key = GNUNET_new (struct DVKeyState);
7875
7876 if (GNUNET_EXTRA_LOGGING > 0)
7877 {
7878 char *path;
7879
7880 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
7881 for (unsigned int i = 0; i < num_hops; i++)
7882 {
7883 char *tmp;
7884
7885 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
7886 GNUNET_free (path);
7887 path = tmp;
7888 }
7889 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7890 "Received DVBox with remaining path %s\n",
7891 path);
7892 GNUNET_free (path);
7893 }
7894
7895 if (num_hops > 0)
7896 {
7897 /* We're trying from the end of the hops array, as we may be
7898 able to find a shortcut unknown to the origin that way */
7899 for (int i = num_hops - 1; i >= 0; i--)
7900 {
7901 struct Neighbour *n;
7902
7903 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
7904 {
7905 GNUNET_break_op (0);
7906 finish_cmc_handling (cmc);
7907 return;
7908 }
7909 n = lookup_neighbour (&hops[i]);
7910 if (NULL == n)
7911 continue;
7912 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7913 "Skipping %u/%u hops ahead while routing DV Box\n",
7914 i,
7915 num_hops);
7916
7917 forward_dv_box (n,
7918 (struct TransportDVBoxMessage *) dvb,
7919 ntohs (dvb->total_hops) + 1,
7920 num_hops - i - 1, /* number of hops left */
7921 &hops[i + 1], /* remaining hops */
7922 enc_payload,
7923 enc_payload_size);
7924 GNUNET_STATISTICS_update (GST_stats,
7925 "# DV hops skipped routing boxes",
7926 i,
7927 GNUNET_NO);
7928 GNUNET_STATISTICS_update (GST_stats,
7929 "# DV boxes routed (total)",
7930 1,
7931 GNUNET_NO);
7932 finish_cmc_handling (cmc);
7933 return;
7934 }
7935 /* Woopsie, next hop not in neighbours, drop! */
7936 GNUNET_STATISTICS_update (GST_stats,
7937 "# DV Boxes dropped: next hop unknown",
7938 1,
7939 GNUNET_NO);
7940 finish_cmc_handling (cmc);
7941 return;
7942 }
7943 /* We are the target. Unbox and handle message. */
7944 GNUNET_STATISTICS_update (GST_stats,
7945 "# DV boxes opened (ultimate target)",
7946 1,
7947 GNUNET_NO);
7948 cmc->total_hops = ntohs (dvb->total_hops);
7949
7950 dh_key_derive_eph_pub (&dvb->ephemeral_key, &dvb->iv, key);
7951 hdr = (const char *) &dvb[1];
7952 hdr_len = ntohs (dvb->orig_size) - sizeof(*dvb) - sizeof(struct
7953 GNUNET_PeerIdentity)
7954 * ntohs (dvb->total_hops);
7955
7956 dv_hmac (key, &hmac, hdr, hdr_len);
7957 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
7958 {
7959 /* HMAC mismatch, discard! */
7960 GNUNET_break_op (0);
7961 finish_cmc_handling (cmc);
7962 return;
7963 }
7964 /* begin actual decryption */
7965 {
7966 struct Backtalker *b;
7967 struct GNUNET_TIME_Absolute monotime;
7968 struct TransportDVBoxPayloadP ppay;
7969 char body[hdr_len - sizeof(ppay)] GNUNET_ALIGN;
7970 const struct GNUNET_MessageHeader *mh =
7971 (const struct GNUNET_MessageHeader *) body;
7972
7973 GNUNET_assert (hdr_len >=
7974 sizeof(ppay) + sizeof(struct GNUNET_MessageHeader));
7975 dv_decrypt (key, &ppay, hdr, sizeof(ppay));
7976 dv_decrypt (key, &body, &hdr[sizeof(ppay)], hdr_len - sizeof(ppay));
7977 dv_key_clean (key);
7978 if (ntohs (mh->size) != sizeof(body))
7979 {
7980 GNUNET_break_op (0);
7981 finish_cmc_handling (cmc);
7982 return;
7983 }
7984 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
7985 switch (ntohs (mh->type))
7986 {
7987 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
7988 GNUNET_break_op (0);
7989 finish_cmc_handling (cmc);
7990 return;
7991
7992 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
7993 GNUNET_break_op (0);
7994 finish_cmc_handling (cmc);
7995 return;
7996
7997 default:
7998 /* permitted, continue */
7999 break;
8000 }
8001 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
8002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8003 "Decrypted backtalk from %s\n",
8004 GNUNET_i2s (&ppay.sender));
8005 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
8006 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
8007 {
8008 GNUNET_STATISTICS_update (
8009 GST_stats,
8010 "# Backchannel messages dropped: monotonic time not increasing",
8011 1,
8012 GNUNET_NO);
8013 finish_cmc_handling (cmc);
8014 return;
8015 }
8016 if ((NULL == b) ||
8017 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
8018 {
8019 /* Check signature */
8020 struct EphemeralConfirmationPS ec;
8021
8022 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
8023 ec.target = GST_my_identity;
8024 ec.ephemeral_key = dvb->ephemeral_key;
8025 ec.purpose.size = htonl (sizeof(ec));
8026 ec.sender_monotonic_time = ppay.monotonic_time;
8027 if (
8028 GNUNET_OK !=
8029 GNUNET_CRYPTO_eddsa_verify (
8030 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
8031 &ec,
8032 &ppay.sender_sig,
8033 &ppay.sender.public_key))
8034 {
8035 /* Signature invalid, discard! */
8036 GNUNET_break_op (0);
8037 finish_cmc_handling (cmc);
8038 return;
8039 }
8040 }
8041 /* Update sender, we now know the real origin! */
8042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8043 "DVBox received for me from %s via %s\n",
8044 GNUNET_i2s2 (&ppay.sender),
8045 GNUNET_i2s (&cmc->im.sender));
8046 cmc->im.sender = ppay.sender;
8047
8048 if (NULL != b)
8049 {
8050 /* update key cache and mono time */
8051 b->last_ephemeral = dvb->ephemeral_key;
8052 b->monotonic_time = monotime;
8053 update_backtalker_monotime (b);
8054 b->timeout =
8055 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8056
8057 demultiplex_with_cmc (cmc, mh);
8058 return;
8059 }
8060 /* setup data structure to cache signature AND check
8061 monotonic time with PEERSTORE before forwarding backchannel payload */
8062 b = GNUNET_malloc (sizeof(struct Backtalker) + sizeof(body));
8063 b->pid = ppay.sender;
8064 b->body_size = sizeof(body);
8065 memcpy (&b[1], body, sizeof(body));
8066 GNUNET_assert (GNUNET_YES ==
8067 GNUNET_CONTAINER_multipeermap_put (
8068 backtalkers,
8069 &b->pid,
8070 b,
8071 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8072 b->monotonic_time = monotime; /* NOTE: to be checked still! */
8073 b->cmc = cmc;
8074 b->timeout =
8075 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8076 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8077 b->get =
8078 GNUNET_PEERSTORE_iterate (peerstore,
8079 "transport",
8080 &b->pid,
8081 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
8082 &backtalker_monotime_cb,
8083 b);
8084 } /* end actual decryption */
8085}
8086
8087
8088/**
8089 * Client notified us about transmission from a peer. Process the request.
8090 *
8091 * @param cls a `struct TransportClient` which sent us the message
8092 * @param obm the send message that was sent
8093 * @return #GNUNET_YES if message is well-formed
8094 */
8095static int
8096check_incoming_msg (void *cls,
8097 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8098{
8099 struct TransportClient *tc = cls;
8100
8101 if (CT_COMMUNICATOR != tc->type)
8102 {
8103 GNUNET_break (0);
8104 return GNUNET_SYSERR;
8105 }
8106 GNUNET_MQ_check_boxed_message (im);
8107 return GNUNET_OK;
8108}
8109
8110
8111/**
8112 * Closure for #check_known_address.
8113 */
8114struct CheckKnownAddressContext
8115{
8116 /**
8117 * Set to the address we are looking for.
8118 */
8119 const char *address;
8120
8121 /**
8122 * Set to a matching validation state, if one was found.
8123 */
8124 struct ValidationState *vs;
8125};
8126
8127
8128/**
8129 * Test if the validation state in @a value matches the
8130 * address from @a cls.
8131 *
8132 * @param cls a `struct CheckKnownAddressContext`
8133 * @param pid unused (must match though)
8134 * @param value a `struct ValidationState`
8135 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8136 */
8137static int
8138check_known_address (void *cls,
8139 const struct GNUNET_PeerIdentity *pid,
8140 void *value)
8141{
8142 struct CheckKnownAddressContext *ckac = cls;
8143 struct ValidationState *vs = value;
8144
8145 (void) pid;
8146 if (0 != strcmp (vs->address, ckac->address))
8147 return GNUNET_OK;
8148 ckac->vs = vs;
8149 return GNUNET_NO;
8150}
8151
8152
8153/**
8154 * Task run periodically to validate some address based on #validation_heap.
8155 *
8156 * @param cls NULL
8157 */
8158static void
8159validation_start_cb (void *cls);
8160
8161
8162/**
8163 * Set the time for next_challenge of @a vs to @a new_time.
8164 * Updates the heap and if necessary reschedules the job.
8165 *
8166 * @param vs validation state to update
8167 * @param new_time new time for revalidation
8168 */
8169static void
8170update_next_challenge_time (struct ValidationState *vs,
8171 struct GNUNET_TIME_Absolute new_time)
8172{
8173 struct GNUNET_TIME_Relative delta;
8174
8175 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
8176 return; /* be lazy */
8177 vs->next_challenge = new_time;
8178 if (NULL == vs->hn)
8179 vs->hn =
8180 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
8181 else
8182 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
8183 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
8184 (NULL != validation_task))
8185 return;
8186 if (NULL != validation_task)
8187 GNUNET_SCHEDULER_cancel (validation_task);
8188 /* randomize a bit */
8189 delta.rel_value_us =
8190 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
8191 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
8192 new_time = GNUNET_TIME_absolute_add (new_time, delta);
8193 validation_task =
8194 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
8195}
8196
8197
8198/**
8199 * Start address validation.
8200 *
8201 * @param pid peer the @a address is for
8202 * @param address an address to reach @a pid (presumably)
8203 */
8204static void
8205start_address_validation (const struct GNUNET_PeerIdentity *pid,
8206 const char *address)
8207{
8208 struct GNUNET_TIME_Absolute now;
8209 struct ValidationState *vs;
8210 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
8211
8212 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8213 pid,
8214 &check_known_address,
8215 &ckac);
8216 if (NULL != (vs = ckac.vs))
8217 {
8218 /* if 'vs' is not currently valid, we need to speed up retrying the
8219 * validation */
8220 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8221 {
8222 /* reduce backoff as we got a fresh advertisement */
8223 vs->challenge_backoff =
8224 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8225 GNUNET_TIME_relative_divide (
8226 vs->challenge_backoff,
8227 2));
8228 update_next_challenge_time (vs,
8229 GNUNET_TIME_relative_to_absolute (
8230 vs->challenge_backoff));
8231 }
8232 return;
8233 }
8234 now = GNUNET_TIME_absolute_get ();
8235 vs = GNUNET_new (struct ValidationState);
8236 vs->pid = *pid;
8237 vs->valid_until =
8238 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8239 vs->first_challenge_use = now;
8240 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8241 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8242 &vs->challenge,
8243 sizeof(vs->challenge));
8244 vs->address = GNUNET_strdup (address);
8245 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8246 "Starting address validation `%s' of peer %s using challenge %s\n",
8247 address,
8248 GNUNET_i2s (pid),
8249 GNUNET_sh2s (&vs->challenge.value));
8250 GNUNET_assert (GNUNET_YES ==
8251 GNUNET_CONTAINER_multipeermap_put (
8252 validation_map,
8253 &vs->pid,
8254 vs,
8255 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
8256 update_next_challenge_time (vs, now);
8257}
8258
8259
8260/**
8261 * Function called by PEERSTORE for each matching record.
8262 *
8263 * @param cls closure, a `struct IncomingRequest`
8264 * @param record peerstore record information
8265 * @param emsg error message, or NULL if no errors
8266 */
8267static void
8268handle_hello_for_incoming (void *cls,
8269 const struct GNUNET_PEERSTORE_Record *record,
8270 const char *emsg)
8271{
8272 struct IncomingRequest *ir = cls;
8273 const char *val;
8274
8275 if (NULL != emsg)
8276 {
8277 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
8278 "Got failure from PEERSTORE: %s\n",
8279 emsg);
8280 return;
8281 }
8282 val = record->value;
8283 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
8284 {
8285 GNUNET_break (0);
8286 return;
8287 }
8288 start_address_validation (&ir->pid, (const char *) record->value);
8289}
8290
8291
8292/**
8293 * Communicator gave us a transport address validation challenge. Process the
8294 * request.
8295 *
8296 * @param cls a `struct CommunicatorMessageContext` (must call
8297 * #finish_cmc_handling() when done)
8298 * @param tvc the message that was received
8299 */
8300static void
8301handle_validation_challenge (
8302 void *cls,
8303 const struct TransportValidationChallengeMessage *tvc)
8304{
8305 struct CommunicatorMessageContext *cmc = cls;
8306 struct TransportValidationResponseMessage tvr;
8307 struct VirtualLink *vl;
8308 struct GNUNET_TIME_RelativeNBO validity_duration;
8309 struct IncomingRequest *ir;
8310 struct Neighbour *n;
8311 struct GNUNET_PeerIdentity sender;
8312
8313 /* DV-routed messages are not allowed for validation challenges */
8314 if (cmc->total_hops > 0)
8315 {
8316 GNUNET_break_op (0);
8317 finish_cmc_handling (cmc);
8318 return;
8319 }
8320 validity_duration = cmc->im.expected_address_validity;
8321 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8322 "Received address validation challenge %s\n",
8323 GNUNET_sh2s (&tvc->challenge.value));
8324 /* If we have a virtual link, we use this mechanism to signal the
8325 size of the flow control window, and to allow the sender
8326 to ask for increases. If for us the virtual link is still down,
8327 we will always give a window size of zero. */
8328 tvr.header.type =
8329 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
8330 tvr.header.size = htons (sizeof(tvr));
8331 tvr.reserved = htonl (0);
8332 tvr.challenge = tvc->challenge;
8333 tvr.origin_time = tvc->sender_time;
8334 tvr.validity_duration = validity_duration;
8335 {
8336 /* create signature */
8337 struct TransportValidationPS tvp = {
8338 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
8339 .purpose.size = htonl (sizeof(tvp)),
8340 .validity_duration = validity_duration,
8341 .challenge = tvc->challenge
8342 };
8343
8344 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
8345 &tvp,
8346 &tvr.signature);
8347 }
8348 sender = cmc->im.sender;
8349 vl = lookup_virtual_link (&sender);
8350 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
8351 {
8352 // route_control_message_without_fc (&cmc->im.sender,
8353 route_control_message_without_fc (vl,
8354 &tvr.header,
8355 RMO_ANYTHING_GOES | RMO_REDUNDANT);
8356 }
8357 else
8358 {
8359 /* Use route via neighbour */
8360 n = lookup_neighbour (&sender);
8361 if (NULL != n)
8362 route_via_neighbour (n, &tvr.header,
8363 RMO_ANYTHING_GOES | RMO_REDUNDANT
8364 | RMO_UNCONFIRMED_ALLOWED);
8365 }
8366
8367 finish_cmc_handling (cmc);
8368 if (NULL != vl)
8369 return;
8370
8371 /* For us, the link is still down, but we need bi-directional
8372 connections (for flow-control and for this to be useful for
8373 CORE), so we must try to bring the link up! */
8374
8375 /* (1) Check existing queues, if any, we may be lucky! */
8376 n = lookup_neighbour (&sender);
8377 if (NULL != n)
8378 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
8379 start_address_validation (&sender, q->address);
8380 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
8381 we could use */
8382 for (ir = ir_head; NULL != ir; ir = ir->next)
8383 if (0 == GNUNET_memcmp (&ir->pid, &sender))
8384 return;
8385 /* we are already trying */
8386 ir = GNUNET_new (struct IncomingRequest);
8387 ir->pid = sender;
8388 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
8389 ir->wc = GNUNET_PEERSTORE_watch (peerstore,
8390 "transport",
8391 &ir->pid,
8392 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8393 &handle_hello_for_incoming,
8394 ir);
8395 ir_total++;
8396 /* Bound attempts we do in parallel here, might otherwise get excessive */
8397 while (ir_total > MAX_INCOMING_REQUEST)
8398 free_incoming_request (ir_head);
8399}
8400
8401
8402/**
8403 * Closure for #check_known_challenge.
8404 */
8405struct CheckKnownChallengeContext
8406{
8407 /**
8408 * Set to the challenge we are looking for.
8409 */
8410 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge;
8411
8412 /**
8413 * Set to a matching validation state, if one was found.
8414 */
8415 struct ValidationState *vs;
8416};
8417
8418
8419/**
8420 * Test if the validation state in @a value matches the
8421 * challenge from @a cls.
8422 *
8423 * @param cls a `struct CheckKnownChallengeContext`
8424 * @param pid unused (must match though)
8425 * @param value a `struct ValidationState`
8426 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8427 */
8428static int
8429check_known_challenge (void *cls,
8430 const struct GNUNET_PeerIdentity *pid,
8431 void *value)
8432{
8433 struct CheckKnownChallengeContext *ckac = cls;
8434 struct ValidationState *vs = value;
8435
8436 (void) pid;
8437 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
8438 return GNUNET_OK;
8439 ckac->vs = vs;
8440 return GNUNET_NO;
8441}
8442
8443
8444/**
8445 * Function called when peerstore is done storing a
8446 * validated address.
8447 *
8448 * @param cls a `struct ValidationState`
8449 * @param success #GNUNET_YES on success
8450 */
8451static void
8452peerstore_store_validation_cb (void *cls, int success)
8453{
8454 struct ValidationState *vs = cls;
8455
8456 vs->sc = NULL;
8457 if (GNUNET_YES == success)
8458 return;
8459 GNUNET_STATISTICS_update (GST_stats,
8460 "# Peerstore failed to store foreign address",
8461 1,
8462 GNUNET_NO);
8463}
8464
8465
8466/**
8467 * Find the queue matching @a pid and @a address.
8468 *
8469 * @param pid peer the queue must go to
8470 * @param address address the queue must use
8471 * @return NULL if no such queue exists
8472 */
8473static struct Queue *
8474find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
8475{
8476 struct Neighbour *n;
8477
8478 n = lookup_neighbour (pid);
8479 if (NULL == n)
8480 return NULL;
8481 for (struct Queue *pos = n->queue_head; NULL != pos;
8482 pos = pos->next_neighbour)
8483 {
8484 if (0 == strcmp (pos->address, address))
8485 return pos;
8486 }
8487 return NULL;
8488}
8489
8490
8491/**
8492 * Communicator gave us a transport address validation response. Process the
8493 * request.
8494 *
8495 * @param cls a `struct CommunicatorMessageContext` (must call
8496 * #finish_cmc_handling() when done)
8497 * @param tvr the message that was received
8498 */
8499static void
8500handle_validation_response (
8501 void *cls,
8502 const struct TransportValidationResponseMessage *tvr)
8503{
8504 struct CommunicatorMessageContext *cmc = cls;
8505 struct ValidationState *vs;
8506 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
8507 .vs = NULL };
8508 struct GNUNET_TIME_Absolute origin_time;
8509 struct Queue *q;
8510 struct Neighbour *n;
8511 struct VirtualLink *vl;
8512
8513 /* check this is one of our challenges */
8514 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8515 &cmc->im.sender,
8516 &check_known_challenge,
8517 &ckac);
8518 if (NULL == (vs = ckac.vs))
8519 {
8520 /* This can happen simply if we 'forgot' the challenge by now,
8521 i.e. because we received the validation response twice */
8522 GNUNET_STATISTICS_update (GST_stats,
8523 "# Validations dropped, challenge unknown",
8524 1,
8525 GNUNET_NO);
8526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8527 "Validation response %s dropped, challenge unknown\n",
8528 GNUNET_sh2s (&tvr->challenge.value));
8529 finish_cmc_handling (cmc);
8530 return;
8531 }
8532
8533 /* sanity check on origin time */
8534 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
8535 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
8536 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
8537 {
8538 GNUNET_break_op (0);
8539 finish_cmc_handling (cmc);
8540 return;
8541 }
8542
8543 {
8544 /* check signature */
8545 struct TransportValidationPS tvp = {
8546 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
8547 .purpose.size = htonl (sizeof(tvp)),
8548 .validity_duration = tvr->validity_duration,
8549 .challenge = tvr->challenge
8550 };
8551
8552 if (
8553 GNUNET_OK !=
8554 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
8555 &tvp,
8556 &tvr->signature,
8557 &cmc->im.sender.public_key))
8558 {
8559 GNUNET_break_op (0);
8560 finish_cmc_handling (cmc);
8561 return;
8562 }
8563 }
8564
8565 /* validity is capped by our willingness to keep track of the
8566 validation entry and the maximum the other peer allows */
8567 vs->valid_until = GNUNET_TIME_relative_to_absolute (
8568 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
8569 tvr->validity_duration),
8570 MAX_ADDRESS_VALID_UNTIL));
8571 vs->validated_until =
8572 GNUNET_TIME_absolute_min (vs->valid_until,
8573 GNUNET_TIME_relative_to_absolute (
8574 ADDRESS_VALIDATION_LIFETIME));
8575 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
8576 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
8577 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8578 &vs->challenge,
8579 sizeof(vs->challenge));
8580 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
8581 vs->validated_until,
8582 GNUNET_TIME_relative_multiply (vs->validation_rtt,
8583 VALIDATION_RTT_BUFFER_FACTOR));
8584 vs->last_challenge_use =
8585 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
8586 update_next_challenge_time (vs, vs->first_challenge_use);
8587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8588 "Validation response %s accepted, address valid until %s\n",
8589 GNUNET_sh2s (&tvr->challenge.value),
8590 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
8591 vs->sc = GNUNET_PEERSTORE_store (peerstore,
8592 "transport",
8593 &cmc->im.sender,
8594 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
8595 vs->address,
8596 strlen (vs->address) + 1,
8597 vs->valid_until,
8598 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
8599 &peerstore_store_validation_cb,
8600 vs);
8601 finish_cmc_handling (cmc);
8602
8603 /* Finally, we now possibly have a confirmed (!) working queue,
8604 update queue status (if queue still is around) */
8605 q = find_queue (&vs->pid, vs->address);
8606 if (NULL == q)
8607 {
8608 GNUNET_STATISTICS_update (GST_stats,
8609 "# Queues lost at time of successful validation",
8610 1,
8611 GNUNET_NO);
8612 return;
8613 }
8614 q->validated_until = vs->validated_until;
8615 q->pd.aged_rtt = vs->validation_rtt;
8616 n = q->neighbour;
8617 vl = lookup_virtual_link (&vs->pid);
8618 if (NULL == vl)
8619 {
8620 vl = GNUNET_new (struct VirtualLink);
8621 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8622 "Creating new virtual link %p to %s using direct neighbour!\n",
8623 vl,
8624 GNUNET_i2s (&vs->pid));
8625 vl->confirmed = GNUNET_YES;
8626 vl->message_uuid_ctr =
8627 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8628 vl->target = n->pid;
8629 vl->core_recv_window = RECV_WINDOW_SIZE;
8630 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8631 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
8632 GNUNET_break (GNUNET_YES ==
8633 GNUNET_CONTAINER_multipeermap_put (
8634 links,
8635 &vl->target,
8636 vl,
8637 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8638 vl->n = n;
8639 n->vl = vl;
8640 q->idle = GNUNET_YES;
8641 vl->visibility_task =
8642 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8643 consider_sending_fc (vl);
8644 /* We lacked a confirmed connection to the target
8645 before, so tell CORE about it (finally!) */
8646 cores_send_connect_info (&n->pid);
8647 }
8648 else
8649 {
8650 /* Link was already up, remember n is also now available and we are done */
8651 if (NULL == vl->n)
8652 {
8653 vl->n = n;
8654 n->vl = vl;
8655 if (GNUNET_YES == vl->confirmed)
8656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8657 "Virtual link to %s could now also direct neighbour!\n",
8658 GNUNET_i2s (&vs->pid));
8659 }
8660 else
8661 {
8662 GNUNET_assert (n == vl->n);
8663 }
8664 if (GNUNET_NO == vl->confirmed)
8665 {
8666 vl->confirmed = GNUNET_YES;
8667 q->idle = GNUNET_YES;
8668 vl->visibility_task =
8669 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
8670 consider_sending_fc (vl);
8671 /* We lacked a confirmed connection to the target
8672 before, so tell CORE about it (finally!) */
8673 cores_send_connect_info (&n->pid);
8674 }
8675 }
8676}
8677
8678
8679/**
8680 * Incoming meessage. Process the request.
8681 *
8682 * @param im the send message that was received
8683 */
8684static void
8685handle_incoming_msg (void *cls,
8686 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8687{
8688 struct TransportClient *tc = cls;
8689 struct CommunicatorMessageContext *cmc =
8690 GNUNET_new (struct CommunicatorMessageContext);
8691
8692 cmc->tc = tc;
8693 cmc->im = *im;
8694 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8695 "Received message with size %u via communicator from peer %s\n",
8696 &im->header.size,
8697 GNUNET_i2s (&im->sender));
8698 demultiplex_with_cmc (cmc, (const struct GNUNET_MessageHeader *) &im[1]);
8699}
8700
8701
8702/**
8703 * Communicator gave us a transport address validation response. Process the
8704 * request.
8705 *
8706 * @param cls a `struct CommunicatorMessageContext` (must call
8707 * #finish_cmc_handling() when done)
8708 * @param fc the message that was received
8709 */
8710static void
8711handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
8712{
8713 struct CommunicatorMessageContext *cmc = cls;
8714 struct VirtualLink *vl;
8715 uint32_t seq;
8716 struct GNUNET_TIME_Absolute st;
8717 uint64_t os;
8718 uint64_t wnd;
8719 uint32_t random;
8720
8721 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8722 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
8723 vl = lookup_virtual_link (&cmc->im.sender);
8724 if (NULL == vl)
8725 {
8726 vl = GNUNET_new (struct VirtualLink);
8727 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8728 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
8729 vl,
8730 GNUNET_i2s (&cmc->im.sender));
8731 vl->confirmed = GNUNET_NO;
8732 vl->message_uuid_ctr =
8733 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
8734 vl->target = cmc->im.sender;
8735 vl->core_recv_window = RECV_WINDOW_SIZE;
8736 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
8737 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
8738 GNUNET_break (GNUNET_YES ==
8739 GNUNET_CONTAINER_multipeermap_put (
8740 links,
8741 &vl->target,
8742 vl,
8743 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8744 }
8745 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
8746 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
8747 {
8748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8749 "FC dropped: Message out of order\n");
8750 /* out of order, drop */
8751 GNUNET_STATISTICS_update (GST_stats,
8752 "# FC dropped: message out of order",
8753 1,
8754 GNUNET_NO);
8755 finish_cmc_handling (cmc);
8756 return;
8757 }
8758 seq = ntohl (fc->seq);
8759 if (seq < vl->last_fc_seq)
8760 {
8761 /* Wrap-around/reset of other peer; start all counters from zero */
8762 vl->outbound_fc_window_size_used = 0;
8763 }
8764 vl->last_fc_seq = seq;
8765 vl->last_fc_timestamp = st;
8766 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
8767 os = GNUNET_ntohll (fc->outbound_sent);
8768 vl->incoming_fc_window_size_loss =
8769 (int64_t) (os - vl->incoming_fc_window_size_used);
8770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8771 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
8772 GNUNET_i2s (&vl->target),
8773 (unsigned int) seq,
8774 (unsigned long long) vl->outbound_fc_window_size,
8775 (long long) vl->incoming_fc_window_size_loss);
8776 wnd = GNUNET_ntohll (fc->outbound_window_size);
8777 random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
8778 UINT32_MAX);
8779 if ((GNUNET_YES == vl->confirmed) && ((wnd < vl->incoming_fc_window_size) ||
8780 (vl->last_outbound_window_size_received
8781 != wnd) ||
8782 (0 == random
8783 % FC_NO_CHANGE_REPLY_PROBABILITY)))
8784 {
8785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8786 "Consider re-sending our FC message, as clearly the other peer's idea of the window is not up-to-date (%llu vs %llu) or %llu last received differs, or random reply %lu\n",
8787 (unsigned long long) wnd,
8788 (unsigned long long) vl->incoming_fc_window_size,
8789 (unsigned long long) vl->last_outbound_window_size_received,
8790 random % FC_NO_CHANGE_REPLY_PROBABILITY);
8791 consider_sending_fc (vl);
8792 }
8793 if ((wnd == vl->incoming_fc_window_size) &&
8794 (vl->last_outbound_window_size_received == wnd) &&
8795 (NULL != vl->fc_retransmit_task))
8796 {
8797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8798 "Stopping FC retransmission to %s: peer is current at window %llu\n",
8799 GNUNET_i2s (&vl->target),
8800 (unsigned long long) wnd);
8801 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
8802 vl->fc_retransmit_task = NULL;
8803 vl->fc_retransmit_count = 0;
8804 }
8805 vl->last_outbound_window_size_received = wnd;
8806 /* FC window likely increased, check transmission possibilities! */
8807 check_vl_transmission (vl);
8808 finish_cmc_handling (cmc);
8809}
8810
8811
8812/**
8813 * Given an inbound message @a msg from a communicator @a cmc,
8814 * demultiplex it based on the type calling the right handler.
8815 *
8816 * @param cmc context for demultiplexing
8817 * @param msg message to demultiplex
8818 */
8819static void
8820demultiplex_with_cmc (struct CommunicatorMessageContext *cmc,
8821 const struct GNUNET_MessageHeader *msg)
8822{
8823 struct GNUNET_MQ_MessageHandler handlers[] =
8824 { GNUNET_MQ_hd_var_size (fragment_box,
8825 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
8826 struct TransportFragmentBoxMessage,
8827 cmc),
8828 GNUNET_MQ_hd_var_size (reliability_box,
8829 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
8830 struct TransportReliabilityBoxMessage,
8831 cmc),
8832 GNUNET_MQ_hd_var_size (reliability_ack,
8833 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
8834 struct TransportReliabilityAckMessage,
8835 cmc),
8836 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
8837 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
8838 struct TransportBackchannelEncapsulationMessage,
8839 cmc),
8840 GNUNET_MQ_hd_var_size (dv_learn,
8841 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
8842 struct TransportDVLearnMessage,
8843 cmc),
8844 GNUNET_MQ_hd_var_size (dv_box,
8845 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
8846 struct TransportDVBoxMessage,
8847 cmc),
8848 GNUNET_MQ_hd_fixed_size (
8849 validation_challenge,
8850 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
8851 struct TransportValidationChallengeMessage,
8852 cmc),
8853 GNUNET_MQ_hd_fixed_size (flow_control,
8854 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
8855 struct TransportFlowControlMessage,
8856 cmc),
8857 GNUNET_MQ_hd_fixed_size (
8858 validation_response,
8859 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
8860 struct TransportValidationResponseMessage,
8861 cmc),
8862 GNUNET_MQ_handler_end () };
8863 int ret;
8864
8865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8866 "Handling message of type %u with %u bytes\n",
8867 (unsigned int) ntohs (msg->type),
8868 (unsigned int) ntohs (msg->size));
8869 ret = GNUNET_MQ_handle_message (handlers, msg);
8870 if (GNUNET_SYSERR == ret)
8871 {
8872 GNUNET_break (0);
8873 GNUNET_SERVICE_client_drop (cmc->tc->client);
8874 GNUNET_free (cmc);
8875 return;
8876 }
8877 if (GNUNET_NO == ret)
8878 {
8879 /* unencapsulated 'raw' message */
8880 handle_raw_message (cmc, msg);
8881 }
8882}
8883
8884
8885/**
8886 * New queue became available. Check message.
8887 *
8888 * @param cls the client
8889 * @param aqm the send message that was sent
8890 */
8891static int
8892check_add_queue_message (void *cls,
8893 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
8894{
8895 struct TransportClient *tc = cls;
8896
8897 if (CT_COMMUNICATOR != tc->type)
8898 {
8899 GNUNET_break (0);
8900 return GNUNET_SYSERR;
8901 }
8902 GNUNET_MQ_check_zero_termination (aqm);
8903 return GNUNET_OK;
8904}
8905
8906
8907/**
8908 * If necessary, generates the UUID for a @a pm
8909 *
8910 * @param pm pending message to generate UUID for.
8911 */
8912static void
8913set_pending_message_uuid (struct PendingMessage *pm)
8914{
8915 if (pm->msg_uuid_set)
8916 return;
8917 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
8918 pm->msg_uuid_set = GNUNET_YES;
8919}
8920
8921
8922/**
8923 * Setup data structure waiting for acknowledgements.
8924 *
8925 * @param queue queue the @a pm will be sent over
8926 * @param dvh path the message will take, may be NULL
8927 * @param pm the pending message for transmission
8928 * @return corresponding fresh pending acknowledgement
8929 */
8930static struct PendingAcknowledgement *
8931prepare_pending_acknowledgement (struct Queue *queue,
8932 struct DistanceVectorHop *dvh,
8933 struct PendingMessage *pm)
8934{
8935 struct PendingAcknowledgement *pa;
8936
8937 pa = GNUNET_new (struct PendingAcknowledgement);
8938 pa->queue = queue;
8939 pa->dvh = dvh;
8940 pa->pm = pm;
8941 do
8942 {
8943 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8944 &pa->ack_uuid,
8945 sizeof(pa->ack_uuid));
8946 }
8947 while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
8948 pending_acks,
8949 &pa->ack_uuid.value,
8950 pa,
8951 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8952 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
8953 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
8954 if (NULL != dvh)
8955 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
8956 pa->transmission_time = GNUNET_TIME_absolute_get ();
8957 pa->message_size = pm->bytes_msg;
8958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8959 "Waiting for ACKnowledgment `%s' for <%llu>\n",
8960 GNUNET_uuid2s (&pa->ack_uuid.value),
8961 pm->logging_uuid);
8962 return pa;
8963}
8964
8965
8966/**
8967 * Fragment the given @a pm to the given @a mtu. Adds
8968 * additional fragments to the neighbour as well. If the
8969 * @a mtu is too small, generates and error for the @a pm
8970 * and returns NULL.
8971 *
8972 * @param queue which queue to fragment for
8973 * @param dvh path the message will take, or NULL
8974 * @param pm pending message to fragment for transmission
8975 * @return new message to transmit
8976 */
8977static struct PendingMessage *
8978fragment_message (struct Queue *queue,
8979 struct DistanceVectorHop *dvh,
8980 struct PendingMessage *pm)
8981{
8982 struct PendingAcknowledgement *pa;
8983 struct PendingMessage *ff;
8984 uint16_t mtu;
8985
8986 mtu = (UINT16_MAX == queue->mtu)
8987 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
8988 : queue->mtu;
8989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8990 "Fragmenting message <%llu> with size %u to %s for MTU %u\n",
8991 pm->logging_uuid,
8992 pm->bytes_msg,
8993 GNUNET_i2s (&pm->vl->target),
8994 (unsigned int) mtu);
8995 set_pending_message_uuid (pm);
8996 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8997 "Fragmenting message %llu <%llu> with size %u to %s for MTU %u\n",
8998 (unsigned long long) pm->msg_uuid.uuid,
8999 pm->logging_uuid,
9000 pm->bytes_msg,
9001 GNUNET_i2s (&pm->vl->target),
9002 (unsigned int) mtu);
9003
9004 /* This invariant is established in #handle_add_queue_message() */
9005 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
9006
9007 /* select fragment for transmission, descending the tree if it has
9008 been expanded until we are at a leaf or at a fragment that is small
9009 enough
9010 */
9011 ff = pm;
9012 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
9013 (ff->frag_off == ff->bytes_msg) && (NULL != ff->head_frag))
9014 {
9015 ff = ff->head_frag; /* descent into fragmented fragments */
9016 }
9017
9018 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < ff->bytes_msg))
9019 {
9020 /* Did not yet calculate all fragments, calculate next fragment */
9021 struct PendingMessage *frag;
9022 struct TransportFragmentBoxMessage tfb;
9023 const char *orig;
9024 char *msg;
9025 uint16_t fragmax;
9026 uint16_t fragsize;
9027 uint16_t msize;
9028 uint16_t xoff = 0;
9029
9030 orig = (const char *) &ff[1];
9031 msize = ff->bytes_msg;
9032 if (pm != ff)
9033 {
9034 const struct TransportFragmentBoxMessage *tfbo;
9035
9036 tfbo = (const struct TransportFragmentBoxMessage *) orig;
9037 orig += sizeof(struct TransportFragmentBoxMessage);
9038 msize -= sizeof(struct TransportFragmentBoxMessage);
9039 xoff = ntohs (tfbo->frag_off);
9040 }
9041 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
9042 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
9043 frag =
9044 GNUNET_malloc (sizeof(struct PendingMessage)
9045 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
9046 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9047 "3 created pm %p from pm %p storing vl %p from pm %p\n",
9048 frag,
9049 ff,
9050 pm->vl,
9051 pm);
9052 frag->logging_uuid = logging_uuid_gen++;
9053 frag->vl = pm->vl;
9054 frag->frag_parent = ff;
9055 frag->timeout = pm->timeout;
9056 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
9057 frag->pmt = PMT_FRAGMENT_BOX;
9058 msg = (char *) &frag[1];
9059 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
9060 tfb.header.size =
9061 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
9062 pa = prepare_pending_acknowledgement (queue, dvh, frag);
9063 tfb.ack_uuid = pa->ack_uuid;
9064 tfb.msg_uuid = pm->msg_uuid;
9065 tfb.frag_off = htons (ff->frag_off + xoff);
9066 tfb.msg_size = htons (pm->bytes_msg);
9067 memcpy (msg, &tfb, sizeof(tfb));
9068 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
9069 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag,
9070 ff->tail_frag, frag);
9071 ff->frag_off += fragsize;
9072 ff = frag;
9073 }
9074
9075 /* Move head to the tail and return it */
9076 GNUNET_CONTAINER_MDLL_remove (frag,
9077 ff->frag_parent->head_frag,
9078 ff->frag_parent->tail_frag,
9079 ff);
9080 GNUNET_CONTAINER_MDLL_insert_tail (frag,
9081 ff->frag_parent->head_frag,
9082 ff->frag_parent->tail_frag,
9083 ff);
9084
9085 return ff;
9086}
9087
9088
9089/**
9090 * Reliability-box the given @a pm. On error (can there be any), NULL
9091 * may be returned, otherwise the "replacement" for @a pm (which
9092 * should then be added to the respective neighbour's queue instead of
9093 * @a pm). If the @a pm is already fragmented or reliability boxed,
9094 * or itself an ACK, this function simply returns @a pm.
9095 *
9096 * @param queue which queue to prepare transmission for
9097 * @param dvh path the message will take, or NULL
9098 * @param pm pending message to box for transmission over unreliabile queue
9099 * @return new message to transmit
9100 */
9101static struct PendingMessage *
9102reliability_box_message (struct Queue *queue,
9103 struct DistanceVectorHop *dvh,
9104 struct PendingMessage *pm)
9105{
9106 struct TransportReliabilityBoxMessage rbox;
9107 struct PendingAcknowledgement *pa;
9108 struct PendingMessage *bpm;
9109 char *msg;
9110
9111 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
9112 return pm; /* already fragmented or reliability boxed, or control message:
9113 do nothing */
9114 if (NULL != pm->bpm)
9115 return pm->bpm; /* already computed earlier: do nothing */
9116 // TODO I guess we do not need this assertion. We might have a DLL with
9117 // fragments, because the MTU changed, and we do not need to fragment anymore.
9118 // But we should keep the fragments until message was completed, because
9119 // the MTU might change again.
9120 // GNUNET_assert (NULL == pm->head_frag);
9121 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
9122 {
9123 /* failed hard */
9124 GNUNET_break (0);
9125 client_send_response (pm);
9126 return NULL;
9127 }
9128
9129 pa = prepare_pending_acknowledgement (queue, dvh, pm);
9130
9131 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
9132 + pm->bytes_msg);
9133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9134 "4 created pm %p storing vl %p from pm %p\n",
9135 bpm,
9136 pm->vl,
9137 pm);
9138 bpm->logging_uuid = logging_uuid_gen++;
9139 bpm->vl = pm->vl;
9140 bpm->frag_parent = pm;
9141 // Why was this needed?
9142 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
9143 bpm->timeout = pm->timeout;
9144 bpm->pmt = PMT_RELIABILITY_BOX;
9145 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
9146 set_pending_message_uuid (bpm);
9147 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
9148 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
9149 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
9150
9151 rbox.ack_uuid = pa->ack_uuid;
9152 msg = (char *) &bpm[1];
9153 memcpy (msg, &rbox, sizeof(rbox));
9154 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
9155 pm->bpm = bpm;
9156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9157 "Preparing reliability box for message <%llu> of size %lu (%lu) to %s on queue %s\n",
9158 pm->logging_uuid,
9159 pm->bytes_msg,
9160 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
9161 GNUNET_i2s (&pm->vl->target),
9162 queue->address);
9163 return bpm;
9164}
9165
9166
9167static void
9168reorder_root_pm (struct PendingMessage *pm,
9169 struct GNUNET_TIME_Absolute next_attempt)
9170{
9171 struct VirtualLink *vl = pm->vl;
9172 struct PendingMessage *pos;
9173
9174 /* re-insert sort in neighbour list */
9175 GNUNET_CONTAINER_MDLL_remove (vl,
9176 vl->pending_msg_head,
9177 vl->pending_msg_tail,
9178 pm);
9179 pos = vl->pending_msg_tail;
9180 while ((NULL != pos) &&
9181 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
9182 pos = pos->prev_vl;
9183 GNUNET_CONTAINER_MDLL_insert_after (vl,
9184 vl->pending_msg_head,
9185 vl->pending_msg_tail,
9186 pos,
9187 pm);
9188}
9189
9190
9191/**
9192 * Change the value of the `next_attempt` field of @a pm
9193 * to @a next_attempt and re-order @a pm in the transmission
9194 * list as required by the new timestamp.
9195 *
9196 * @param pm a pending message to update
9197 * @param next_attempt timestamp to use
9198 */
9199static void
9200update_pm_next_attempt (struct PendingMessage *pm,
9201 struct GNUNET_TIME_Absolute next_attempt)
9202{
9203 struct VirtualLink *vl = pm->vl;
9204
9205 // TODO Do we really need a next_attempt value for PendingMessage other than the root Pending Message?
9206 pm->next_attempt = next_attempt;
9207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9208 "Next attempt for message <%llu> set to %s\n",
9209 pm->logging_uuid,
9210 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
9211
9212 if (NULL == pm->frag_parent)
9213 {
9214 reorder_root_pm (pm, next_attempt);
9215 }
9216 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))
9217 {
9218 struct PendingMessage *root = pm->frag_parent;
9219
9220 while (NULL != root->frag_parent)
9221 root = root->frag_parent;
9222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9223 "Next attempt for root message <%llu> set to %s\n",
9224 root->logging_uuid);
9225 root->next_attempt = next_attempt;
9226 reorder_root_pm (root, next_attempt);
9227 }
9228 else
9229 {
9230 /* re-insert sort in fragment list */
9231 struct PendingMessage *fp = pm->frag_parent;
9232 struct PendingMessage *pos;
9233
9234 GNUNET_CONTAINER_MDLL_remove (frag, fp->head_frag, fp->tail_frag, pm);
9235 pos = fp->tail_frag;
9236 while ((NULL != pos) &&
9237 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
9238 pos = pos->prev_frag;
9239 GNUNET_CONTAINER_MDLL_insert_after (frag,
9240 fp->head_frag,
9241 fp->tail_frag,
9242 pos,
9243 pm);
9244 if (NULL == pos)
9245 {
9246 pos = fp;
9247 // Get the root pm
9248 while (NULL != pos->frag_parent)
9249 pos = pos->frag_parent;
9250 pos->next_attempt = next_attempt;
9251 reorder_root_pm (pos, next_attempt);
9252 }
9253 }
9254}
9255
9256
9257/**
9258 * Context for #select_best_pending_from_link().
9259 */
9260struct PendingMessageScoreContext
9261{
9262 /**
9263 * Set to the best message that was found, NULL for none.
9264 */
9265 struct PendingMessage *best;
9266
9267 /**
9268 * DVH that @e best should take, or NULL for direct transmission.
9269 */
9270 struct DistanceVectorHop *dvh;
9271
9272 /**
9273 * What is the estimated total overhead for this message?
9274 */
9275 size_t real_overhead;
9276
9277 /**
9278 * Number of pending messages we seriously considered this time.
9279 */
9280 unsigned int consideration_counter;
9281
9282 /**
9283 * Did we have to fragment?
9284 */
9285 int frag;
9286
9287 /**
9288 * Did we have to reliability box?
9289 */
9290 int relb;
9291
9292 /**
9293 * There are pending messages, but it was to early to send one of them.
9294 */
9295 int to_early;
9296
9297 /**
9298 * When will we try to transmit the message again for which it was to early to retry.
9299 */
9300 struct GNUNET_TIME_Relative to_early_retry_delay;
9301};
9302
9303
9304/**
9305 * Select the best pending message from @a vl for transmission
9306 * via @a queue.
9307 *
9308 * @param sc[in,out] best message so far (NULL for none), plus scoring data
9309 * @param queue the queue that will be used for transmission
9310 * @param vl the virtual link providing the messages
9311 * @param dvh path we are currently considering, or NULL for none
9312 * @param overhead number of bytes of overhead to be expected
9313 * from DV encapsulation (0 for without DV)
9314 */
9315static void
9316select_best_pending_from_link (struct PendingMessageScoreContext *sc,
9317 struct Queue *queue,
9318 struct VirtualLink *vl,
9319 struct DistanceVectorHop *dvh,
9320 size_t overhead)
9321{
9322 struct GNUNET_TIME_Absolute now;
9323
9324 now = GNUNET_TIME_absolute_get ();
9325 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
9326 pos = pos->next_vl)
9327 {
9328 size_t real_overhead = overhead;
9329 int frag;
9330 int relb;
9331
9332 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
9333 {
9334 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9335 "DV messages must not be DV-routed to next hop!\n");
9336 continue; /* DV messages must not be DV-routed to next hop! */
9337 }
9338 if (pos->next_attempt.abs_value_us > now.abs_value_us)
9339 {
9340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9341 "too early for all messages, they are sorted by next_attempt\n");
9342 sc->to_early = GNUNET_YES;
9343 sc->to_early_retry_delay = GNUNET_TIME_absolute_get_remaining (
9344 pos->next_attempt);
9345
9346 break; /* too early for all messages, they are sorted by next_attempt */
9347 }
9348 sc->to_early = GNUNET_NO;
9349 if (NULL != pos->qe)
9350 {
9351 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9352 "not eligible\n");
9353 continue; /* not eligible */
9354 }
9355 sc->consideration_counter++;
9356 /* determine if we have to fragment, if so add fragmentation
9357 overhead! */
9358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9359 "check %u for sc->best\n",
9360 pos->logging_uuid);
9361 frag = GNUNET_NO;
9362 if (((0 != queue->mtu) &&
9363 (pos->bytes_msg + real_overhead > queue->mtu)) ||
9364 (pos->bytes_msg > UINT16_MAX - sizeof(struct
9365 GNUNET_TRANSPORT_SendMessageTo))
9366 ||
9367 (NULL != pos->head_frag /* fragments already exist, should
9368 respect that even if MTU is UINT16_MAX for
9369 this queue */))
9370 {
9371 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9372 "fragment msg with size %u, realoverhead is %u\n",
9373 pos->bytes_msg,
9374 real_overhead);
9375 frag = GNUNET_YES;
9376 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
9377 {
9378 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
9379 header without the ACK UUID when using a *reliable* channel! */
9380 }
9381 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
9382 }
9383 /* determine if we have to reliability-box, if so add reliability box
9384 overhead */
9385 relb = GNUNET_NO;
9386 if ((GNUNET_NO == frag) &&
9387 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
9388 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
9389 {
9390 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
9391
9392 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
9393 {
9394 frag = GNUNET_YES;
9395 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
9396 }
9397 else
9398 {
9399 relb = GNUNET_YES;
9400 }
9401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9402 "Create reliability box of msg with size %u, realoverhead is %u %u %u %u\n",
9403 pos->bytes_msg,
9404 real_overhead,
9405 queue->mtu,
9406 frag,
9407 relb);
9408 }
9409
9410 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
9411 message would beat it! */
9412 if (NULL != sc->best)
9413 {
9414 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
9415 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
9416 experimentally validated. There may be some huge potential for
9417 improvement here. Also, we right now only compare how well the
9418 given message fits _this_ queue, and do not consider how well other
9419 queues might suit the message. Taking other queues into consideration
9420 may further improve the result, but could also be expensive
9421 in terms of CPU time. */
9422 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
9423 long long pm_score = frag * 40 + relb * 20 + real_overhead;
9424 long long time_delta =
9425 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
9426 / 1000LL;
9427
9428 /* "time_delta" considers which message has been 'ready' for transmission
9429 for longer, if a message has a preference for low latency, increase
9430 the weight of the time_delta by 10x if it is favorable for that message */
9431 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9432 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
9433 time_delta *= 10; /* increase weight (always, both are low latency) */
9434 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9435 (time_delta > 0))
9436 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
9437 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
9438 (time_delta < 0))
9439 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
9440 if (0 != queue->mtu)
9441 {
9442 /* Grant bonus if we are below MTU, larger bonus the closer we will
9443 be to the MTU */
9444 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
9445 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
9446 if (queue->mtu > real_overhead + pos->bytes_msg)
9447 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
9448 }
9449 if (sc_score + time_delta > pm_score)
9450 {
9451 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9452 "sc_score of %u larger, keep sc->best %u\n",
9453 pos->logging_uuid,
9454 sc->best->logging_uuid);
9455 continue; /* sc_score larger, keep sc->best */
9456 }
9457 }
9458 sc->best = pos;
9459 sc->dvh = dvh;
9460 sc->frag = frag;
9461 sc->relb = relb;
9462 sc->real_overhead = real_overhead;
9463 }
9464}
9465
9466
9467/**
9468 * Function to call to further operate on the now DV encapsulated
9469 * message @a hdr, forwarding it via @a next_hop under respect of
9470 * @a options.
9471 *
9472 * @param cls a `struct PendingMessageScoreContext`
9473 * @param next_hop next hop of the DV path
9474 * @param hdr encapsulated message, technically a `struct TransportDVBoxMessage`
9475 * @param options options of the original message
9476 */
9477static void
9478extract_box_cb (void *cls,
9479 struct Neighbour *next_hop,
9480 const struct GNUNET_MessageHeader *hdr,
9481 enum RouteMessageOptions options)
9482{
9483 struct PendingMessageScoreContext *sc = cls;
9484 struct PendingMessage *pm = sc->best;
9485 struct PendingMessage *bpm;
9486 uint16_t bsize = ntohs (hdr->size);
9487
9488 GNUNET_assert (NULL == pm->bpm);
9489 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
9490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9491 "5 created pm %p storing vl %p from pm %p\n",
9492 bpm,
9493 pm->vl,
9494 pm);
9495 bpm->logging_uuid = logging_uuid_gen++;
9496 bpm->pmt = PMT_DV_BOX;
9497 bpm->vl = pm->vl;
9498 bpm->timeout = pm->timeout;
9499 bpm->bytes_msg = bsize;
9500 bpm->frag_parent = pm;
9501 set_pending_message_uuid (bpm);
9502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9503 "Creating DV Box %llu for original message %llu (next hop is %s)\n",
9504 bpm->logging_uuid,
9505 pm->logging_uuid,
9506 GNUNET_i2s (&next_hop->pid));
9507 memcpy (&bpm[1], hdr, bsize);
9508 pm->bpm = bpm;
9509}
9510
9511
9512/**
9513 * We believe we are ready to transmit a `struct PendingMessage` on a
9514 * queue, the big question is which one! We need to see if there is
9515 * one pending that is allowed by flow control and congestion control
9516 * and (ideally) matches our queue's performance profile.
9517 *
9518 * If such a message is found, we give the message to the communicator
9519 * for transmission (updating the tracker, and re-scheduling ourselves
9520 * if applicable).
9521 *
9522 * If no such message is found, the queue's `idle` field must be set
9523 * to #GNUNET_YES.
9524 *
9525 * @param cls the `struct Queue` to process transmissions for
9526 */
9527static void
9528transmit_on_queue (void *cls)
9529{
9530 struct Queue *queue = cls;
9531 struct Neighbour *n = queue->neighbour;
9532 struct PendingMessageScoreContext sc;
9533 struct PendingMessage *pm;
9534
9535 queue->transmit_task = NULL;
9536 if (NULL == n->vl)
9537 {
9538 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9539 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
9540 GNUNET_i2s (&n->pid),
9541 queue->address);
9542 queue->idle = GNUNET_YES;
9543 return;
9544 }
9545 memset (&sc, 0, sizeof(sc));
9546 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
9547 if (NULL == sc.best)
9548 {
9549 /* Also look at DVH that have the n as first hop! */
9550 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
9551 dvh = dvh->next_neighbour)
9552 {
9553 select_best_pending_from_link (&sc,
9554 queue,
9555 dvh->dv->vl,
9556 dvh,
9557 sizeof(struct GNUNET_PeerIdentity)
9558 * (1 + dvh->distance)
9559 + sizeof(struct TransportDVBoxMessage)
9560 + sizeof(struct TransportDVBoxPayloadP));
9561 }
9562 }
9563 if (NULL == sc.best)
9564 {
9565 /* no message pending, nothing to do here! */
9566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9567 "No pending messages, queue `%s' to %s now idle\n",
9568 queue->address,
9569 GNUNET_i2s (&n->pid));
9570 if (GNUNET_YES == sc.to_early)
9571 schedule_transmit_on_queue (sc.to_early_retry_delay,
9572 queue,
9573 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9574 queue->idle = GNUNET_YES;
9575 return;
9576 }
9577 /* There is a message pending, we are certainly not idle */
9578 queue->idle = GNUNET_NO;
9579
9580 /* Given selection in `sc`, do transmission */
9581 pm = sc.best;
9582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9583 "Selected message <%llu>\n",
9584 pm->logging_uuid);
9585 if (NULL != sc.dvh)
9586 {
9587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9588 "Is this %u a DV box?\n",
9589 pm->pmt);
9590 GNUNET_assert (PMT_DV_BOX != pm->pmt);
9591 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
9592 {
9593 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9594 "Discard old box, because we have a new DV path.\n");
9595 free_pending_message (sc.best->bpm);
9596 sc.best->bpm = NULL;
9597 }
9598
9599 if (NULL == sc.best->bpm)
9600 {
9601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9602 "encapsulate_for_dv 2\n");
9603 encapsulate_for_dv (sc.dvh->dv,
9604 1,
9605 &sc.dvh,
9606 (const struct GNUNET_MessageHeader *) &sc.best[1],
9607 &extract_box_cb,
9608 &sc,
9609 RMO_NONE,
9610 GNUNET_NO);
9611 GNUNET_assert (NULL != sc.best->bpm);
9612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9613 "%u %u %u %u %u\n",
9614 sizeof(struct GNUNET_PeerIdentity),
9615 sizeof(struct TransportDVBoxMessage),
9616 sizeof(struct TransportDVBoxPayloadP),
9617 sizeof(struct TransportFragmentBoxMessage),
9618 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
9619 sc.best->bpm->used_dvh = sc.dvh;
9620 }
9621 pm = sc.best->bpm;
9622 }
9623 if (GNUNET_YES == sc.frag)
9624 {
9625 pm = fragment_message (queue, sc.dvh, pm);
9626 if (NULL == pm)
9627 {
9628 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9629 "Fragmentation failed queue %s to %s for <%llu>, trying again\n",
9630 queue->address,
9631 GNUNET_i2s (&n->pid),
9632 sc.best->logging_uuid);
9633 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9634 queue,
9635 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9636 return;
9637 }
9638 }
9639 else if (GNUNET_YES == sc.relb)
9640 {
9641 pm = reliability_box_message (queue, sc.dvh, pm);
9642 if (NULL == pm)
9643 {
9644 /* Reliability boxing failed, try next message... */
9645 GNUNET_log (
9646 GNUNET_ERROR_TYPE_DEBUG,
9647 "Reliability boxing failed queue %s to %s for <%llu>, trying again\n",
9648 queue->address,
9649 GNUNET_i2s (&n->pid),
9650 sc.best->logging_uuid);
9651 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9652 queue,
9653 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9654 return;
9655 }
9656 }
9657
9658 /* Pass 'pm' for transission to the communicator */
9659 GNUNET_log (
9660 GNUNET_ERROR_TYPE_DEBUG,
9661 "Passing message <%llu> to queue %s for peer %s (considered %u others)\n",
9662 pm->logging_uuid,
9663 queue->address,
9664 GNUNET_i2s (&n->pid),
9665 sc.consideration_counter);
9666
9667 /* Flow control: increment amount of traffic sent; if we are routing
9668 via DV (and thus the ultimate target of the pending message is for
9669 a different virtual link than the one of the queue), then we need
9670 to use up not only the window of the direct link but also the
9671 flow control window for the DV link! */
9672 pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
9673
9674 if (pm->vl != queue->neighbour->vl)
9675 {
9676 /* If the virtual link of the queue differs, this better be distance
9677 vector routing! */
9678 GNUNET_assert (NULL != sc.dvh);
9679 /* If we do distance vector routing, we better not do this for a
9680 message that was itself DV-routed */
9681 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
9682 /* We use the size of the unboxed message here, to avoid counting
9683 the DV-Box header which is eaten up on the way by intermediaries */
9684 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
9685 }
9686 else
9687 {
9688 GNUNET_assert (NULL == sc.dvh);
9689 }
9690
9691 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
9692
9693 /* Check if this transmission somehow conclusively finished handing 'pm'
9694 even without any explicit ACKs */
9695 if ((PMT_CORE == pm->pmt) ||
9696 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
9697 {
9698 completed_pending_message (pm);
9699 }
9700 else
9701 {
9702 struct GNUNET_TIME_Relative wait_duration;
9703
9704 /* Message not finished, waiting for acknowledgement.
9705 Update time by which we might retransmit 's' based on queue
9706 characteristics (i.e. RTT); it takes one RTT for the message to
9707 arrive and the ACK to come back in the best case; but the other
9708 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
9709 retransmitting.
9710
9711 OPTIMIZE: Note that in the future this heuristic should likely
9712 be improved further (measure RTT stability, consider message
9713 urgency and size when delaying ACKs, etc.) */
9714
9715 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
9716 queue->pd.aged_rtt.rel_value_us)
9717 wait_duration = queue->pd.aged_rtt;
9718 else
9719 wait_duration = DEFAULT_ACK_WAIT_DURATION;
9720 struct GNUNET_TIME_Absolute next = GNUNET_TIME_relative_to_absolute (
9721 GNUNET_TIME_relative_multiply (
9722 wait_duration, 4));
9723 struct GNUNET_TIME_Relative plus = GNUNET_TIME_relative_multiply (
9724 wait_duration, 4);
9725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9726 "Waiting %s (%llu) for ACK until %llu\n",
9727 GNUNET_STRINGS_relative_time_to_string (
9728 GNUNET_TIME_relative_multiply (
9729 queue->pd.aged_rtt, 4), GNUNET_NO),
9730 plus,
9731 next);
9732 update_pm_next_attempt (pm,
9733 GNUNET_TIME_relative_to_absolute (
9734 GNUNET_TIME_relative_multiply (wait_duration,
9735 4)));
9736 }
9737 /* finally, re-schedule queue transmission task itself */
9738 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9739 queue,
9740 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9741}
9742
9743
9744/**
9745 * Queue to a peer went down. Process the request.
9746 *
9747 * @param cls the client
9748 * @param dqm the send message that was sent
9749 */
9750static void
9751handle_del_queue_message (void *cls,
9752 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
9753{
9754 struct TransportClient *tc = cls;
9755
9756 if (CT_COMMUNICATOR != tc->type)
9757 {
9758 GNUNET_break (0);
9759 GNUNET_SERVICE_client_drop (tc->client);
9760 return;
9761 }
9762 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
9763 queue = queue->next_client)
9764 {
9765 struct Neighbour *neighbour = queue->neighbour;
9766
9767 if ((dqm->qid != queue->qid) ||
9768 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
9769 continue;
9770 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9771 "Dropped queue %s to peer %s\n",
9772 queue->address,
9773 GNUNET_i2s (&neighbour->pid));
9774 free_queue (queue);
9775 GNUNET_SERVICE_client_continue (tc->client);
9776 return;
9777 }
9778 GNUNET_break (0);
9779 GNUNET_SERVICE_client_drop (tc->client);
9780}
9781
9782
9783/**
9784 * Message was transmitted. Process the request.
9785 *
9786 * @param cls the client
9787 * @param sma the send message that was sent
9788 */
9789static void
9790handle_send_message_ack (void *cls,
9791 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
9792{
9793 struct TransportClient *tc = cls;
9794 struct QueueEntry *qe;
9795 struct PendingMessage *pm;
9796
9797 if (CT_COMMUNICATOR != tc->type)
9798 {
9799 GNUNET_break (0);
9800 GNUNET_SERVICE_client_drop (tc->client);
9801 return;
9802 }
9803
9804 /* find our queue entry matching the ACK */
9805 qe = NULL;
9806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9807 "Looking for queue for PID %s\n",
9808 GNUNET_i2s (&sma->receiver));
9809 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
9810 queue = queue->next_client)
9811 {
9812 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
9813 continue;
9814 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9815 "Found PID %s\n",
9816 GNUNET_i2s (&queue->neighbour->pid));
9817
9818
9819 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
9820 qep = qep->next)
9821 {
9822 if (qep->mid != sma->mid)
9823 continue;
9824 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9825 "QueueEntry MID: %llu on queue QID: %llu, Ack MID: %llu\n",
9826 (unsigned long long) qep->mid,
9827 (unsigned long long) queue->qid,
9828 (unsigned long long) sma->mid);
9829 qe = qep;
9830 if ((NULL != qe->pm)&&(qe->pm->qe != qe))
9831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9832 "For pending message %llu we had retransmissions.\n",
9833 qe->pm->logging_uuid);
9834 break;
9835 }
9836 }
9837 if (NULL == qe)
9838 {
9839 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9840 "No QueueEntry found for Ack MID %llu\n",
9841 (unsigned long long) sma->mid);
9842 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
9843 /* this should never happen */
9844 /*GNUNET_break (0);
9845 GNUNET_SERVICE_client_drop (tc->client);*/
9846 GNUNET_SERVICE_client_continue (tc->client);
9847 return;
9848 }
9849 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
9850 qe->queue->queue_tail,
9851 qe);
9852 qe->queue->queue_length--;
9853 tc->details.communicator.total_queue_length--;
9854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9855 "Received ACK on queue %s to peer %s (new length: %u/%u)\n",
9856 qe->queue->address,
9857 GNUNET_i2s (&qe->queue->neighbour->pid),
9858 qe->queue->queue_length,
9859 tc->details.communicator.total_queue_length);
9860 GNUNET_SERVICE_client_continue (tc->client);
9861
9862 /* if applicable, resume transmissions that waited on ACK */
9863 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
9864 tc->details.communicator.total_queue_length)
9865 {
9866 /* Communicator dropped below threshold, resume all queues
9867 incident with this client! */
9868 GNUNET_STATISTICS_update (
9869 GST_stats,
9870 "# Transmission throttled due to communicator queue limit",
9871 -1,
9872 GNUNET_NO);
9873 for (struct Queue *queue = tc->details.communicator.queue_head;
9874 NULL != queue;
9875 queue = queue->next_client)
9876 {
9877 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9878 queue,
9879 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9880 }
9881 }
9882 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
9883 {
9884 /* queue dropped below threshold; only resume this one queue */
9885 GNUNET_STATISTICS_update (GST_stats,
9886 "# Transmission throttled due to queue queue limit",
9887 -1,
9888 GNUNET_NO);
9889 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9890 qe->queue,
9891 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9892 }
9893 else if (1 == qe->queue->q_capacity)
9894 {
9895 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
9896 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9897 "Transmission rescheduled due to communicator message queue with qid %u has capacity %lu.\n",
9898 qe->queue->qid,
9899 qe->queue->q_capacity);
9900 /* message queue has capacity; only resume this one queue */
9901 /* queue dropped below threshold; only resume this one queue */
9902 GNUNET_STATISTICS_update (GST_stats,
9903 "# Transmission throttled due to message queue capacity",
9904 -1,
9905 GNUNET_NO);
9906 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
9907 qe->queue,
9908 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
9909 }
9910
9911 if (NULL != (pm = qe->pm))
9912 {
9913 struct VirtualLink *vl;
9914
9915 // GNUNET_assert (qe == pm->qe);
9916 pm->qe = NULL;
9917 /* If waiting for this communicator may have blocked transmission
9918 of pm on other queues for this neighbour, force schedule
9919 transmit on queue for queues of the neighbour */
9920 if (NULL == pm->frag_parent)
9921 {
9922 vl = pm->vl;
9923 if ((NULL != vl) &&
9924 (NULL != vl->pending_msg_head) &&
9925 (vl->pending_msg_head == pm))
9926 check_vl_transmission (vl);
9927 }
9928 }
9929 GNUNET_free (qe);
9930}
9931
9932
9933/**
9934 * Iterator telling new MONITOR client about all existing
9935 * queues to peers.
9936 *
9937 * @param cls the new `struct TransportClient`
9938 * @param pid a connected peer
9939 * @param value the `struct Neighbour` with more information
9940 * @return #GNUNET_OK (continue to iterate)
9941 */
9942static int
9943notify_client_queues (void *cls,
9944 const struct GNUNET_PeerIdentity *pid,
9945 void *value)
9946{
9947 struct TransportClient *tc = cls;
9948 struct Neighbour *neighbour = value;
9949
9950 GNUNET_assert (CT_MONITOR == tc->type);
9951 for (struct Queue *q = neighbour->queue_head; NULL != q;
9952 q = q->next_neighbour)
9953 {
9954 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
9955 .cs = q->cs,
9956 .num_msg_pending = q->num_msg_pending,
9957 .num_bytes_pending = q->num_bytes_pending };
9958
9959 notify_monitor (tc, pid, q->address, q->nt, &me);
9960 }
9961 return GNUNET_OK;
9962}
9963
9964
9965/**
9966 * Initialize a monitor client.
9967 *
9968 * @param cls the client
9969 * @param start the start message that was sent
9970 */
9971static void
9972handle_monitor_start (void *cls,
9973 const struct GNUNET_TRANSPORT_MonitorStart *start)
9974{
9975 struct TransportClient *tc = cls;
9976
9977 if (CT_NONE != tc->type)
9978 {
9979 GNUNET_break (0);
9980 GNUNET_SERVICE_client_drop (tc->client);
9981 return;
9982 }
9983 tc->type = CT_MONITOR;
9984 tc->details.monitor.peer = start->peer;
9985 tc->details.monitor.one_shot = ntohl (start->one_shot);
9986 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &notify_client_queues, tc);
9987 GNUNET_SERVICE_client_mark_monitor (tc->client);
9988 GNUNET_SERVICE_client_continue (tc->client);
9989}
9990
9991
9992/**
9993 * Find transport client providing communication service
9994 * for the protocol @a prefix.
9995 *
9996 * @param prefix communicator name
9997 * @return NULL if no such transport client is available
9998 */
9999static struct TransportClient *
10000lookup_communicator (const char *prefix)
10001{
10002 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
10003 {
10004 if (CT_COMMUNICATOR != tc->type)
10005 continue;
10006 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
10007 return tc;
10008 }
10009 GNUNET_log (
10010 GNUNET_ERROR_TYPE_WARNING,
10011 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
10012 prefix);
10013 return NULL;
10014}
10015
10016
10017/**
10018 * Signature of a function called with a communicator @a address of a peer
10019 * @a pid that an application wants us to connect to.
10020 *
10021 * @param pid target peer
10022 * @param address the address to try
10023 */
10024static void
10025suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
10026{
10027 static uint32_t idgen;
10028 struct TransportClient *tc;
10029 char *prefix;
10030 struct GNUNET_TRANSPORT_CreateQueue *cqm;
10031 struct GNUNET_MQ_Envelope *env;
10032 size_t alen;
10033
10034 prefix = GNUNET_HELLO_address_to_prefix (address);
10035 if (NULL == prefix)
10036 {
10037 GNUNET_break (0); /* We got an invalid address!? */
10038 return;
10039 }
10040 tc = lookup_communicator (prefix);
10041 if (NULL == tc)
10042 {
10043 GNUNET_STATISTICS_update (GST_stats,
10044 "# Suggestions ignored due to missing communicator",
10045 1,
10046 GNUNET_NO);
10047 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10048 "Cannot connect to %s at `%s', no matching communicator present\n",
10049 GNUNET_i2s (pid),
10050 address);
10051 GNUNET_free (prefix);
10052 return;
10053 }
10054 /* forward suggestion for queue creation to communicator */
10055 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10056 "Request #%u for `%s' communicator to create queue to `%s'\n",
10057 (unsigned int) idgen,
10058 prefix,
10059 address);
10060 GNUNET_free (prefix);
10061 alen = strlen (address) + 1;
10062 env =
10063 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
10064 cqm->request_id = htonl (idgen++);
10065 cqm->receiver = *pid;
10066 memcpy (&cqm[1], address, alen);
10067 GNUNET_MQ_send (tc->mq, env);
10068}
10069
10070
10071/**
10072 * The queue @a q (which matches the peer and address in @a vs) is
10073 * ready for queueing. We should now queue the validation request.
10074 *
10075 * @param q queue to send on
10076 * @param vs state to derive validation challenge from
10077 */
10078static void
10079validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
10080{
10081 struct TransportValidationChallengeMessage tvc;
10082
10083 vs->last_challenge_use = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
10084 tvc.header.type =
10085 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
10086 tvc.header.size = htons (sizeof(tvc));
10087 tvc.reserved = htonl (0);
10088 tvc.challenge = vs->challenge;
10089 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
10090 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10091 "Sending address validation challenge %s to %s\n",
10092 GNUNET_sh2s (&tvc.challenge.value),
10093 GNUNET_i2s (&q->neighbour->pid));
10094 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
10095}
10096
10097
10098/**
10099 * Task run periodically to validate some address based on #validation_heap.
10100 *
10101 * @param cls NULL
10102 */
10103static void
10104validation_start_cb (void *cls)
10105{
10106 struct ValidationState *vs;
10107 struct Queue *q;
10108
10109 (void) cls;
10110 validation_task = NULL;
10111 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
10112 /* drop validations past their expiration */
10113 while (
10114 (NULL != vs) &&
10115 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
10116 {
10117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10118 "Validation response %s cleaned up\n",
10119 GNUNET_sh2s (&vs->challenge.value));
10120 free_validation_state (vs);
10121 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
10122 }
10123 if (NULL == vs)
10124 {
10125 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
10126 "Address validation task not scheduled anymore, nothing to do\n");
10127 return; /* woopsie, no more addresses known, should only
10128 happen if we're really a lonely peer */
10129 }
10130 q = find_queue (&vs->pid, vs->address);
10131 if (NULL == q)
10132 {
10133 vs->awaiting_queue = GNUNET_YES;
10134 suggest_to_connect (&vs->pid, vs->address);
10135 }
10136 else
10137 validation_transmit_on_queue (q, vs);
10138 /* Finally, reschedule next attempt */
10139 vs->challenge_backoff =
10140 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
10141 MAX_VALIDATION_CHALLENGE_FREQ);
10142 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10143 "Address validation task will run again in %s\n",
10144 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
10145 GNUNET_YES));
10146 update_next_challenge_time (vs,
10147 GNUNET_TIME_relative_to_absolute (
10148 vs->challenge_backoff));
10149}
10150
10151
10152/**
10153 * Closure for #check_connection_quality.
10154 */
10155struct QueueQualityContext
10156{
10157 /**
10158 * Set to the @e k'th queue encountered.
10159 */
10160 struct Queue *q;
10161
10162 /**
10163 * Set to the number of quality queues encountered.
10164 */
10165 unsigned int quality_count;
10166
10167 /**
10168 * Set to the total number of queues encountered.
10169 */
10170 unsigned int num_queues;
10171
10172 /**
10173 * Decremented for each queue, for selection of the
10174 * k-th queue in @e q.
10175 */
10176 unsigned int k;
10177};
10178
10179
10180/**
10181 * Check whether any queue to the given neighbour is
10182 * of a good "quality" and if so, increment the counter.
10183 * Also counts the total number of queues, and returns
10184 * the k-th queue found.
10185 *
10186 * @param cls a `struct QueueQualityContext *` with counters
10187 * @param pid peer this is about
10188 * @param value a `struct Neighbour`
10189 * @return #GNUNET_OK (continue to iterate)
10190 */
10191static int
10192check_connection_quality (void *cls,
10193 const struct GNUNET_PeerIdentity *pid,
10194 void *value)
10195{
10196 struct QueueQualityContext *ctx = cls;
10197 struct Neighbour *n = value;
10198 int do_inc;
10199
10200 (void) pid;
10201 do_inc = GNUNET_NO;
10202 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
10203 {
10204 ctx->num_queues++;
10205 if (0 == ctx->k--)
10206 ctx->q = q;
10207 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
10208 statistics and consider those as well here? */
10209 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
10210 do_inc = GNUNET_YES;
10211 }
10212 if (GNUNET_YES == do_inc)
10213 ctx->quality_count++;
10214 return GNUNET_OK;
10215}
10216
10217
10218/**
10219 * Task run when we CONSIDER initiating a DV learn
10220 * process. We first check that sending out a message is
10221 * even possible (queues exist), then that it is desirable
10222 * (if not, reschedule the task for later), and finally
10223 * we may then begin the job. If there are too many
10224 * entries in the #dvlearn_map, we purge the oldest entry
10225 * using #lle_tail.
10226 *
10227 * @param cls NULL
10228 */
10229static void
10230start_dv_learn (void *cls)
10231{
10232 struct LearnLaunchEntry *lle;
10233 struct QueueQualityContext qqc;
10234 struct TransportDVLearnMessage dvl;
10235
10236 (void) cls;
10237 dvlearn_task = NULL;
10238 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
10239 return; /* lost all connectivity, cannot do learning */
10240 qqc.quality_count = 0;
10241 qqc.num_queues = 0;
10242 qqc.k = GNUNET_CONTAINER_multipeermap_size (neighbours);
10243 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10244 &check_connection_quality,
10245 &qqc);
10246 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
10247 {
10248 struct GNUNET_TIME_Relative delay;
10249 unsigned int factor;
10250
10251 /* scale our retries by how far we are above the threshold */
10252 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
10253 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
10254 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10255 "At connection quality %u, will launch DV learn in %s\n",
10256 qqc.quality_count,
10257 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
10258 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
10259 return;
10260 }
10261 /* remove old entries in #dvlearn_map if it has grown too big */
10262 while (MAX_DV_LEARN_PENDING <=
10263 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
10264 {
10265 lle = lle_tail;
10266 GNUNET_assert (GNUNET_YES ==
10267 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
10268 &lle->challenge.value,
10269 lle));
10270 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
10271 GNUNET_free (lle);
10272 }
10273 /* setup data structure for learning */
10274 lle = GNUNET_new (struct LearnLaunchEntry);
10275 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
10276 &lle->challenge,
10277 sizeof(lle->challenge));
10278 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10279 "Starting launch DV learn with challenge %s\n",
10280 GNUNET_sh2s (&lle->challenge.value));
10281 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
10282 GNUNET_break (GNUNET_YES ==
10283 GNUNET_CONTAINER_multishortmap_put (
10284 dvlearn_map,
10285 &lle->challenge.value,
10286 lle,
10287 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
10288 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
10289 dvl.header.size = htons (sizeof(dvl));
10290 dvl.num_hops = htons (0);
10291 dvl.bidirectional = htons (0);
10292 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
10293 dvl.monotonic_time =
10294 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
10295 {
10296 struct DvInitPS dvip = {
10297 .purpose.purpose = htonl (
10298 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
10299 .purpose.size = htonl (sizeof(dvip)),
10300 .monotonic_time = dvl.monotonic_time,
10301 .challenge = lle->challenge
10302 };
10303
10304 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
10305 &dvip,
10306 &dvl.init_sig);
10307 }
10308 dvl.initiator = GST_my_identity;
10309 dvl.challenge = lle->challenge;
10310
10311 qqc.quality_count = 0;
10312 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
10313 qqc.num_queues = 0;
10314 qqc.q = NULL;
10315 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10316 &check_connection_quality,
10317 &qqc);
10318 GNUNET_assert (NULL != qqc.q);
10319
10320 /* Do this as close to transmission time as possible! */
10321 lle->launch_time = GNUNET_TIME_absolute_get ();
10322
10323 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
10324 /* reschedule this job, randomizing the time it runs (but no
10325 actual backoff!) */
10326 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
10327 DV_LEARN_BASE_FREQUENCY),
10328 &start_dv_learn,
10329 NULL);
10330}
10331
10332
10333/**
10334 * A new queue has been created, check if any address validation
10335 * requests have been waiting for it.
10336 *
10337 * @param cls a `struct Queue`
10338 * @param pid peer concerned (unused)
10339 * @param value a `struct ValidationState`
10340 * @return #GNUNET_NO if a match was found and we can stop looking
10341 */
10342static int
10343check_validation_request_pending (void *cls,
10344 const struct GNUNET_PeerIdentity *pid,
10345 void *value)
10346{
10347 struct Queue *q = cls;
10348 struct ValidationState *vs = value;
10349
10350 (void) pid;
10351 if ((GNUNET_YES == vs->awaiting_queue) &&
10352 (0 == strcmp (vs->address, q->address)))
10353 {
10354 vs->awaiting_queue = GNUNET_NO;
10355 validation_transmit_on_queue (q, vs);
10356 return GNUNET_NO;
10357 }
10358 return GNUNET_OK;
10359}
10360
10361
10362/**
10363 * Function called with the monotonic time of a DV initiator
10364 * by PEERSTORE. Updates the time.
10365 *
10366 * @param cls a `struct Neighbour`
10367 * @param record the information found, NULL for the last call
10368 * @param emsg error message
10369 */
10370static void
10371neighbour_dv_monotime_cb (void *cls,
10372 const struct GNUNET_PEERSTORE_Record *record,
10373 const char *emsg)
10374{
10375 struct Neighbour *n = cls;
10376 struct GNUNET_TIME_AbsoluteNBO *mtbe;
10377
10378 (void) emsg;
10379 if (NULL == record)
10380 {
10381 /* we're done with #neighbour_dv_monotime_cb() invocations,
10382 continue normal processing */
10383 n->get = NULL;
10384 n->dv_monotime_available = GNUNET_YES;
10385 return;
10386 }
10387 if (sizeof(*mtbe) != record->value_size)
10388 {
10389 GNUNET_break (0);
10390 return;
10391 }
10392 mtbe = record->value;
10393 n->last_dv_learn_monotime =
10394 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
10395 GNUNET_TIME_absolute_ntoh (*mtbe));
10396}
10397
10398
10399/**
10400 * New queue became available. Process the request.
10401 *
10402 * @param cls the client
10403 * @param aqm the send message that was sent
10404 */
10405static void
10406handle_add_queue_message (void *cls,
10407 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
10408{
10409 struct TransportClient *tc = cls;
10410 struct Queue *queue;
10411 struct Neighbour *neighbour;
10412 const char *addr;
10413 uint16_t addr_len;
10414
10415 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
10416 {
10417 /* MTU so small as to be useless for transmissions,
10418 required for #fragment_message()! */
10419 GNUNET_break_op (0);
10420 GNUNET_SERVICE_client_drop (tc->client);
10421 return;
10422 }
10423 /* This may simply be a queue update */
10424 for (queue = tc->details.communicator.queue_head;
10425 NULL != queue;
10426 queue = queue->next_client)
10427 {
10428 if (queue->qid != aqm->qid)
10429 continue;
10430 break;
10431 }
10432
10433 if (NULL != queue)
10434 {
10435 neighbour = queue->neighbour;
10436 }
10437 else
10438 {
10439 neighbour = lookup_neighbour (&aqm->receiver);
10440 if (NULL == neighbour)
10441 {
10442 neighbour = GNUNET_new (struct Neighbour);
10443 neighbour->pid = aqm->receiver;
10444 GNUNET_assert (GNUNET_OK ==
10445 GNUNET_CONTAINER_multipeermap_put (
10446 neighbours,
10447 &neighbour->pid,
10448 neighbour,
10449 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
10450 neighbour->get =
10451 GNUNET_PEERSTORE_iterate (peerstore,
10452 "transport",
10453 &neighbour->pid,
10454 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
10455 &neighbour_dv_monotime_cb,
10456 neighbour);
10457 }
10458 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
10459 addr = (const char *) &aqm[1];
10460 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10461 "New queue %s to %s available with QID %llu and q_len %lu and mtu %u\n",
10462 addr,
10463 GNUNET_i2s (&aqm->receiver),
10464 (unsigned long long) aqm->qid,
10465 GNUNET_ntohll (aqm->q_len),
10466 ntohl (aqm->mtu));
10467 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
10468 queue->tc = tc;
10469 queue->address = (const char *) &queue[1];
10470 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
10471 queue->qid = aqm->qid;
10472 queue->neighbour = neighbour;
10473 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (aqm->q_len))
10474 queue->unlimited_length = GNUNET_YES;
10475 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
10476 memcpy (&queue[1], addr, addr_len);
10477 /* notify monitors about new queue */
10478 {
10479 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
10480
10481 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
10482 }
10483 GNUNET_CONTAINER_MDLL_insert (neighbour,
10484 neighbour->queue_head,
10485 neighbour->queue_tail,
10486 queue);
10487 GNUNET_CONTAINER_MDLL_insert (client,
10488 tc->details.communicator.queue_head,
10489 tc->details.communicator.queue_tail,
10490 queue);
10491
10492 }
10493 queue->mtu = ntohl (aqm->mtu);
10494 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
10495 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
10496 queue->idle = GNUNET_YES;
10497 /* check if valdiations are waiting for the queue */
10498 (void)
10499 GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
10500 &aqm->receiver,
10501 &check_validation_request_pending,
10502 queue);
10503 /* look for traffic for this queue */
10504 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10505 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10506 /* might be our first queue, try launching DV learning */
10507 if (NULL == dvlearn_task)
10508 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
10509 GNUNET_SERVICE_client_continue (tc->client);
10510}
10511
10512
10513/**
10514 * @brief Handle updates to queues.
10515 *
10516 * @param cls the transport client.
10517 * @param msg Message struct.
10518 */
10519static void
10520handle_update_queue_message (void *cls,
10521 const struct
10522 GNUNET_TRANSPORT_UpdateQueueMessage *msg)
10523{
10524 struct TransportClient *tc = cls;
10525 struct Queue *target_queue = NULL;
10526
10527 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10528 "Received queue update message for %u with q_len %llu and mtu %u\n",
10529 msg->qid,
10530 (unsigned long long) GNUNET_ntohll (msg->q_len),
10531 ntohl (msg->mtu));
10532 for (target_queue = tc->details.communicator.queue_head;
10533 NULL != target_queue;
10534 target_queue = target_queue->next_client)
10535 {
10536 if (msg->qid == target_queue->qid)
10537 break;
10538 }
10539 if (NULL == target_queue)
10540 {
10541 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
10542 "Queue to update no longer exists! Discarding update.\n");
10543 return;
10544 }
10545
10546 target_queue->nt = msg->nt;
10547 target_queue->mtu = ntohl (msg->mtu);
10548 target_queue->cs = msg->cs;
10549 target_queue->priority = ntohl (msg->priority);
10550 /* The update message indicates how many messages
10551 * the queue should be able to handle.
10552 */
10553 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (msg->q_len))
10554 target_queue->unlimited_length = GNUNET_YES;
10555 else
10556 target_queue->unlimited_length = GNUNET_NO;
10557 target_queue->q_capacity = GNUNET_ntohll (msg->q_len);
10558 if (0 < target_queue->q_capacity)
10559 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10560 target_queue,
10561 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10562 GNUNET_SERVICE_client_continue (tc->client);
10563}
10564
10565
10566/**
10567 * Communicator tells us that our request to create a queue "worked", that
10568 * is setting up the queue is now in process.
10569 *
10570 * @param cls the `struct TransportClient`
10571 * @param cqr confirmation message
10572 */
10573static void
10574handle_queue_create_ok (void *cls,
10575 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
10576{
10577 struct TransportClient *tc = cls;
10578
10579 if (CT_COMMUNICATOR != tc->type)
10580 {
10581 GNUNET_break (0);
10582 GNUNET_SERVICE_client_drop (tc->client);
10583 return;
10584 }
10585 GNUNET_STATISTICS_update (GST_stats,
10586 "# Suggestions succeeded at communicator",
10587 1,
10588 GNUNET_NO);
10589 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10590 "Request #%u for communicator to create queue succeeded\n",
10591 (unsigned int) ntohs (cqr->request_id));
10592 GNUNET_SERVICE_client_continue (tc->client);
10593}
10594
10595
10596/**
10597 * Communicator tells us that our request to create a queue failed. This
10598 * usually indicates that the provided address is simply invalid or that the
10599 * communicator's resources are exhausted.
10600 *
10601 * @param cls the `struct TransportClient`
10602 * @param cqr failure message
10603 */
10604static void
10605handle_queue_create_fail (
10606 void *cls,
10607 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
10608{
10609 struct TransportClient *tc = cls;
10610
10611 if (CT_COMMUNICATOR != tc->type)
10612 {
10613 GNUNET_break (0);
10614 GNUNET_SERVICE_client_drop (tc->client);
10615 return;
10616 }
10617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10618 "Request #%u for communicator to create queue failed\n",
10619 (unsigned int) ntohs (cqr->request_id));
10620 GNUNET_STATISTICS_update (GST_stats,
10621 "# Suggestions failed in queue creation at communicator",
10622 1,
10623 GNUNET_NO);
10624 GNUNET_SERVICE_client_continue (tc->client);
10625}
10626
10627
10628/**
10629 * We have received a `struct ExpressPreferenceMessage` from an application
10630 * client.
10631 *
10632 * @param cls handle to the client
10633 * @param msg the start message
10634 */
10635static void
10636handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
10637{
10638 struct TransportClient *tc = cls;
10639 struct PeerRequest *pr;
10640
10641 if (CT_APPLICATION != tc->type)
10642 {
10643 GNUNET_break (0);
10644 GNUNET_SERVICE_client_drop (tc->client);
10645 return;
10646 }
10647 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
10648 &msg->peer);
10649 if (NULL == pr)
10650 {
10651 GNUNET_break (0);
10652 GNUNET_SERVICE_client_drop (tc->client);
10653 return;
10654 }
10655 (void) stop_peer_request (tc, &pr->pid, pr);
10656 GNUNET_SERVICE_client_continue (tc->client);
10657}
10658
10659
10660/**
10661 * Function called by PEERSTORE for each matching record.
10662 *
10663 * @param cls closure, a `struct PeerRequest`
10664 * @param record peerstore record information
10665 * @param emsg error message, or NULL if no errors
10666 */
10667static void
10668handle_hello_for_client (void *cls,
10669 const struct GNUNET_PEERSTORE_Record *record,
10670 const char *emsg)
10671{
10672 struct PeerRequest *pr = cls;
10673 const char *val;
10674
10675 if (NULL != emsg)
10676 {
10677 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
10678 "Got failure from PEERSTORE: %s\n",
10679 emsg);
10680 return;
10681 }
10682 val = record->value;
10683 if ((0 == record->value_size) || ('\0' != val[record->value_size - 1]))
10684 {
10685 GNUNET_break (0);
10686 return;
10687 }
10688 start_address_validation (&pr->pid, (const char *) record->value);
10689}
10690
10691
10692/**
10693 * We have received a `struct ExpressPreferenceMessage` from an application
10694 * client.
10695 *
10696 * @param cls handle to the client
10697 * @param msg the start message
10698 */
10699static void
10700handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
10701{
10702 struct TransportClient *tc = cls;
10703 struct PeerRequest *pr;
10704
10705 if (CT_NONE == tc->type)
10706 {
10707 tc->type = CT_APPLICATION;
10708 tc->details.application.requests =
10709 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
10710 }
10711 if (CT_APPLICATION != tc->type)
10712 {
10713 GNUNET_break (0);
10714 GNUNET_SERVICE_client_drop (tc->client);
10715 return;
10716 }
10717 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10718 "Client suggested we talk to %s with preference %d at rate %u\n",
10719 GNUNET_i2s (&msg->peer),
10720 (int) ntohl (msg->pk),
10721 (int) ntohl (msg->bw.value__));
10722 pr = GNUNET_new (struct PeerRequest);
10723 pr->tc = tc;
10724 pr->pid = msg->peer;
10725 pr->bw = msg->bw;
10726 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
10727 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
10728 tc->details.application.requests,
10729 &pr->pid,
10730 pr,
10731 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
10732 {
10733 GNUNET_break (0);
10734 GNUNET_free (pr);
10735 GNUNET_SERVICE_client_drop (tc->client);
10736 return;
10737 }
10738 pr->wc = GNUNET_PEERSTORE_watch (peerstore,
10739 "transport",
10740 &pr->pid,
10741 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
10742 &handle_hello_for_client,
10743 pr);
10744 GNUNET_SERVICE_client_continue (tc->client);
10745}
10746
10747
10748/**
10749 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
10750 * messages.
10751 *
10752 * @param cls a `struct TransportClient *`
10753 * @param m message to verify
10754 * @return #GNUNET_OK on success
10755 */
10756static int
10757check_request_hello_validation (void *cls,
10758 const struct RequestHelloValidationMessage *m)
10759{
10760 (void) cls;
10761 GNUNET_MQ_check_zero_termination (m);
10762 return GNUNET_OK;
10763}
10764
10765
10766/**
10767 * A client encountered an address of another peer. Consider validating it,
10768 * and if validation succeeds, persist it to PEERSTORE.
10769 *
10770 * @param cls a `struct TransportClient *`
10771 * @param m message to verify
10772 */
10773static void
10774handle_request_hello_validation (void *cls,
10775 const struct RequestHelloValidationMessage *m)
10776{
10777 struct TransportClient *tc = cls;
10778
10779 start_address_validation (&m->peer, (const char *) &m[1]);
10780 GNUNET_SERVICE_client_continue (tc->client);
10781}
10782
10783
10784/**
10785 * Free neighbour entry.
10786 *
10787 * @param cls NULL
10788 * @param pid unused
10789 * @param value a `struct Neighbour`
10790 * @return #GNUNET_OK (always)
10791 */
10792static int
10793free_neighbour_cb (void *cls,
10794 const struct GNUNET_PeerIdentity *pid,
10795 void *value)
10796{
10797 struct Neighbour *neighbour = value;
10798
10799 (void) cls;
10800 (void) pid;
10801 GNUNET_break (0); // should this ever happen?
10802 free_neighbour (neighbour);
10803
10804 return GNUNET_OK;
10805}
10806
10807
10808/**
10809 * Free DV route entry.
10810 *
10811 * @param cls NULL
10812 * @param pid unused
10813 * @param value a `struct DistanceVector`
10814 * @return #GNUNET_OK (always)
10815 */
10816static int
10817free_dv_routes_cb (void *cls,
10818 const struct GNUNET_PeerIdentity *pid,
10819 void *value)
10820{
10821 struct DistanceVector *dv = value;
10822
10823 (void) cls;
10824 (void) pid;
10825 free_dv_route (dv);
10826
10827 return GNUNET_OK;
10828}
10829
10830
10831/**
10832 * Free validation state.
10833 *
10834 * @param cls NULL
10835 * @param pid unused
10836 * @param value a `struct ValidationState`
10837 * @return #GNUNET_OK (always)
10838 */
10839static int
10840free_validation_state_cb (void *cls,
10841 const struct GNUNET_PeerIdentity *pid,
10842 void *value)
10843{
10844 struct ValidationState *vs = value;
10845
10846 (void) cls;
10847 (void) pid;
10848 free_validation_state (vs);
10849 return GNUNET_OK;
10850}
10851
10852
10853/**
10854 * Free pending acknowledgement.
10855 *
10856 * @param cls NULL
10857 * @param key unused
10858 * @param value a `struct PendingAcknowledgement`
10859 * @return #GNUNET_OK (always)
10860 */
10861static int
10862free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
10863{
10864 struct PendingAcknowledgement *pa = value;
10865
10866 (void) cls;
10867 (void) key;
10868 free_pending_acknowledgement (pa);
10869 return GNUNET_OK;
10870}
10871
10872
10873/**
10874 * Free acknowledgement cummulator.
10875 *
10876 * @param cls NULL
10877 * @param pid unused
10878 * @param value a `struct AcknowledgementCummulator`
10879 * @return #GNUNET_OK (always)
10880 */
10881static int
10882free_ack_cummulator_cb (void *cls,
10883 const struct GNUNET_PeerIdentity *pid,
10884 void *value)
10885{
10886 struct AcknowledgementCummulator *ac = value;
10887
10888 (void) cls;
10889 (void) pid;
10890 GNUNET_SCHEDULER_cancel (ac->task);
10891 GNUNET_free (ac);
10892 return GNUNET_OK;
10893}
10894
10895
10896/**
10897 * Function called when the service shuts down. Unloads our plugins
10898 * and cancels pending validations.
10899 *
10900 * @param cls closure, unused
10901 */
10902static void
10903do_shutdown (void *cls)
10904{
10905 struct LearnLaunchEntry *lle;
10906
10907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10908 "shutdown logic\n");
10909 (void) cls;
10910 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
10911 &free_neighbour_cb, NULL);
10912 if (NULL != validation_task)
10913 {
10914 GNUNET_SCHEDULER_cancel (validation_task);
10915 validation_task = NULL;
10916 }
10917 if (NULL != dvlearn_task)
10918 {
10919 GNUNET_SCHEDULER_cancel (dvlearn_task);
10920 dvlearn_task = NULL;
10921 }
10922 if (NULL != GST_stats)
10923 {
10924 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
10925 GST_stats = NULL;
10926 }
10927 if (NULL != GST_my_private_key)
10928 {
10929 GNUNET_free (GST_my_private_key);
10930 GST_my_private_key = NULL;
10931 }
10932 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
10933 &free_ack_cummulator_cb,
10934 NULL);
10935 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
10936 ack_cummulators = NULL;
10937 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
10938 &free_pending_ack_cb,
10939 NULL);
10940 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
10941 pending_acks = NULL;
10942 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
10943 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
10944 neighbours = NULL;
10945 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
10946 GNUNET_CONTAINER_multipeermap_destroy (links);
10947 links = NULL;
10948 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
10949 &free_backtalker_cb,
10950 NULL);
10951 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
10952 backtalkers = NULL;
10953 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
10954 &free_validation_state_cb,
10955 NULL);
10956 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
10957 validation_map = NULL;
10958 while (NULL != ir_head)
10959 free_incoming_request (ir_head);
10960 GNUNET_assert (0 == ir_total);
10961 while (NULL != (lle = lle_head))
10962 {
10963 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
10964 GNUNET_free (lle);
10965 }
10966 if (NULL != peerstore)
10967 {
10968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10969 "Disconnecting from PEERSTORE service\n");
10970 GNUNET_PEERSTORE_disconnect (peerstore, GNUNET_NO);
10971 peerstore = NULL;
10972 }
10973 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
10974 dvlearn_map = NULL;
10975 GNUNET_CONTAINER_heap_destroy (validation_heap);
10976 validation_heap = NULL;
10977 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
10978 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
10979 dv_routes = NULL;
10980 GNUNET_SCHEDULER_shutdown ();
10981}
10982
10983
10984static void
10985shutdown_task (void *cls)
10986{
10987 in_shutdown = GNUNET_YES;
10988
10989 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10990 "Shutdown task executed\n");
10991 if (NULL != clients_head)
10992 {
10993 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
10994 {
10995 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
10996 "client still connected: %u\n",
10997 tc->type);
10998 }
10999 }
11000 else
11001 do_shutdown (cls);
11002
11003}
11004
11005
11006/**
11007 * Initiate transport service.
11008 *
11009 * @param cls closure
11010 * @param c configuration to use
11011 * @param service the initialized service
11012 */
11013static void
11014run (void *cls,
11015 const struct GNUNET_CONFIGURATION_Handle *c,
11016 struct GNUNET_SERVICE_Handle *service)
11017{
11018 (void) cls;
11019 (void) service;
11020 /* setup globals */
11021 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
11022 in_shutdown = GNUNET_NO;
11023 GST_cfg = c;
11024 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
11025 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
11026 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
11027 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11028 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
11029 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11030 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
11031 GNUNET_YES);
11032 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
11033 validation_heap =
11034 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
11035 GST_my_private_key =
11036 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
11037 if (NULL == GST_my_private_key)
11038 {
11039 GNUNET_log (
11040 GNUNET_ERROR_TYPE_ERROR,
11041 _ (
11042 "Transport service is lacking key configuration settings. Exiting.\n"));
11043 GNUNET_SCHEDULER_shutdown ();
11044 return;
11045 }
11046 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
11047 &GST_my_identity.public_key);
11048 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
11049 "My identity is `%s'\n",
11050 GNUNET_i2s_full (&GST_my_identity));
11051 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
11052 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
11053 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
11054 if (NULL == peerstore)
11055 {
11056 GNUNET_break (0);
11057 GNUNET_SCHEDULER_shutdown ();
11058 return;
11059 }
11060}
11061
11062
11063/**
11064 * Define "main" method using service macro.
11065 */
11066GNUNET_SERVICE_MAIN (
11067 "transport",
11068 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
11069 &run,
11070 &client_connect_cb,
11071 &client_disconnect_cb,
11072 NULL,
11073 /* communication with applications */
11074 GNUNET_MQ_hd_fixed_size (suggest,
11075 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
11076 struct ExpressPreferenceMessage,
11077 NULL),
11078 GNUNET_MQ_hd_fixed_size (suggest_cancel,
11079 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
11080 struct ExpressPreferenceMessage,
11081 NULL),
11082 GNUNET_MQ_hd_var_size (request_hello_validation,
11083 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
11084 struct RequestHelloValidationMessage,
11085 NULL),
11086 /* communication with core */
11087 GNUNET_MQ_hd_fixed_size (client_start,
11088 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
11089 struct StartMessage,
11090 NULL),
11091 GNUNET_MQ_hd_var_size (client_send,
11092 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
11093 struct OutboundMessage,
11094 NULL),
11095 GNUNET_MQ_hd_fixed_size (client_recv_ok,
11096 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
11097 struct RecvOkMessage,
11098 NULL),
11099 /* communication with communicators */
11100 GNUNET_MQ_hd_var_size (communicator_available,
11101 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
11102 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
11103 NULL),
11104 GNUNET_MQ_hd_var_size (communicator_backchannel,
11105 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
11106 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
11107 NULL),
11108 GNUNET_MQ_hd_var_size (add_address,
11109 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
11110 struct GNUNET_TRANSPORT_AddAddressMessage,
11111 NULL),
11112 GNUNET_MQ_hd_fixed_size (del_address,
11113 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
11114 struct GNUNET_TRANSPORT_DelAddressMessage,
11115 NULL),
11116 GNUNET_MQ_hd_var_size (incoming_msg,
11117 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
11118 struct GNUNET_TRANSPORT_IncomingMessage,
11119 NULL),
11120 GNUNET_MQ_hd_fixed_size (queue_create_ok,
11121 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
11122 struct GNUNET_TRANSPORT_CreateQueueResponse,
11123 NULL),
11124 GNUNET_MQ_hd_fixed_size (queue_create_fail,
11125 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
11126 struct GNUNET_TRANSPORT_CreateQueueResponse,
11127 NULL),
11128 GNUNET_MQ_hd_var_size (add_queue_message,
11129 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
11130 struct GNUNET_TRANSPORT_AddQueueMessage,
11131 NULL),
11132 GNUNET_MQ_hd_fixed_size (update_queue_message,
11133 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE,
11134 struct GNUNET_TRANSPORT_UpdateQueueMessage,
11135 NULL),
11136 GNUNET_MQ_hd_fixed_size (del_queue_message,
11137 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
11138 struct GNUNET_TRANSPORT_DelQueueMessage,
11139 NULL),
11140 GNUNET_MQ_hd_fixed_size (send_message_ack,
11141 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
11142 struct GNUNET_TRANSPORT_SendMessageToAck,
11143 NULL),
11144 /* communication with monitors */
11145 GNUNET_MQ_hd_fixed_size (monitor_start,
11146 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
11147 struct GNUNET_TRANSPORT_MonitorStart,
11148 NULL),
11149 GNUNET_MQ_handler_end ());
11150
11151
11152/* 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 fad2ca4a1..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_URI:
1632 /* Future HELLO message, discard */
1633 return ret;
1634
1635 case GNUNET_MESSAGE_TYPE_HELLO:
1636 if (GNUNET_OK != GST_validation_handle_hello (message))
1637 {
1638 GNUNET_break_op (0);
1639 GST_blacklist_abort_matching (address, session);
1640 }
1641 return ret;
1642
1643 case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
1644 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1645 "Processing PING from `%s'\n",
1646 GST_plugins_a2s (address));
1647 if (GNUNET_OK !=
1648 GST_validation_handle_ping (&address->peer, message, address, session))
1649 {
1650 GST_blacklist_abort_matching (address, session);
1651 kill_session (plugin_name, session);
1652 }
1653 break;
1654
1655 case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
1656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1657 "Processing PONG from `%s'\n",
1658 GST_plugins_a2s (address));
1659 if (GNUNET_OK != GST_validation_handle_pong (&address->peer, message))
1660 {
1661 GNUNET_break_op (0);
1662 GST_blacklist_abort_matching (address, session);
1663 kill_session (plugin_name, session);
1664 }
1665 break;
1666
1667 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN:
1668 /* Do blacklist check if communication with this peer is allowed */
1669 (void) GST_blacklist_test_allowed (&address->peer,
1670 NULL,
1671 &connect_bl_check_cont,
1672 GNUNET_copy_message (message),
1673 address,
1674 session);
1675 break;
1676
1677 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_SYN_ACK:
1678 if (GNUNET_OK !=
1679 GST_neighbours_handle_session_syn_ack (message, address, session))
1680 {
1681 GST_blacklist_abort_matching (address, session);
1682 kill_session (plugin_name, session);
1683 }
1684 break;
1685
1686 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK:
1687 if (GNUNET_OK !=
1688 GST_neighbours_handle_session_ack (message, address, session))
1689 {
1690 GNUNET_break_op (0);
1691 GST_blacklist_abort_matching (address, session);
1692 kill_session (plugin_name, session);
1693 }
1694 break;
1695
1696 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT:
1697 GST_neighbours_handle_disconnect_message (&address->peer, message);
1698 break;
1699
1700 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_QUOTA:
1701 GST_neighbours_handle_quota_message (&address->peer, message);
1702 break;
1703
1704 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE:
1705 GST_neighbours_keepalive (&address->peer, message);
1706 break;
1707
1708 case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE:
1709 GST_neighbours_keepalive_response (&address->peer, message);
1710 break;
1711
1712 default:
1713 /* should be payload */
1714 GNUNET_STATISTICS_update (GST_stats,
1715 gettext_noop ("# bytes payload received"),
1716 ntohs (message->size),
1717 GNUNET_NO);
1718 ret = process_payload (address, session, message);
1719 break;
1720 }
1721end:
1722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1723 "Allowing receive from peer %s to continue in %s\n",
1724 GNUNET_i2s (&address->peer),
1725 GNUNET_STRINGS_relative_time_to_string (ret, GNUNET_YES));
1726 return ret;
1727}
1728
1729
1730/**
1731 * Function that will be called for each address the transport
1732 * is aware that it might be reachable under. Update our HELLO.
1733 *
1734 * @param cls name of the plugin (const char*)
1735 * @param add_remove should the address added (YES) or removed (NO) from the
1736 * set of valid addresses?
1737 * @param address the address to add or remove
1738 */
1739static void
1740plugin_env_address_change_notification (
1741 void *cls,
1742 int add_remove,
1743 const struct GNUNET_HELLO_Address *address)
1744{
1745 static int addresses = 0;
1746
1747 if (GNUNET_YES == add_remove)
1748 {
1749 addresses++;
1750 GNUNET_STATISTICS_update (GST_stats, "# transport addresses", 1, GNUNET_NO);
1751 }
1752 else if (GNUNET_NO == add_remove)
1753 {
1754 if (0 == addresses)
1755 {
1756 GNUNET_break (0);
1757 }
1758 else
1759 {
1760 addresses--;
1761 GNUNET_STATISTICS_update (GST_stats,
1762 "# transport addresses",
1763 -1,
1764 GNUNET_NO);
1765 }
1766 }
1767 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1768 "Transport now has %u addresses to communicate\n",
1769 addresses);
1770 GST_hello_modify_addresses (add_remove, address);
1771}
1772
1773
1774/**
1775 * Function that will be called whenever the plugin internally
1776 * cleans up a session pointer and hence the service needs to
1777 * discard all of those sessions as well. Plugins that do not
1778 * use sessions can simply omit calling this function and always
1779 * use NULL wherever a session pointer is needed. This function
1780 * should be called BEFORE a potential "TransmitContinuation"
1781 * from the "TransmitFunction".
1782 *
1783 * @param cls closure
1784 * @param address which address was the session for
1785 * @param session which session is being destroyed
1786 */
1787static void
1788plugin_env_session_end (void *cls,
1789 const struct GNUNET_HELLO_Address *address,
1790 struct GNUNET_ATS_Session *session)
1791{
1792 struct GNUNET_ATS_SessionKiller *sk;
1793
1794 if (NULL == address)
1795 {
1796 GNUNET_break (0);
1797 return;
1798 }
1799 if (NULL == session)
1800 {
1801 GNUNET_break (0);
1802 return;
1803 }
1804 GNUNET_assert (strlen (address->transport_name) > 0);
1805
1806 GNUNET_log (
1807 GNUNET_ERROR_TYPE_DEBUG,
1808 "Notification from plugin about terminated session %p from peer `%s' address `%s'\n",
1809 session,
1810 GNUNET_i2s (&address->peer),
1811 GST_plugins_a2s (address));
1812
1813 GST_neighbours_session_terminated (&address->peer, session);
1814 GST_ats_del_session (address, session);
1815 GST_blacklist_abort_matching (address, session);
1816
1817 for (sk = sk_head; NULL != sk; sk = sk->next)
1818 {
1819 if (sk->session == session)
1820 {
1821 GNUNET_CONTAINER_DLL_remove (sk_head, sk_tail, sk);
1822 GNUNET_SCHEDULER_cancel (sk->task);
1823 GNUNET_free (sk);
1824 break;
1825 }
1826 }
1827}
1828
1829
1830/**
1831 * Black list check result from blacklist check triggered when a
1832 * plugin gave us a new session in #plugin_env_session_start(). If
1833 * connection to the peer is disallowed, kill the session.
1834 *
1835 * @param cls NULL
1836 * @param peer the peer
1837 * @param address address associated with the request
1838 * @param session session associated with the request
1839 * @param result the result
1840 */
1841static void
1842plugin_env_session_start_bl_check_cont (
1843 void *cls,
1844 const struct GNUNET_PeerIdentity *peer,
1845 const struct GNUNET_HELLO_Address *address,
1846 struct GNUNET_ATS_Session *session,
1847 int result)
1848{
1849 if (GNUNET_OK != result)
1850 {
1851 kill_session (address->transport_name, session);
1852 return;
1853 }
1854 if (GNUNET_YES !=
1855 GNUNET_HELLO_address_check_option (address,
1856 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1857 {
1858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1859 "Informing verifier about inbound session's address `%s'\n",
1860 GST_plugins_a2s (address));
1861 GST_validation_handle_address (address);
1862 }
1863}
1864
1865
1866/**
1867 * Plugin tells transport service about a new inbound session
1868 *
1869 * @param cls unused
1870 * @param address the address
1871 * @param session the new session
1872 * @param scope network scope information
1873 */
1874static void
1875plugin_env_session_start (void *cls,
1876 const struct GNUNET_HELLO_Address *address,
1877 struct GNUNET_ATS_Session *session,
1878 enum GNUNET_NetworkType scope)
1879{
1880 struct GNUNET_ATS_Properties prop;
1881
1882 if (NULL == address)
1883 {
1884 GNUNET_break (0);
1885 return;
1886 }
1887 if (NULL == session)
1888 {
1889 GNUNET_break (0);
1890 return;
1891 }
1892 GNUNET_log (
1893 GNUNET_ERROR_TYPE_INFO,
1894 "Notification from plugin `%s' about new session from peer `%s' address `%s'\n",
1895 address->transport_name,
1896 GNUNET_i2s (&address->peer),
1897 GST_plugins_a2s (address));
1898 if (GNUNET_YES ==
1899 GNUNET_HELLO_address_check_option (address,
1900 GNUNET_HELLO_ADDRESS_INFO_INBOUND))
1901 {
1902 /* inbound is always new, but outbound MAY already be known, but
1903 for example for UNIX, we have symmetric connections and thus we
1904 may not know the address yet; add if necessary! */
1905 /* FIXME: maybe change API here so we just pass scope? */
1906 memset (&prop, 0, sizeof(prop));
1907 GNUNET_break (GNUNET_NT_UNSPECIFIED != scope);
1908 prop.scope = scope;
1909 GST_ats_add_inbound_address (address, session, &prop);
1910 }
1911 /* Do blacklist check if communication with this peer is allowed */
1912 (void) GST_blacklist_test_allowed (&address->peer,
1913 address->transport_name,
1914 &plugin_env_session_start_bl_check_cont,
1915 NULL,
1916 address,
1917 session);
1918}
1919
1920
1921/**
1922 * Function called by ATS to notify the callee that the
1923 * assigned bandwidth or address for a given peer was changed. If the
1924 * callback is called with address/bandwidth assignments of zero, the
1925 * ATS disconnect function will still be called once the disconnect
1926 * actually happened.
1927 *
1928 * @param cls closure
1929 * @param peer the peer this address is intended for
1930 * @param address address to use (for peer given in address)
1931 * @param session session to use (if available)
1932 * @param bandwidth_out assigned outbound bandwidth for the connection in NBO,
1933 * 0 to disconnect from peer
1934 * @param bandwidth_in assigned inbound bandwidth for the connection in NBO,
1935 * 0 to disconnect from peer
1936 * @param ats ATS information
1937 * @param ats_count number of @a ats elements
1938 */
1939static void
1940ats_request_address_change (void *cls,
1941 const struct GNUNET_PeerIdentity *peer,
1942 const struct GNUNET_HELLO_Address *address,
1943 struct GNUNET_ATS_Session *session,
1944 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
1945 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in)
1946{
1947 uint32_t bw_in = ntohl (bandwidth_in.value__);
1948 uint32_t bw_out = ntohl (bandwidth_out.value__);
1949
1950 if (NULL == peer)
1951 {
1952 /* ATS service died, all suggestions become invalid!
1953 (but we'll keep using the allocations for a little
1954 while, to keep going while ATS restarts) */
1955 /* FIXME: We should drop all
1956 connections now, as ATS won't explicitly tell
1957 us and be unaware of ongoing resource allocations! */
1958 return;
1959 }
1960 /* ATS tells me to disconnect from peer */
1961 if ((0 == bw_in) && (0 == bw_out))
1962 {
1963 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1964 "ATS tells me to disconnect from peer `%s'\n",
1965 GNUNET_i2s (peer));
1966 GST_neighbours_force_disconnect (peer);
1967 return;
1968 }
1969 GNUNET_assert (NULL != address);
1970 GNUNET_STATISTICS_update (GST_stats,
1971 "# ATS suggestions received",
1972 1,
1973 GNUNET_NO);
1974 GST_neighbours_switch_to_address (address,
1975 session,
1976 bandwidth_in,
1977 bandwidth_out);
1978}
1979
1980
1981/**
1982 * Closure for #test_connection_ok().
1983 */
1984struct TestConnectionContext
1985{
1986 /**
1987 * Is this the first neighbour we're checking?
1988 */
1989 int first;
1990
1991 /**
1992 * Handle to the blacklisting client we need to ask.
1993 */
1994 struct TransportClient *tc;
1995};
1996
1997
1998/**
1999 * Got the result about an existing connection from a new blacklister.
2000 * Shutdown the neighbour if necessary.
2001 *
2002 * @param cls unused
2003 * @param peer the neighbour that was investigated
2004 * @param address address associated with the request
2005 * @param session session associated with the request
2006 * @param allowed #GNUNET_OK if we can keep it,
2007 * #GNUNET_NO if we must shutdown the connection
2008 */
2009static void
2010confirm_or_drop_neighbour (void *cls,
2011 const struct GNUNET_PeerIdentity *peer,
2012 const struct GNUNET_HELLO_Address *address,
2013 struct GNUNET_ATS_Session *session,
2014 int allowed)
2015{
2016 if (GNUNET_OK == allowed)
2017 return; /* we're done */
2018 GNUNET_STATISTICS_update (GST_stats,
2019 gettext_noop ("# disconnects due to blacklist"),
2020 1,
2021 GNUNET_NO);
2022 GST_neighbours_force_disconnect (peer);
2023}
2024
2025
2026/**
2027 * Test if an existing connection is still acceptable given a new
2028 * blacklisting client.
2029 *
2030 * @param cls the `struct TestConnectionContext *`
2031 * @param peer identity of the peer
2032 * @param address the address
2033 * @param state current state this peer is in
2034 * @param state_timeout timeout for the current state of the peer
2035 * @param bandwidth_in bandwidth assigned inbound
2036 * @param bandwidth_out bandwidth assigned outbound
2037 */
2038static void
2039test_connection_ok (void *cls,
2040 const struct GNUNET_PeerIdentity *peer,
2041 const struct GNUNET_HELLO_Address *address,
2042 enum GNUNET_TRANSPORT_PeerState state,
2043 struct GNUNET_TIME_Absolute state_timeout,
2044 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
2045 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out)
2046{
2047 struct TestConnectionContext *tcc = cls;
2048 struct GST_BlacklistCheck *bc;
2049
2050 bc = GNUNET_new (struct GST_BlacklistCheck);
2051 GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
2052 bc->peer = *peer;
2053 bc->address = GNUNET_HELLO_address_copy (address);
2054 bc->cont = &confirm_or_drop_neighbour;
2055 bc->cont_cls = NULL;
2056 bc->bl_pos = tcc->tc;
2057 if (GNUNET_YES == tcc->first)
2058 {
2059 /* all would wait for the same client, no need to
2060 * create more than just the first task right now */
2061 bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
2062 tcc->first = GNUNET_NO;
2063 }
2064}
2065
2066
2067/**
2068 * Initialize a blacklisting client. We got a blacklist-init
2069 * message from this client, add it to the list of clients
2070 * to query for blacklisting.
2071 *
2072 * @param cls the client
2073 * @param message the blacklist-init message that was sent
2074 */
2075static void
2076handle_client_blacklist_init (void *cls,
2077 const struct GNUNET_MessageHeader *message)
2078{
2079 struct TransportClient *tc = cls;
2080 struct TestConnectionContext tcc;
2081
2082 if (CT_NONE != tc->type)
2083 {
2084 GNUNET_break (0);
2085 GNUNET_SERVICE_client_drop (tc->client);
2086 return;
2087 }
2088 GNUNET_SERVICE_client_mark_monitor (tc->client);
2089 tc->type = CT_BLACKLIST;
2090 tc->details.blacklist.call_receive_done = GNUNET_YES;
2091 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "New blacklist client %p\n", tc);
2092 /* confirm that all existing connections are OK! */
2093 tcc.tc = tc;
2094 tcc.first = GNUNET_YES;
2095 GST_neighbours_iterate (&test_connection_ok, &tcc);
2096}
2097
2098
2099/**
2100 * Free the given entry in the blacklist.
2101 *
2102 * @param cls unused
2103 * @param key host identity (unused)
2104 * @param value the blacklist entry
2105 * @return #GNUNET_OK (continue to iterate)
2106 */
2107static int
2108free_blacklist_entry (void *cls,
2109 const struct GNUNET_PeerIdentity *key,
2110 void *value)
2111{
2112 char *be = value;
2113
2114 GNUNET_free (be);
2115 return GNUNET_OK;
2116}
2117
2118
2119/**
2120 * Set traffic metric to manipulate
2121 *
2122 * @param cls closure
2123 * @param message containing information
2124 */
2125static void
2126handle_client_set_metric (void *cls, const struct TrafficMetricMessage *tm)
2127{
2128 struct TransportClient *tc = cls;
2129
2130 GST_manipulation_set_metric (tm);
2131 GNUNET_SERVICE_client_continue (tc->client);
2132}
2133
2134
2135/**
2136 * Function called when the service shuts down. Unloads our plugins
2137 * and cancels pending validations.
2138 *
2139 * @param cls closure, unused
2140 */
2141static void
2142shutdown_task (void *cls)
2143{
2144 struct AddressToStringContext *cur;
2145
2146 GST_neighbours_stop ();
2147 GST_plugins_unload ();
2148 GST_validation_stop ();
2149 GST_ats_done ();
2150 GNUNET_ATS_scheduling_done (GST_ats);
2151 GST_ats = NULL;
2152 GNUNET_ATS_connectivity_done (GST_ats_connect);
2153 GST_ats_connect = NULL;
2154 GNUNET_NT_scanner_done (GST_is);
2155 GST_is = NULL;
2156 while (NULL != (cur = a2s_head))
2157 {
2158 GNUNET_CONTAINER_DLL_remove (a2s_head, a2s_tail, cur);
2159 GNUNET_free (cur);
2160 }
2161 if (NULL != plugin_nc)
2162 {
2163 GNUNET_notification_context_destroy (plugin_nc);
2164 plugin_nc = NULL;
2165 }
2166 GNUNET_CONTAINER_multipeermap_destroy (active_stccs);
2167 active_stccs = NULL;
2168 if (NULL != blacklist)
2169 {
2170 GNUNET_CONTAINER_multipeermap_iterate (blacklist,
2171 &free_blacklist_entry,
2172 NULL);
2173 GNUNET_CONTAINER_multipeermap_destroy (blacklist);
2174 blacklist = NULL;
2175 }
2176 GST_hello_stop ();
2177 GST_manipulation_stop ();
2178
2179 if (NULL != GST_peerinfo)
2180 {
2181 GNUNET_PEERINFO_disconnect (GST_peerinfo);
2182 GST_peerinfo = NULL;
2183 }
2184 if (NULL != GST_stats)
2185 {
2186 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
2187 GST_stats = NULL;
2188 }
2189}
2190
2191
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 65b090187..000000000
--- a/src/transport/tcp_service_legacy.c
+++ /dev/null
@@ -1,1646 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2012 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file util/service.c
23 * @brief functions related to starting services
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_constants.h"
30#include "gnunet_resolver_service.h"
31
32#if HAVE_MALLINFO2
33#include <malloc.h>
34#include "gauger.h"
35#endif
36
37
38/* ******************* access control ******************** */
39
40/**
41 * Check if the given IP address is in the list of IP addresses.
42 *
43 * @param list a list of networks
44 * @param add the IP to check (in network byte order)
45 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
46 */
47static int
48check_ipv4_listed (const struct GNUNET_STRINGS_IPv4NetworkPolicy *list,
49 const struct in_addr *add)
50{
51 unsigned int i;
52
53 if (NULL == list)
54 return GNUNET_NO;
55 i = 0;
56 while ((list[i].network.s_addr != 0) || (list[i].netmask.s_addr != 0))
57 {
58 if ((add->s_addr & list[i].netmask.s_addr) ==
59 (list[i].network.s_addr & list[i].netmask.s_addr))
60 return GNUNET_YES;
61 i++;
62 }
63 return GNUNET_NO;
64}
65
66
67/**
68 * Check if the given IP address is in the list of IP addresses.
69 *
70 * @param list a list of networks
71 * @param ip the IP to check (in network byte order)
72 * @return #GNUNET_NO if the IP is not in the list, #GNUNET_YES if it it is
73 */
74static int
75check_ipv6_listed (const struct GNUNET_STRINGS_IPv6NetworkPolicy *list,
76 const struct in6_addr *ip)
77{
78 unsigned int i;
79 unsigned int j;
80 struct in6_addr zero;
81
82 if (NULL == list)
83 return GNUNET_NO;
84 memset (&zero, 0, sizeof(struct in6_addr));
85 i = 0;
86NEXT:
87 while (0 != memcmp (&zero, &list[i].network, sizeof(struct in6_addr)))
88 {
89 for (j = 0; j < sizeof(struct in6_addr) / sizeof(int); j++)
90 if (((((int *) ip)[j] & ((int *) &list[i].netmask)[j])) !=
91 (((int *) &list[i].network)[j] & ((int *) &list[i].netmask)[j]))
92 {
93 i++;
94 goto NEXT;
95 }
96 return GNUNET_YES;
97 }
98 return GNUNET_NO;
99}
100
101
102/* ****************** service struct ****************** */
103
104
105/**
106 * Context for "service_task".
107 */
108struct LEGACY_SERVICE_Context
109{
110 /**
111 * Our configuration.
112 */
113 const struct GNUNET_CONFIGURATION_Handle *cfg;
114
115 /**
116 * Handle for the server.
117 */
118 struct GNUNET_SERVER_Handle *server;
119
120 /**
121 * NULL-terminated array of addresses to bind to, NULL if we got pre-bound
122 * listen sockets.
123 */
124 struct sockaddr **addrs;
125
126 /**
127 * Name of our service.
128 */
129 const char *service_name;
130
131 /**
132 * Main service-specific task to run.
133 */
134 LEGACY_SERVICE_Main task;
135
136 /**
137 * Closure for @e task.
138 */
139 void *task_cls;
140
141 /**
142 * IPv4 addresses that are not allowed to connect.
143 */
144 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_denied;
145
146 /**
147 * IPv6 addresses that are not allowed to connect.
148 */
149 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_denied;
150
151 /**
152 * IPv4 addresses that are allowed to connect (if not
153 * set, all are allowed).
154 */
155 struct GNUNET_STRINGS_IPv4NetworkPolicy *v4_allowed;
156
157 /**
158 * IPv6 addresses that are allowed to connect (if not
159 * set, all are allowed).
160 */
161 struct GNUNET_STRINGS_IPv6NetworkPolicy *v6_allowed;
162
163 /**
164 * My (default) message handlers. Adjusted copy
165 * of "defhandlers".
166 */
167 struct GNUNET_SERVER_MessageHandler *my_handlers;
168
169 /**
170 * Array of the lengths of the entries in addrs.
171 */
172 socklen_t *addrlens;
173
174 /**
175 * NULL-terminated array of listen sockets we should take over.
176 */
177 struct GNUNET_NETWORK_Handle **lsocks;
178
179 /**
180 * Task ID of the shutdown task.
181 */
182 struct GNUNET_SCHEDULER_Task *shutdown_task;
183
184 /**
185 * Idle timeout for server.
186 */
187 struct GNUNET_TIME_Relative timeout;
188
189 /**
190 * Overall success/failure of the service start.
191 */
192 int ret;
193
194 /**
195 * If we are daemonizing, this FD is set to the
196 * pipe to the parent. Send '.' if we started
197 * ok, '!' if not. -1 if we are not daemonizing.
198 */
199 int ready_confirm_fd;
200
201 /**
202 * Do we close connections if we receive messages
203 * for which we have no handler?
204 */
205 int require_found;
206
207 /**
208 * Do we require a matching UID for UNIX domain socket connections?
209 * #GNUNET_NO means that the UID does not have to match (however,
210 * @e match_gid may still impose other access control checks).
211 */
212 int match_uid;
213
214 /**
215 * Do we require a matching GID for UNIX domain socket connections?
216 * Ignored if @e match_uid is #GNUNET_YES. Note that this is about
217 * checking that the client's UID is in our group OR that the
218 * client's GID is our GID. If both "match_gid" and @e match_uid are
219 * #GNUNET_NO, all users on the local system have access.
220 */
221 int match_gid;
222
223 /**
224 * Our options.
225 */
226 enum LEGACY_SERVICE_Options options;
227};
228
229
230/* ****************** message handlers ****************** */
231
232/**
233 * Send a 'TEST' message back to the client.
234 *
235 * @param cls the 'struct GNUNET_SERVER_Client' to send TEST to
236 * @param size number of bytes available in 'buf'
237 * @param buf where to copy the message
238 * @return number of bytes written to 'buf'
239 */
240static size_t
241write_test (void *cls, size_t size, void *buf)
242{
243 struct GNUNET_SERVER_Client *client = cls;
244 struct GNUNET_MessageHeader *msg;
245
246 if (size < sizeof(struct GNUNET_MessageHeader))
247 {
248 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
249 return 0; /* client disconnected */
250 }
251 msg = (struct GNUNET_MessageHeader *) buf;
252 msg->type = htons (GNUNET_MESSAGE_TYPE_TEST);
253 msg->size = htons (sizeof(struct GNUNET_MessageHeader));
254 GNUNET_SERVER_receive_done (client, GNUNET_OK);
255 return sizeof(struct GNUNET_MessageHeader);
256}
257
258
259/**
260 * Handler for TEST message.
261 *
262 * @param cls closure (refers to service)
263 * @param client identification of the client
264 * @param message the actual message
265 */
266static void
267handle_test (void *cls,
268 struct GNUNET_SERVER_Client *client,
269 const struct GNUNET_MessageHeader *message)
270{
271 /* simply bounce message back to acknowledge */
272 if (NULL ==
273 GNUNET_SERVER_notify_transmit_ready (client,
274 sizeof(struct GNUNET_MessageHeader),
275 GNUNET_TIME_UNIT_FOREVER_REL,
276 &write_test,
277 client))
278 GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
279}
280
281
282/**
283 * Default handlers for all services. Will be copied and the
284 * "callback_cls" fields will be replaced with the specific service
285 * struct.
286 */
287static const struct GNUNET_SERVER_MessageHandler defhandlers[] =
288{ { &handle_test,
289 NULL,
290 GNUNET_MESSAGE_TYPE_TEST,
291 sizeof(struct GNUNET_MessageHeader) },
292 { NULL, NULL, 0, 0 } };
293
294
295/* ****************** service core routines ************** */
296
297
298/**
299 * Check if access to the service is allowed from the given address.
300 *
301 * @param cls closure
302 * @param uc credentials, if available, otherwise NULL
303 * @param addr address
304 * @param addrlen length of address
305 * @return #GNUNET_YES to allow, #GNUNET_NO to deny, #GNUNET_SYSERR
306 * for unknown address family (will be denied).
307 */
308static int
309check_access (void *cls,
310 const struct GNUNET_CONNECTION_Credentials *uc,
311 const struct sockaddr *addr,
312 socklen_t addrlen)
313{
314 struct LEGACY_SERVICE_Context *sctx = cls;
315 const struct sockaddr_in *i4;
316 const struct sockaddr_in6 *i6;
317 int ret;
318
319 switch (addr->sa_family)
320 {
321 case AF_INET:
322 GNUNET_assert (addrlen == sizeof(struct sockaddr_in));
323 i4 = (const struct sockaddr_in *) addr;
324 ret = ((NULL == sctx->v4_allowed) ||
325 (check_ipv4_listed (sctx->v4_allowed, &i4->sin_addr))) &&
326 ((NULL == sctx->v4_denied) ||
327 (! check_ipv4_listed (sctx->v4_denied, &i4->sin_addr)));
328 break;
329
330 case AF_INET6:
331 GNUNET_assert (addrlen == sizeof(struct sockaddr_in6));
332 i6 = (const struct sockaddr_in6 *) addr;
333 ret = ((NULL == sctx->v6_allowed) ||
334 (check_ipv6_listed (sctx->v6_allowed, &i6->sin6_addr))) &&
335 ((NULL == sctx->v6_denied) ||
336 (! check_ipv6_listed (sctx->v6_denied, &i6->sin6_addr)));
337 break;
338
339 case AF_UNIX:
340 ret = GNUNET_OK; /* controlled using file-system ACL now */
341 break;
342
343 default:
344 LOG (GNUNET_ERROR_TYPE_WARNING,
345 _ ("Unknown address family %d\n"),
346 addr->sa_family);
347 return GNUNET_SYSERR;
348 }
349 if (GNUNET_OK != ret)
350 {
351 LOG (GNUNET_ERROR_TYPE_WARNING,
352 _ ("Access from `%s' denied to service `%s'\n"),
353 GNUNET_a2s (addr, addrlen),
354 sctx->service_name);
355 }
356 return ret;
357}
358
359
360/**
361 * Get the name of the file where we will
362 * write the PID of the service.
363 *
364 * @param sctx service context
365 * @return name of the file for the process ID
366 */
367static char *
368get_pid_file_name (struct LEGACY_SERVICE_Context *sctx)
369{
370 char *pif;
371
372 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg,
373 sctx->service_name,
374 "PIDFILE",
375 &pif))
376 return NULL;
377 return pif;
378}
379
380
381/**
382 * Parse an IPv4 access control list.
383 *
384 * @param ret location where to write the ACL (set)
385 * @param sctx service context to use to get the configuration
386 * @param option name of the ACL option to parse
387 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
388 * no ACL configured)
389 */
390static int
391process_acl4 (struct GNUNET_STRINGS_IPv4NetworkPolicy **ret,
392 struct LEGACY_SERVICE_Context *sctx,
393 const char *option)
394{
395 char *opt;
396
397 if (! GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
398 {
399 *ret = NULL;
400 return GNUNET_OK;
401 }
402 GNUNET_break (GNUNET_OK ==
403 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
404 sctx->service_name,
405 option,
406 &opt));
407 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv4_policy (opt)))
408 {
409 LOG (GNUNET_ERROR_TYPE_WARNING,
410 _ ("Could not parse IPv4 network specification `%s' for `%s:%s'\n"),
411 opt,
412 sctx->service_name,
413 option);
414 GNUNET_free (opt);
415 return GNUNET_SYSERR;
416 }
417 GNUNET_free (opt);
418 return GNUNET_OK;
419}
420
421
422/**
423 * Parse an IPv6 access control list.
424 *
425 * @param ret location where to write the ACL (set)
426 * @param sctx service context to use to get the configuration
427 * @param option name of the ACL option to parse
428 * @return #GNUNET_SYSERR on parse error, #GNUNET_OK on success (including
429 * no ACL configured)
430 */
431static int
432process_acl6 (struct GNUNET_STRINGS_IPv6NetworkPolicy **ret,
433 struct LEGACY_SERVICE_Context *sctx,
434 const char *option)
435{
436 char *opt;
437
438 if (! GNUNET_CONFIGURATION_have_value (sctx->cfg, sctx->service_name, option))
439 {
440 *ret = NULL;
441 return GNUNET_OK;
442 }
443 GNUNET_break (GNUNET_OK ==
444 GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
445 sctx->service_name,
446 option,
447 &opt));
448 if (NULL == (*ret = GNUNET_STRINGS_parse_ipv6_policy (opt)))
449 {
450 LOG (GNUNET_ERROR_TYPE_WARNING,
451 _ ("Could not parse IPv6 network specification `%s' for `%s:%s'\n"),
452 opt,
453 sctx->service_name,
454 option);
455 GNUNET_free (opt);
456 return GNUNET_SYSERR;
457 }
458 GNUNET_free (opt);
459 return GNUNET_OK;
460}
461
462
463/**
464 * Add the given UNIX domain path as an address to the
465 * list (as the first entry).
466 *
467 * @param saddrs array to update
468 * @param saddrlens where to store the address length
469 * @param unixpath path to add
470 * @param abstract #GNUNET_YES to add an abstract UNIX domain socket. This
471 * parameter is ignore on systems other than LINUX
472 */
473static void
474add_unixpath (struct sockaddr **saddrs,
475 socklen_t *saddrlens,
476 const char *unixpath,
477 int abstract)
478{
479#ifdef AF_UNIX
480 struct sockaddr_un *un;
481
482 un = GNUNET_new (struct sockaddr_un);
483 un->sun_family = AF_UNIX;
484 GNUNET_strlcpy (un->sun_path, unixpath, sizeof(un->sun_path));
485#ifdef __linux__
486 if (GNUNET_YES == abstract)
487 un->sun_path[0] = '\0';
488#endif
489#if HAVE_SOCKADDR_UN_SUN_LEN
490 un->sun_len = (u_char) sizeof(struct sockaddr_un);
491#endif
492 *saddrs = (struct sockaddr *) un;
493 *saddrlens = sizeof(struct sockaddr_un);
494#else
495 /* this function should never be called
496 * unless AF_UNIX is defined! */
497 GNUNET_assert (0);
498#endif
499}
500
501
502/**
503 * Get the list of addresses that a server for the given service
504 * should bind to.
505 *
506 * @param service_name name of the service
507 * @param cfg configuration (which specifies the addresses)
508 * @param addrs set (call by reference) to an array of pointers to the
509 * addresses the server should bind to and listen on; the
510 * array will be NULL-terminated (on success)
511 * @param addr_lens set (call by reference) to an array of the lengths
512 * of the respective `struct sockaddr` struct in the @a addrs
513 * array (on success)
514 * @return number of addresses found on success,
515 * #GNUNET_SYSERR if the configuration
516 * did not specify reasonable finding information or
517 * if it specified a hostname that could not be resolved;
518 * #GNUNET_NO if the number of addresses configured is
519 * zero (in this case, `*addrs` and `*addr_lens` will be
520 * set to NULL).
521 */
522int
523LEGACY_SERVICE_get_server_addresses (
524 const char *service_name,
525 const struct GNUNET_CONFIGURATION_Handle *cfg,
526 struct sockaddr ***addrs,
527 socklen_t **addr_lens)
528{
529 int disablev6;
530 struct GNUNET_NETWORK_Handle *desc;
531 unsigned long long port;
532 char *unixpath;
533 struct addrinfo hints;
534 struct addrinfo *res;
535 struct addrinfo *pos;
536 struct addrinfo *next;
537 unsigned int i;
538 int resi;
539 int ret;
540 int abstract;
541 struct sockaddr **saddrs;
542 socklen_t *saddrlens;
543 char *hostname;
544
545 *addrs = NULL;
546 *addr_lens = NULL;
547 desc = NULL;
548 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "DISABLEV6"))
549 {
550 if (GNUNET_SYSERR ==
551 (disablev6 = GNUNET_CONFIGURATION_get_value_yesno (cfg,
552 service_name,
553 "DISABLEV6")))
554 return GNUNET_SYSERR;
555 }
556 else
557 disablev6 = GNUNET_NO;
558
559 if (! disablev6)
560 {
561 /* probe IPv6 support */
562 desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
563 if (NULL == desc)
564 {
565 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
566 (EACCES == errno))
567 {
568 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
569 return GNUNET_SYSERR;
570 }
571 LOG (GNUNET_ERROR_TYPE_INFO,
572 _ (
573 "Disabling IPv6 support for service `%s', failed to create IPv6 socket: %s\n"),
574 service_name,
575 strerror (errno));
576 disablev6 = GNUNET_YES;
577 }
578 else
579 {
580 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
581 desc = NULL;
582 }
583 }
584
585 port = 0;
586 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "PORT"))
587 {
588 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (cfg,
589 service_name,
590 "PORT",
591 &port))
592 {
593 LOG (GNUNET_ERROR_TYPE_ERROR,
594 _ ("Require valid port number for service `%s' in configuration!\n"),
595 service_name);
596 }
597 if (port > 65535)
598 {
599 LOG (GNUNET_ERROR_TYPE_ERROR,
600 _ ("Require valid port number for service `%s' in configuration!\n"),
601 service_name);
602 return GNUNET_SYSERR;
603 }
604 }
605
606 if (GNUNET_CONFIGURATION_have_value (cfg, service_name, "BINDTO"))
607 {
608 GNUNET_break (GNUNET_OK ==
609 GNUNET_CONFIGURATION_get_value_string (cfg,
610 service_name,
611 "BINDTO",
612 &hostname));
613 }
614 else
615 hostname = NULL;
616
617 unixpath = NULL;
618 abstract = GNUNET_NO;
619#ifdef AF_UNIX
620 if ((GNUNET_YES ==
621 GNUNET_CONFIGURATION_have_value (cfg, service_name, "UNIXPATH")) &&
622 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_filename (cfg,
623 service_name,
624 "UNIXPATH",
625 &unixpath)) &&
626 (0 < strlen (unixpath)))
627 {
628 /* probe UNIX support */
629 struct sockaddr_un s_un;
630
631 if (strlen (unixpath) >= sizeof(s_un.sun_path))
632 {
633 LOG (GNUNET_ERROR_TYPE_WARNING,
634 _ ("UNIXPATH `%s' too long, maximum length is %llu\n"),
635 unixpath,
636 (unsigned long long) sizeof(s_un.sun_path));
637 unixpath = GNUNET_NETWORK_shorten_unixpath (unixpath);
638 LOG (GNUNET_ERROR_TYPE_INFO, _ ("Using `%s' instead\n"), unixpath);
639 }
640#ifdef __linux__
641 abstract = GNUNET_CONFIGURATION_get_value_yesno (cfg,
642 "TESTING",
643 "USE_ABSTRACT_SOCKETS");
644 if (GNUNET_SYSERR == abstract)
645 abstract = GNUNET_NO;
646#endif
647 if ((GNUNET_YES != abstract) &&
648 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (unixpath)))
649 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "mkdir", unixpath);
650 }
651 if (NULL != unixpath)
652 {
653 desc = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_STREAM, 0);
654 if (NULL == desc)
655 {
656 if ((ENOBUFS == errno) || (ENOMEM == errno) || (ENFILE == errno) ||
657 (EACCES == errno))
658 {
659 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "socket");
660 GNUNET_free (hostname);
661 GNUNET_free (unixpath);
662 return GNUNET_SYSERR;
663 }
664 LOG (GNUNET_ERROR_TYPE_INFO,
665 _ (
666 "Disabling UNIX domain socket support for service `%s', failed to create UNIX domain socket: %s\n"),
667 service_name,
668 strerror (errno));
669 GNUNET_free (unixpath);
670 unixpath = NULL;
671 }
672 else
673 {
674 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
675 desc = NULL;
676 }
677 }
678#endif
679
680 if ((0 == port) && (NULL == unixpath))
681 {
682 LOG (GNUNET_ERROR_TYPE_ERROR,
683 _ (
684 "Have neither PORT nor UNIXPATH for service `%s', but one is required\n"),
685 service_name);
686 GNUNET_free (hostname);
687 return GNUNET_SYSERR;
688 }
689 if (0 == port)
690 {
691 saddrs = GNUNET_malloc (2 * sizeof(struct sockaddr *));
692 saddrlens = GNUNET_malloc (2 * sizeof(socklen_t));
693 add_unixpath (saddrs, saddrlens, unixpath, abstract);
694 GNUNET_free (unixpath);
695 GNUNET_free (hostname);
696 *addrs = saddrs;
697 *addr_lens = saddrlens;
698 return 1;
699 }
700
701 if (NULL != hostname)
702 {
703 LOG (GNUNET_ERROR_TYPE_DEBUG,
704 "Resolving `%s' since that is where `%s' will bind to.\n",
705 hostname,
706 service_name);
707 memset (&hints, 0, sizeof(struct addrinfo));
708 if (disablev6)
709 hints.ai_family = AF_INET;
710 hints.ai_protocol = IPPROTO_TCP;
711 if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
712 (NULL == res))
713 {
714 LOG (GNUNET_ERROR_TYPE_ERROR,
715 _ ("Failed to resolve `%s': %s\n"),
716 hostname,
717 gai_strerror (ret));
718 GNUNET_free (hostname);
719 GNUNET_free (unixpath);
720 return GNUNET_SYSERR;
721 }
722 next = res;
723 i = 0;
724 while (NULL != (pos = next))
725 {
726 next = pos->ai_next;
727 if ((disablev6) && (pos->ai_family == AF_INET6))
728 continue;
729 i++;
730 }
731 if (0 == i)
732 {
733 LOG (GNUNET_ERROR_TYPE_ERROR,
734 _ ("Failed to find %saddress for `%s'.\n"),
735 disablev6 ? "IPv4 " : "",
736 hostname);
737 freeaddrinfo (res);
738 GNUNET_free (hostname);
739 GNUNET_free (unixpath);
740 return GNUNET_SYSERR;
741 }
742 resi = i;
743 if (NULL != unixpath)
744 resi++;
745 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
746 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
747 i = 0;
748 if (NULL != unixpath)
749 {
750 add_unixpath (saddrs, saddrlens, unixpath, abstract);
751 i++;
752 }
753 next = res;
754 while (NULL != (pos = next))
755 {
756 next = pos->ai_next;
757 if ((disablev6) && (AF_INET6 == pos->ai_family))
758 continue;
759 if ((IPPROTO_TCP != pos->ai_protocol) && (0 != pos->ai_protocol))
760 continue; /* not TCP */
761 if ((SOCK_STREAM != pos->ai_socktype) && (0 != pos->ai_socktype))
762 continue; /* huh? */
763 LOG (GNUNET_ERROR_TYPE_DEBUG,
764 "Service `%s' will bind to `%s'\n",
765 service_name,
766 GNUNET_a2s (pos->ai_addr, pos->ai_addrlen));
767 if (AF_INET == pos->ai_family)
768 {
769 GNUNET_assert (sizeof(struct sockaddr_in) == pos->ai_addrlen);
770 saddrlens[i] = pos->ai_addrlen;
771 saddrs[i] = GNUNET_malloc (saddrlens[i]);
772 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
773 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
774 }
775 else
776 {
777 GNUNET_assert (AF_INET6 == pos->ai_family);
778 GNUNET_assert (sizeof(struct sockaddr_in6) == pos->ai_addrlen);
779 saddrlens[i] = pos->ai_addrlen;
780 saddrs[i] = GNUNET_malloc (saddrlens[i]);
781 GNUNET_memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
782 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
783 }
784 i++;
785 }
786 GNUNET_free (hostname);
787 freeaddrinfo (res);
788 resi = i;
789 }
790 else
791 {
792 /* will bind against everything, just set port */
793 if (disablev6)
794 {
795 /* V4-only */
796 resi = 1;
797 if (NULL != unixpath)
798 resi++;
799 i = 0;
800 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
801 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
802 if (NULL != unixpath)
803 {
804 add_unixpath (saddrs, saddrlens, unixpath, abstract);
805 i++;
806 }
807 saddrlens[i] = sizeof(struct sockaddr_in);
808 saddrs[i] = GNUNET_malloc (saddrlens[i]);
809#if HAVE_SOCKADDR_IN_SIN_LEN
810 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
811#endif
812 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
813 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
814 }
815 else
816 {
817 /* dual stack */
818 resi = 2;
819 if (NULL != unixpath)
820 resi++;
821 saddrs = GNUNET_malloc ((resi + 1) * sizeof(struct sockaddr *));
822 saddrlens = GNUNET_malloc ((resi + 1) * sizeof(socklen_t));
823 i = 0;
824 if (NULL != unixpath)
825 {
826 add_unixpath (saddrs, saddrlens, unixpath, abstract);
827 i++;
828 }
829 saddrlens[i] = sizeof(struct sockaddr_in6);
830 saddrs[i] = GNUNET_malloc (saddrlens[i]);
831#if HAVE_SOCKADDR_IN_SIN_LEN
832 ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
833#endif
834 ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
835 ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
836 i++;
837 saddrlens[i] = sizeof(struct sockaddr_in);
838 saddrs[i] = GNUNET_malloc (saddrlens[i]);
839#if HAVE_SOCKADDR_IN_SIN_LEN
840 ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
841#endif
842 ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
843 ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
844 }
845 }
846 GNUNET_free (unixpath);
847 *addrs = saddrs;
848 *addr_lens = saddrlens;
849 return resi;
850}
851
852
853/**
854 * Setup addr, addrlen, idle_timeout
855 * based on configuration!
856 *
857 * Configuration may specify:
858 * - PORT (where to bind to for TCP)
859 * - UNIXPATH (where to bind to for UNIX domain sockets)
860 * - TIMEOUT (after how many ms does an inactive service timeout);
861 * - DISABLEV6 (disable support for IPv6, otherwise we use dual-stack)
862 * - BINDTO (hostname or IP address to bind to, otherwise we take everything)
863 * - ACCEPT_FROM (only allow connections from specified IPv4 subnets)
864 * - ACCEPT_FROM6 (only allow connections from specified IPv6 subnets)
865 * - REJECT_FROM (disallow allow connections from specified IPv4 subnets)
866 * - REJECT_FROM6 (disallow allow connections from specified IPv6 subnets)
867 *
868 * @param sctx service context to initialize
869 * @return #GNUNET_OK if configuration succeeded
870 */
871static int
872setup_service (struct LEGACY_SERVICE_Context *sctx)
873{
874 struct GNUNET_TIME_Relative idleout;
875 int tolerant;
876 const char *nfds;
877 unsigned int cnt;
878 int flags;
879
880 if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
881 sctx->service_name,
882 "TIMEOUT"))
883 {
884 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_time (sctx->cfg,
885 sctx->service_name,
886 "TIMEOUT",
887 &idleout))
888 {
889 LOG (GNUNET_ERROR_TYPE_ERROR,
890 _ ("Specified value for `%s' of service `%s' is invalid\n"),
891 "TIMEOUT",
892 sctx->service_name);
893 return GNUNET_SYSERR;
894 }
895 sctx->timeout = idleout;
896 }
897 else
898 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
899
900 if (GNUNET_CONFIGURATION_have_value (sctx->cfg,
901 sctx->service_name,
902 "TOLERANT"))
903 {
904 if (GNUNET_SYSERR ==
905 (tolerant = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
906 sctx->service_name,
907 "TOLERANT")))
908 {
909 LOG (GNUNET_ERROR_TYPE_ERROR,
910 _ ("Specified value for `%s' of service `%s' is invalid\n"),
911 "TOLERANT",
912 sctx->service_name);
913 return GNUNET_SYSERR;
914 }
915 }
916 else
917 tolerant = GNUNET_NO;
918
919 errno = 0;
920 if ((NULL != (nfds = getenv ("LISTEN_FDS"))) &&
921 (1 == sscanf (nfds, "%u", &cnt)) && (cnt > 0) && (cnt < FD_SETSIZE) &&
922 (cnt + 4 < FD_SETSIZE))
923 {
924 sctx->lsocks =
925 GNUNET_malloc (sizeof(struct GNUNET_NETWORK_Handle *) * (cnt + 1));
926 while (0 < cnt--)
927 {
928 flags = fcntl (3 + cnt, F_GETFD);
929 if ((flags < 0) || (0 != (flags & FD_CLOEXEC)) ||
930 (NULL ==
931 (sctx->lsocks[cnt] = GNUNET_NETWORK_socket_box_native (3 + cnt))))
932 {
933 LOG (GNUNET_ERROR_TYPE_ERROR,
934 _ (
935 "Could not access pre-bound socket %u, will try to bind myself\n"),
936 (unsigned int) 3 + cnt);
937 cnt++;
938 while (sctx->lsocks[cnt] != NULL)
939 GNUNET_break (0 == GNUNET_NETWORK_socket_close (sctx->lsocks[cnt++]));
940 GNUNET_free (sctx->lsocks);
941 sctx->lsocks = NULL;
942 break;
943 }
944 }
945 unsetenv ("LISTEN_FDS");
946 }
947
948 if ((NULL == sctx->lsocks) &&
949 (GNUNET_SYSERR == LEGACY_SERVICE_get_server_addresses (sctx->service_name,
950 sctx->cfg,
951 &sctx->addrs,
952 &sctx->addrlens)))
953 return GNUNET_SYSERR;
954 sctx->require_found = tolerant ? GNUNET_NO : GNUNET_YES;
955 sctx->match_uid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
956 sctx->service_name,
957 "UNIX_MATCH_UID");
958 sctx->match_gid = GNUNET_CONFIGURATION_get_value_yesno (sctx->cfg,
959 sctx->service_name,
960 "UNIX_MATCH_GID");
961 process_acl4 (&sctx->v4_denied, sctx, "REJECT_FROM");
962 process_acl4 (&sctx->v4_allowed, sctx, "ACCEPT_FROM");
963 process_acl6 (&sctx->v6_denied, sctx, "REJECT_FROM6");
964 process_acl6 (&sctx->v6_allowed, sctx, "ACCEPT_FROM6");
965
966 return GNUNET_OK;
967}
968
969
970/**
971 * Get the name of the user that'll be used
972 * to provide the service.
973 *
974 * @param sctx service context
975 * @return value of the 'USERNAME' option
976 */
977static char *
978get_user_name (struct LEGACY_SERVICE_Context *sctx)
979{
980 char *un;
981
982 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_filename (sctx->cfg,
983 sctx->service_name,
984 "USERNAME",
985 &un))
986 return NULL;
987 return un;
988}
989
990
991/**
992 * Write PID file.
993 *
994 * @param sctx service context
995 * @param pid PID to write (should be equal to 'getpid()'
996 * @return #GNUNET_OK on success (including no work to be done)
997 */
998static int
999write_pid_file (struct LEGACY_SERVICE_Context *sctx, pid_t pid)
1000{
1001 FILE *pidfd;
1002 char *pif;
1003 char *user;
1004 char *rdir;
1005 int len;
1006
1007 if (NULL == (pif = get_pid_file_name (sctx)))
1008 return GNUNET_OK; /* no file desired */
1009 user = get_user_name (sctx);
1010 rdir = GNUNET_strdup (pif);
1011 len = strlen (rdir);
1012 while ((len > 0) && (rdir[len] != DIR_SEPARATOR))
1013 len--;
1014 rdir[len] = '\0';
1015 if (0 != access (rdir, F_OK))
1016 {
1017 /* we get to create a directory -- and claim it
1018 * as ours! */
1019 (void) GNUNET_DISK_directory_create (rdir);
1020 if ((NULL != user) && (0 < strlen (user)))
1021 GNUNET_DISK_file_change_owner (rdir, user);
1022 }
1023 if (0 != access (rdir, W_OK | X_OK))
1024 {
1025 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "access", rdir);
1026 GNUNET_free (rdir);
1027 GNUNET_free (user);
1028 GNUNET_free (pif);
1029 return GNUNET_SYSERR;
1030 }
1031 GNUNET_free (rdir);
1032 pidfd = fopen (pif, "w");
1033 if (NULL == pidfd)
1034 {
1035 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_ERROR, "fopen", pif);
1036 GNUNET_free (pif);
1037 GNUNET_free (user);
1038 return GNUNET_SYSERR;
1039 }
1040 if (0 > fprintf (pidfd, "%u", pid))
1041 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "fprintf", pif);
1042 GNUNET_break (0 == fclose (pidfd));
1043 if ((NULL != user) && (0 < strlen (user)))
1044 GNUNET_DISK_file_change_owner (pif, user);
1045 GNUNET_free (user);
1046 GNUNET_free (pif);
1047 return GNUNET_OK;
1048}
1049
1050
1051/**
1052 * Task run during shutdown. Stops the server/service.
1053 *
1054 * @param cls the `struct LEGACY_SERVICE_Context`
1055 */
1056static void
1057shutdown_task (void *cls)
1058{
1059 struct LEGACY_SERVICE_Context *service = cls;
1060 struct GNUNET_SERVER_Handle *server = service->server;
1061
1062 service->shutdown_task = NULL;
1063 if (0 != (service->options & LEGACY_SERVICE_OPTION_SOFT_SHUTDOWN))
1064 GNUNET_SERVER_stop_listening (server);
1065 else
1066 GNUNET_SERVER_destroy (server);
1067}
1068
1069
1070/**
1071 * Initial task for the service.
1072 *
1073 * @param cls service context
1074 */
1075static void
1076service_task (void *cls)
1077{
1078 struct LEGACY_SERVICE_Context *sctx = cls;
1079 unsigned int i;
1080
1081 GNUNET_RESOLVER_connect (sctx->cfg);
1082 if (NULL != sctx->lsocks)
1083 sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
1084 sctx,
1085 sctx->lsocks,
1086 sctx->timeout,
1087 sctx->require_found);
1088 else
1089 sctx->server = GNUNET_SERVER_create (&check_access,
1090 sctx,
1091 sctx->addrs,
1092 sctx->addrlens,
1093 sctx->timeout,
1094 sctx->require_found);
1095 if (NULL == sctx->server)
1096 {
1097 if (NULL != sctx->addrs)
1098 for (i = 0; NULL != sctx->addrs[i]; i++)
1099 LOG (GNUNET_ERROR_TYPE_INFO,
1100 _ ("Failed to start `%s' at `%s'\n"),
1101 sctx->service_name,
1102 GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1103 sctx->ret = GNUNET_SYSERR;
1104 return;
1105 }
1106
1107 if (NULL != sctx->addrs)
1108 for (i = 0; NULL != sctx->addrs[i]; i++)
1109 if ((AF_UNIX == sctx->addrs[i]->sa_family) &&
1110 ('\0' != ((const struct sockaddr_un *) sctx->addrs[i])->sun_path[0]))
1111 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)
1112 sctx->addrs[i])
1113 ->sun_path,
1114 sctx->match_uid,
1115 sctx->match_gid);
1116
1117 if (0 == (sctx->options & LEGACY_SERVICE_OPTION_MANUAL_SHUTDOWN))
1118 {
1119 /* install a task that will kill the server
1120 * process if the scheduler ever gets a shutdown signal */
1121 sctx->shutdown_task = GNUNET_SCHEDULER_add_shutdown (&shutdown_task, sctx);
1122 }
1123 sctx->my_handlers = GNUNET_malloc (sizeof(defhandlers));
1124 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof(defhandlers));
1125 i = 0;
1126 while (NULL != sctx->my_handlers[i].callback)
1127 sctx->my_handlers[i++].callback_cls = sctx;
1128 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1129 if (-1 != sctx->ready_confirm_fd)
1130 {
1131 GNUNET_break (1 == write (sctx->ready_confirm_fd, ".", 1));
1132 GNUNET_break (0 == close (sctx->ready_confirm_fd));
1133 sctx->ready_confirm_fd = -1;
1134 write_pid_file (sctx, getpid ());
1135 }
1136 if (NULL != sctx->addrs)
1137 {
1138 i = 0;
1139 while (NULL != sctx->addrs[i])
1140 {
1141 LOG (GNUNET_ERROR_TYPE_INFO,
1142 _ ("Service `%s' runs at %s\n"),
1143 sctx->service_name,
1144 GNUNET_a2s (sctx->addrs[i], sctx->addrlens[i]));
1145 i++;
1146 }
1147 }
1148 sctx->task (sctx->task_cls, sctx->server, sctx->cfg);
1149}
1150
1151
1152/**
1153 * Detach from terminal.
1154 *
1155 * @param sctx service context
1156 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1157 */
1158static int
1159detach_terminal (struct LEGACY_SERVICE_Context *sctx)
1160{
1161 pid_t pid;
1162 int nullfd;
1163 int filedes[2];
1164
1165 if (0 != pipe (filedes))
1166 {
1167 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "pipe");
1168 return GNUNET_SYSERR;
1169 }
1170 pid = fork ();
1171 if (pid < 0)
1172 {
1173 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "fork");
1174 return GNUNET_SYSERR;
1175 }
1176 if (0 != pid)
1177 {
1178 /* Parent */
1179 char c;
1180
1181 GNUNET_break (0 == close (filedes[1]));
1182 c = 'X';
1183 if (1 != read (filedes[0], &c, sizeof(char)))
1184 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "read");
1185 fflush (stdout);
1186 switch (c)
1187 {
1188 case '.':
1189 exit (0);
1190
1191 case 'I':
1192 LOG (GNUNET_ERROR_TYPE_INFO,
1193 _ ("Service process failed to initialize\n"));
1194 break;
1195
1196 case 'S':
1197 LOG (GNUNET_ERROR_TYPE_INFO,
1198 _ ("Service process could not initialize server function\n"));
1199 break;
1200
1201 case 'X':
1202 LOG (GNUNET_ERROR_TYPE_INFO,
1203 _ ("Service process failed to report status\n"));
1204 break;
1205 }
1206 exit (1); /* child reported error */
1207 }
1208 GNUNET_break (0 == close (0));
1209 GNUNET_break (0 == close (1));
1210 GNUNET_break (0 == close (filedes[0]));
1211 nullfd = open ("/dev/null", O_RDWR | O_APPEND);
1212 if (nullfd < 0)
1213 return GNUNET_SYSERR;
1214 /* set stdin/stdout to /dev/null */
1215 if ((dup2 (nullfd, 0) < 0) || (dup2 (nullfd, 1) < 0))
1216 {
1217 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "dup2");
1218 (void) close (nullfd);
1219 return GNUNET_SYSERR;
1220 }
1221 (void) close (nullfd);
1222 /* Detach from controlling terminal */
1223 pid = setsid ();
1224 if (-1 == pid)
1225 LOG_STRERROR (GNUNET_ERROR_TYPE_ERROR, "setsid");
1226 sctx->ready_confirm_fd = filedes[1];
1227
1228 return GNUNET_OK;
1229}
1230
1231
1232/**
1233 * Set user ID.
1234 *
1235 * @param sctx service context
1236 * @return #GNUNET_OK on success, #GNUNET_SYSERR on error
1237 */
1238static int
1239set_user_id (struct LEGACY_SERVICE_Context *sctx)
1240{
1241 char *user;
1242
1243 if (NULL == (user = get_user_name (sctx)))
1244 return GNUNET_OK; /* keep */
1245
1246 struct passwd *pws;
1247
1248 errno = 0;
1249 pws = getpwnam (user);
1250 if (NULL == pws)
1251 {
1252 LOG (GNUNET_ERROR_TYPE_ERROR,
1253 _ ("Cannot obtain information about user `%s': %s\n"),
1254 user,
1255 errno == 0 ? _ ("No such user") : strerror (errno));
1256 GNUNET_free (user);
1257 return GNUNET_SYSERR;
1258 }
1259 if ((0 != setgid (pws->pw_gid)) || (0 != setegid (pws->pw_gid)) ||
1260#if HAVE_INITGROUPS
1261 (0 != initgroups (user, pws->pw_gid)) ||
1262#endif
1263 (0 != setuid (pws->pw_uid)) || (0 != seteuid (pws->pw_uid)))
1264 {
1265 if ((0 != setregid (pws->pw_gid, pws->pw_gid)) ||
1266 (0 != setreuid (pws->pw_uid, pws->pw_uid)))
1267 {
1268 LOG (GNUNET_ERROR_TYPE_ERROR,
1269 _ ("Cannot change user/group to `%s': %s\n"),
1270 user,
1271 strerror (errno));
1272 GNUNET_free (user);
1273 return GNUNET_SYSERR;
1274 }
1275 }
1276
1277 GNUNET_free (user);
1278 return GNUNET_OK;
1279}
1280
1281
1282/**
1283 * Delete the PID file that was created by our parent.
1284 *
1285 * @param sctx service context
1286 */
1287static void
1288pid_file_delete (struct LEGACY_SERVICE_Context *sctx)
1289{
1290 char *pif = get_pid_file_name (sctx);
1291
1292 if (NULL == pif)
1293 return; /* no PID file */
1294 if (0 != unlink (pif))
1295 LOG_STRERROR_FILE (GNUNET_ERROR_TYPE_WARNING, "unlink", pif);
1296 GNUNET_free (pif);
1297}
1298
1299
1300/**
1301 * Run a standard GNUnet service startup sequence (initialize loggers
1302 * and configuration, parse options).
1303 *
1304 * @param argc number of command line arguments
1305 * @param argv command line arguments
1306 * @param service_name our service name
1307 * @param options service options
1308 * @param task main task of the service
1309 * @param task_cls closure for @a task
1310 * @return #GNUNET_SYSERR on error, #GNUNET_OK
1311 * if we shutdown nicely
1312 */
1313int
1314LEGACY_SERVICE_run (int argc,
1315 char *const *argv,
1316 const char *service_name,
1317 enum LEGACY_SERVICE_Options options,
1318 LEGACY_SERVICE_Main task,
1319 void *task_cls)
1320{
1321#define HANDLE_ERROR \
1322 do \
1323 { \
1324 GNUNET_break (0); \
1325 goto shutdown; \
1326 } while (0)
1327
1328 int err;
1329 int ret;
1330 char *cfg_fn;
1331 char *opt_cfg_fn;
1332 char *loglev;
1333 char *logfile;
1334 int do_daemonize;
1335 unsigned int i;
1336 unsigned long long skew_offset;
1337 unsigned long long skew_variance;
1338 long long clock_offset;
1339 struct LEGACY_SERVICE_Context sctx;
1340 struct GNUNET_CONFIGURATION_Handle *cfg;
1341 const char *xdg;
1342
1343 struct GNUNET_GETOPT_CommandLineOption service_options[] =
1344 { GNUNET_GETOPT_option_cfgfile (&opt_cfg_fn),
1345 GNUNET_GETOPT_option_flag ('d',
1346 "daemonize",
1347 gettext_noop (
1348 "do daemonize (detach from terminal)"),
1349 &do_daemonize),
1350 GNUNET_GETOPT_option_help (NULL),
1351 GNUNET_GETOPT_option_loglevel (&loglev),
1352 GNUNET_GETOPT_option_logfile (&logfile),
1353 GNUNET_GETOPT_option_version (PACKAGE_VERSION " " VCS_VERSION),
1354 GNUNET_GETOPT_OPTION_END };
1355 err = 1;
1356 do_daemonize = 0;
1357 logfile = NULL;
1358 loglev = NULL;
1359 opt_cfg_fn = NULL;
1360 xdg = getenv ("XDG_CONFIG_HOME");
1361 if (NULL != xdg)
1362 GNUNET_asprintf (&cfg_fn,
1363 "%s%s%s",
1364 xdg,
1365 DIR_SEPARATOR_STR,
1366 GNUNET_OS_project_data_get ()->config_file);
1367 else
1368 cfg_fn = GNUNET_strdup (GNUNET_OS_project_data_get ()->user_config_file);
1369 memset (&sctx, 0, sizeof(sctx));
1370 sctx.options = options;
1371 sctx.ready_confirm_fd = -1;
1372 sctx.ret = GNUNET_OK;
1373 sctx.timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1374 sctx.task = task;
1375 sctx.task_cls = task_cls;
1376 sctx.service_name = service_name;
1377 sctx.cfg = cfg = GNUNET_CONFIGURATION_create ();
1378
1379 /* setup subsystems */
1380 ret = GNUNET_GETOPT_run (service_name, service_options, argc, argv);
1381 if (GNUNET_SYSERR == ret)
1382 goto shutdown;
1383 if (GNUNET_NO == ret)
1384 {
1385 err = 0;
1386 goto shutdown;
1387 }
1388 if (GNUNET_OK != GNUNET_log_setup (service_name, loglev, logfile))
1389 HANDLE_ERROR;
1390 if (NULL == opt_cfg_fn)
1391 opt_cfg_fn = GNUNET_strdup (cfg_fn);
1392 if (GNUNET_YES == GNUNET_DISK_file_test (opt_cfg_fn))
1393 {
1394 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, opt_cfg_fn))
1395 {
1396 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1397 _ ("Malformed configuration file `%s', exit ...\n"),
1398 opt_cfg_fn);
1399 goto shutdown;
1400 }
1401 }
1402 else
1403 {
1404 if (GNUNET_SYSERR == GNUNET_CONFIGURATION_load (cfg, NULL))
1405 {
1406 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1407 _ ("Malformed configuration, exit ...\n"));
1408 goto shutdown;
1409 }
1410 if (0 != strcmp (opt_cfg_fn, cfg_fn))
1411 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1412 _ ("Could not access configuration file `%s'\n"),
1413 opt_cfg_fn);
1414 }
1415 if (GNUNET_OK != setup_service (&sctx))
1416 goto shutdown;
1417 if ((1 == do_daemonize) && (GNUNET_OK != detach_terminal (&sctx)))
1418 HANDLE_ERROR;
1419 if (GNUNET_OK != set_user_id (&sctx))
1420 goto shutdown;
1421 LOG (GNUNET_ERROR_TYPE_DEBUG,
1422 "Service `%s' runs with configuration from `%s'\n",
1423 service_name,
1424 opt_cfg_fn);
1425 if ((GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg,
1426 "TESTING",
1427 "SKEW_OFFSET",
1428 &skew_offset)) &&
1429 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_number (sctx.cfg,
1430 "TESTING",
1431 "SKEW_VARIANCE",
1432 &skew_variance)))
1433 {
1434 clock_offset = skew_offset - skew_variance;
1435 GNUNET_TIME_set_offset (clock_offset);
1436 LOG (GNUNET_ERROR_TYPE_DEBUG, "Skewing clock by %lld ms\n", clock_offset);
1437 }
1438 /* actually run service */
1439 err = 0;
1440 GNUNET_SCHEDULER_run (&service_task, &sctx);
1441 /* shutdown */
1442 if ((1 == do_daemonize) && (NULL != sctx.server))
1443 pid_file_delete (&sctx);
1444 GNUNET_free (sctx.my_handlers);
1445
1446shutdown:
1447 if (-1 != sctx.ready_confirm_fd)
1448 {
1449 if (1 != write (sctx.ready_confirm_fd, err ? "I" : "S", 1))
1450 LOG_STRERROR (GNUNET_ERROR_TYPE_WARNING, "write");
1451 GNUNET_break (0 == close (sctx.ready_confirm_fd));
1452 }
1453#if HAVE_MALLINFO2
1454 {
1455 char *counter;
1456
1457 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx.cfg,
1458 service_name,
1459 "GAUGER_HEAP")) &&
1460 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx.cfg,
1461 service_name,
1462 "GAUGER_HEAP",
1463 &counter)))
1464 {
1465 struct mallinfo2 mi;
1466
1467 mi = mallinfo2 ();
1468 GAUGER (service_name, counter, mi.usmblks, "blocks");
1469 GNUNET_free (counter);
1470 }
1471 }
1472#endif
1473 GNUNET_CONFIGURATION_destroy (cfg);
1474 i = 0;
1475 if (NULL != sctx.addrs)
1476 while (NULL != sctx.addrs[i])
1477 GNUNET_free_nz (sctx.addrs[i++]);
1478 GNUNET_free (sctx.addrs);
1479 GNUNET_free (sctx.addrlens);
1480 GNUNET_free (logfile);
1481 GNUNET_free (loglev);
1482 GNUNET_free (cfg_fn);
1483 GNUNET_free (opt_cfg_fn);
1484 GNUNET_free (sctx.v4_denied);
1485 GNUNET_free (sctx.v6_denied);
1486 GNUNET_free (sctx.v4_allowed);
1487 GNUNET_free (sctx.v6_allowed);
1488
1489 return err ? GNUNET_SYSERR : sctx.ret;
1490}
1491
1492
1493/**
1494 * Run a service startup sequence within an existing
1495 * initialized system.
1496 *
1497 * @param service_name our service name
1498 * @param cfg configuration to use
1499 * @param options service options
1500 * @return NULL on error, service handle
1501 */
1502struct LEGACY_SERVICE_Context *
1503LEGACY_SERVICE_start (const char *service_name,
1504 const struct GNUNET_CONFIGURATION_Handle *cfg,
1505 enum LEGACY_SERVICE_Options options)
1506{
1507 int i;
1508 struct LEGACY_SERVICE_Context *sctx;
1509
1510 sctx = GNUNET_new (struct LEGACY_SERVICE_Context);
1511 sctx->ready_confirm_fd = -1; /* no daemonizing */
1512 sctx->ret = GNUNET_OK;
1513 sctx->timeout = GNUNET_TIME_UNIT_FOREVER_REL;
1514 sctx->service_name = service_name;
1515 sctx->cfg = cfg;
1516 sctx->options = options;
1517
1518 /* setup subsystems */
1519 if (GNUNET_OK != setup_service (sctx))
1520 {
1521 LEGACY_SERVICE_stop (sctx);
1522 return NULL;
1523 }
1524 if (NULL != sctx->lsocks)
1525 sctx->server = GNUNET_SERVER_create_with_sockets (&check_access,
1526 sctx,
1527 sctx->lsocks,
1528 sctx->timeout,
1529 sctx->require_found);
1530 else
1531 sctx->server = GNUNET_SERVER_create (&check_access,
1532 sctx,
1533 sctx->addrs,
1534 sctx->addrlens,
1535 sctx->timeout,
1536 sctx->require_found);
1537
1538 if (NULL == sctx->server)
1539 {
1540 LEGACY_SERVICE_stop (sctx);
1541 return NULL;
1542 }
1543
1544 if (NULL != sctx->addrs)
1545 for (i = 0; NULL != sctx->addrs[i]; i++)
1546 if ((AF_UNIX == sctx->addrs[i]->sa_family) &&
1547 ('\0' != ((const struct sockaddr_un *) sctx->addrs[i])->sun_path[0]))
1548 GNUNET_DISK_fix_permissions (((const struct sockaddr_un *)
1549 sctx->addrs[i])
1550 ->sun_path,
1551 sctx->match_uid,
1552 sctx->match_gid);
1553
1554 sctx->my_handlers = GNUNET_malloc (sizeof(defhandlers));
1555 GNUNET_memcpy (sctx->my_handlers, defhandlers, sizeof(defhandlers));
1556 i = 0;
1557 while ((sctx->my_handlers[i].callback != NULL))
1558 sctx->my_handlers[i++].callback_cls = sctx;
1559 GNUNET_SERVER_add_handlers (sctx->server, sctx->my_handlers);
1560 return sctx;
1561}
1562
1563
1564/**
1565 * Obtain the server used by a service. Note that the server must NOT
1566 * be destroyed by the caller.
1567 *
1568 * @param ctx the service context returned from the start function
1569 * @return handle to the server for this service, NULL if there is none
1570 */
1571struct GNUNET_SERVER_Handle *
1572LEGACY_SERVICE_get_server (struct LEGACY_SERVICE_Context *ctx)
1573{
1574 return ctx->server;
1575}
1576
1577
1578/**
1579 * Get the NULL-terminated array of listen sockets for this service.
1580 *
1581 * @param ctx service context to query
1582 * @return NULL if there are no listen sockets, otherwise NULL-terminated
1583 * array of listen sockets.
1584 */
1585struct GNUNET_NETWORK_Handle *const *
1586LEGACY_SERVICE_get_listen_sockets (struct LEGACY_SERVICE_Context *ctx)
1587{
1588 return ctx->lsocks;
1589}
1590
1591
1592/**
1593 * Stop a service that was started with "LEGACY_SERVICE_start".
1594 *
1595 * @param sctx the service context returned from the start function
1596 */
1597void
1598LEGACY_SERVICE_stop (struct LEGACY_SERVICE_Context *sctx)
1599{
1600 unsigned int i;
1601
1602#if HAVE_MALLINFO2
1603 {
1604 char *counter;
1605
1606 if ((GNUNET_YES == GNUNET_CONFIGURATION_have_value (sctx->cfg,
1607 sctx->service_name,
1608 "GAUGER_HEAP")) &&
1609 (GNUNET_OK == GNUNET_CONFIGURATION_get_value_string (sctx->cfg,
1610 sctx->service_name,
1611 "GAUGER_HEAP",
1612 &counter)))
1613 {
1614 struct mallinfo2 mi;
1615
1616 mi = mallinfo2 ();
1617 GAUGER (sctx->service_name, counter, mi.usmblks, "blocks");
1618 GNUNET_free (counter);
1619 }
1620 }
1621#endif
1622 if (NULL != sctx->shutdown_task)
1623 {
1624 GNUNET_SCHEDULER_cancel (sctx->shutdown_task);
1625 sctx->shutdown_task = NULL;
1626 }
1627 if (NULL != sctx->server)
1628 GNUNET_SERVER_destroy (sctx->server);
1629 GNUNET_free (sctx->my_handlers);
1630 if (NULL != sctx->addrs)
1631 {
1632 i = 0;
1633 while (NULL != sctx->addrs[i])
1634 GNUNET_free_nz (sctx->addrs[i++]);
1635 GNUNET_free (sctx->addrs);
1636 }
1637 GNUNET_free (sctx->addrlens);
1638 GNUNET_free (sctx->v4_denied);
1639 GNUNET_free (sctx->v6_denied);
1640 GNUNET_free (sctx->v4_allowed);
1641 GNUNET_free (sctx->v6_allowed);
1642 GNUNET_free (sctx);
1643}
1644
1645
1646/* end of service.c */
diff --git a/src/transport/template_cfg_peer1.conf b/src/transport/template_cfg_peer1.conf
deleted file mode 100644
index 5ba198450..000000000
--- a/src/transport/template_cfg_peer1.conf
+++ /dev/null
@@ -1,50 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4GNUNET_RUNTIME_DIR = $GNUNET_TEST_HOME/runtime/
5GNUNET_USER_RUNTIME_DIR = $GNUNET_TEST_HOME/runtime/
6
7[nat]
8RETURN_LOCAL_ADDRESSES = YES
9DISABLEV6 = NO
10
11[transport-tcp]
12PORT = 12000
13TIMEOUT = 5 s
14
15[transport-udp]
16BROADCAST = NO
17
18[transport-unix]
19PORT = 12007
20
21[arm]
22PORT = 12005
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
24
25[statistics]
26PORT = 12004
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
28
29[resolver]
30PORT = 12003
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
32
33[peerinfo]
34PORT = 12002
35UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
36USE_INCLUDED_HELLOS = NO
37
38[transport]
39#PREFIX = valgrind --leak-check=full
40PORT = 12001
41UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
42
43[ats]
44WAN_QUOTA_IN = unlimited
45WAN_QUOTA_OUT = unlimited
46PORT = 12006
47UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-ats.sock
48
49[hostlist]
50SERVERS = dummy
diff --git a/src/transport/template_cfg_peer2.conf b/src/transport/template_cfg_peer2.conf
deleted file mode 100644
index 6ac610fec..000000000
--- a/src/transport/template_cfg_peer2.conf
+++ /dev/null
@@ -1,58 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4GNUNET_RUNTIME_DIR = $GNUNET_TEST_HOME/runtime/
5GNUNET_USER_RUNTIME_DIR = $GNUNET_TEST_HOME/runtime/
6
7[nat]
8RETURN_LOCAL_ADDRESSES = YES
9DISABLEV6 = NO
10
11[transport-tcp]
12PORT = 12100
13TIMEOUT = 5 s
14
15[transport-udp]
16BROADCAST = NO
17
18[transport-unix]
19PORT = 12017
20
21[transport-http_server]
22PORT = 12018
23USE_IPv6 = YES
24
25[transport-https_server]
26PORT = 12019
27KEY_FILE = $GNUNET_TEST_HOME/https_key_p1.key
28CERT_FILE = $GNUNET_TEST_HOME/https_cert_p1.crt
29USE_IPv6 = YES
30
31[arm]
32PORT = 12014
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
34
35[statistics]
36PORT = 12013
37UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
38
39[resolver]
40PORT = 12012
41UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
42
43[peerinfo]
44PORT = 12011
45UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
46USE_INCLUDED_HELLOS = NO
47
48[transport]
49#PREFIX = valgrind --leak-check=full
50PORT = 12010
51UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
52
53[ats]
54PORT = 12016
55UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-ats.sock
56
57[hostlist]
58SERVERS = dummy
diff --git a/src/transport/test_communicator_basic.c b/src/transport/test_communicator_basic.c
deleted file mode 100644
index f43cdaaf3..000000000
--- a/src/transport/test_communicator_basic.c
+++ /dev/null
@@ -1,1203 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19*/
20
21/**
22* @file transport/test_communicator_basic.c
23* @brief test the communicators
24* @author Julius Bünger
25* @author Martin Schanzenbach
26*/
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "transport-testing-communicator.h"
30#include "gnunet_ats_transport_service.h"
31#include "gnunet_signatures.h"
32#include "gnunet_testing_lib.h"
33#include "transport.h"
34#include "gnunet_statistics_service.h"
35
36#include <inttypes.h>
37
38
39#define LOG(kind, ...) GNUNET_log_from (kind, \
40 "test_transport_communicator", \
41 __VA_ARGS__)
42
43#define NUM_PEERS 2
44
45static struct GNUNET_SCHEDULER_Task *to_task[NUM_PEERS];
46
47static int queue_est = GNUNET_NO;
48
49static struct GNUNET_PeerIdentity peer_id[NUM_PEERS];
50
51static char *communicator_binary;
52
53static struct
54GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_hs[NUM_PEERS];
55
56static struct GNUNET_CONFIGURATION_Handle *cfg_peers[NUM_PEERS];
57
58static struct GNUNET_STATISTICS_Handle *stats[NUM_PEERS];
59
60static char *cfg_peers_name[NUM_PEERS];
61
62static int finished[NUM_PEERS];
63
64static int ret;
65
66static int bidirect = GNUNET_NO;
67
68static size_t long_message_size;
69
70static struct GNUNET_TIME_Absolute start_short[NUM_PEERS];
71
72static struct GNUNET_TIME_Absolute start_long[NUM_PEERS];
73
74static struct GNUNET_TIME_Absolute timeout[NUM_PEERS];
75
76// static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *my_tc;
77
78static char *communicator_name;
79
80static char *test_name;
81
82static struct GNUNET_STATISTICS_GetHandle *box_stats[NUM_PEERS];
83
84static struct GNUNET_STATISTICS_GetHandle *rekey_stats[NUM_PEERS];
85
86#define TEST_SECTION "test-setup"
87
88#define SHORT_MESSAGE_SIZE 128
89
90#define LONG_MESSAGE_SIZE 32000 /* FIXME */
91
92#define ALLOWED_PACKET_LOSS 91
93
94#define BURST_PACKETS 5000
95
96#define TOTAL_ITERATIONS 1
97
98#define PEER_A 0
99
100#define PEER_B 1
101
102static unsigned int iterations_left[NUM_PEERS];
103
104#define TIMEOUT_MULTIPLIER 1
105
106#define DELAY \
107 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,200)
108
109#define SHORT_BURST_WINDOW \
110 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,2)
111
112#define LONG_BURST_WINDOW \
113 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,2)
114
115enum TestPhase
116{
117 TP_INIT,
118 TP_BURST_SHORT,
119 TP_BURST_LONG,
120 TP_SIZE_CHECK
121};
122
123static unsigned int phase_short[NUM_PEERS];
124
125static unsigned int phase_long[NUM_PEERS];
126
127static unsigned int phase_size[NUM_PEERS];
128
129static long long unsigned int allowed_packet_loss_short;
130
131static long long unsigned int allowed_packet_loss_long;
132
133static long long unsigned int burst_packets_short;
134
135static long long unsigned int burst_packets_long;
136
137static long long unsigned int delay_long_value;
138
139static long long unsigned int delay_short_value;
140
141static struct GNUNET_TIME_Relative delay_short;
142
143static struct GNUNET_TIME_Relative delay_long;
144
145static size_t num_sent_short[NUM_PEERS];
146
147static size_t num_sent_long[NUM_PEERS];
148
149static size_t num_sent_size[NUM_PEERS];
150
151static uint32_t ack[NUM_PEERS];
152
153static enum TestPhase phase[NUM_PEERS];
154
155static size_t num_received_short[NUM_PEERS];
156
157static size_t num_received_long[NUM_PEERS];
158
159static size_t num_received_size[NUM_PEERS];
160
161static uint64_t avg_latency[NUM_PEERS];
162
163static void
164communicator_available_cb (
165 void *cls,
166 struct
167 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
168 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc,
169 char *address_prefix)
170{
171 LOG (GNUNET_ERROR_TYPE_INFO,
172 "Communicator available. (cc: %u, prefix: %s)\n",
173 cc,
174 address_prefix);
175}
176
177
178static void
179open_queue (void *cls)
180{
181 const char *address = cls;
182
183 if (NULL != tc_hs[PEER_A]->c_mq)
184 {
185 queue_est = GNUNET_YES;
186 GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (tc_hs[PEER_A],
187 &peer_id[PEER_B],
188 address);
189 }
190 else
191 {
192 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
193 &open_queue,
194 (void *) address);
195 }
196}
197
198
199static void
200add_address_cb (
201 void *cls,
202 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
203 const char *address,
204 struct GNUNET_TIME_Relative expiration,
205 uint32_t aid,
206 enum GNUNET_NetworkType nt)
207{
208 LOG (GNUNET_ERROR_TYPE_DEBUG,
209 "New address. (addr: %s, expir: %s, ID: %" PRIu32 ", nt: %u\n",
210 address,
211 GNUNET_STRINGS_relative_time_to_string (expiration,
212 GNUNET_NO),
213 aid,
214 (int) nt);
215 // addresses[1] = GNUNET_strdup (address);
216 if ((0 == strcmp ((char*) cls, cfg_peers_name[PEER_B])) &&
217 (GNUNET_NO == queue_est))
218 {
219 open_queue ((void *) address);
220 }
221}
222
223
224/**
225 * @brief Callback that informs whether the requested queue will be
226 * established
227 *
228 * Implements #GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback.
229 *
230 * @param cls Closure - unused
231 * @param tc_h Communicator handle - unused
232 * @param will_try #GNUNET_YES if queue will be established
233 * #GNUNET_NO if queue will not be established (bogous address)
234 */
235static void
236queue_create_reply_cb (
237 void *cls,
238 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
239 int will_try)
240{
241 (void) cls;
242 (void) tc_h;
243 if (GNUNET_YES == will_try)
244 LOG (GNUNET_ERROR_TYPE_DEBUG,
245 "Queue will be established!\n");
246 else
247 LOG (GNUNET_ERROR_TYPE_WARNING,
248 "Queue won't be established (bougus address?)!\n");
249}
250
251
252static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
253handle_backchannel_cb (void *cls,
254 struct GNUNET_MessageHeader *msg,
255 struct GNUNET_PeerIdentity *pid)
256{
257 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
258
259 (void) tc_h;
260 (void) msg;
261 LOG (GNUNET_ERROR_TYPE_DEBUG, "Handling BC message...\n");
262 if (0 == memcmp (&peer_id[PEER_A], pid, sizeof (*pid)))
263 return tc_hs[PEER_A];
264 else
265 return tc_hs[PEER_B];
266}
267
268
269static char*
270make_payload (size_t payload_size)
271{
272 struct GNUNET_TIME_Absolute ts;
273 struct GNUNET_TIME_AbsoluteNBO ts_n;
274 char *payload = GNUNET_malloc (payload_size);
275
276 LOG (GNUNET_ERROR_TYPE_DEBUG,
277 "Making payload of size %lu\n", payload_size);
278 GNUNET_assert (payload_size >= 8); // So that out timestamp fits
279 ts = GNUNET_TIME_absolute_get ();
280 ts_n = GNUNET_TIME_absolute_hton (ts);
281 memset (payload, 'a', payload_size);
282 memcpy (payload, &ts_n, sizeof (struct GNUNET_TIME_AbsoluteNBO));
283 return payload;
284}
285
286static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
287get_tc_h (unsigned int peer_nr)
288{
289 LOG (GNUNET_ERROR_TYPE_DEBUG,
290 "Got peer %u\n",
291 peer_nr);
292
293 LOG (GNUNET_ERROR_TYPE_DEBUG,
294 "Handle %p peer 0\n",
295 tc_hs[0]);
296
297 LOG (GNUNET_ERROR_TYPE_DEBUG,
298 "Handle %p peer 1\n",
299 tc_hs[1]);
300
301 LOG (GNUNET_ERROR_TYPE_DEBUG,
302 "Handle %p get\n",
303 tc_hs[peer_nr]);
304
305 return tc_hs[peer_nr];
306}
307
308
309static unsigned int
310get_peer_nr_from_tc (struct
311 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
312{
313 if (tc_h == get_tc_h (0))
314 return PEER_A;
315 else
316 return PEER_B;
317}
318
319static unsigned int
320get_peer_nr (void *cls, unsigned int get_the_other_one)
321{
322 if (0 == strcmp ((char*) cls, cfg_peers_name[0]))
323 return get_the_other_one ? PEER_B : PEER_A;
324 else
325 return get_the_other_one ? PEER_A : PEER_B;
326}
327
328static void
329process_statistics_box_done (void *cls, int success)
330{
331 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
332 unsigned int peer_nr;
333
334 peer_nr = get_peer_nr_from_tc (tc_h);
335
336 if (NULL != box_stats[peer_nr])
337 box_stats[peer_nr] = NULL;
338 if (NULL == rekey_stats[peer_nr])
339 {
340 LOG (GNUNET_ERROR_TYPE_DEBUG,
341 "Finished\n");
342 GNUNET_SCHEDULER_shutdown ();
343 }
344}
345
346
347static void
348process_statistics_rekey_done (void *cls, int success)
349{
350 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
351 unsigned int peer_nr;
352
353 peer_nr = get_peer_nr_from_tc (tc_h);
354
355 if (NULL != rekey_stats[peer_nr])
356 rekey_stats[peer_nr] = NULL;
357 if (NULL == box_stats[peer_nr])
358 {
359 LOG (GNUNET_ERROR_TYPE_DEBUG,
360 "Finished\n");
361 GNUNET_SCHEDULER_shutdown ();
362 }
363}
364
365static int
366process_statistics (void *cls,
367 const char *subsystem,
368 const char *name,
369 uint64_t value,
370 int is_persistent)
371{
372 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
373 "Statistic: Name %s and value %lu\n",
374 name,
375 value);
376 if ((0 == strcmp ("rekey", test_name)) && (0 == strcmp (
377 "# rekeying successful",
378 name)) && (0 == value))
379 {
380 ret = 2;
381 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
382 "No successful rekeying!\n");
383 GNUNET_SCHEDULER_shutdown ();
384 }
385 if ((0 == strcmp ("backchannel", test_name)) &&
386 (0 == strcmp (
387 "# messages decrypted with BOX",
388 name))
389 && (9000 > value))
390 {
391 ret = 2;
392 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
393 "Not enough BOX messages!\n");
394 GNUNET_SCHEDULER_shutdown ();
395 }
396 if ((0 == strcmp ("rekey", test_name)) &&
397 (0 == strcmp (
398 "# messages decrypted with BOX",
399 name))
400 && (6000 > value))
401 {
402 ret = 2;
403 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
404 "Not enough BOX messages!\n");
405 GNUNET_SCHEDULER_shutdown ();
406 }
407 return GNUNET_OK;
408}
409
410static void
411short_test (void *cls);
412
413static void
414short_test_cb (void *cls)
415{
416 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
417 unsigned int peer_nr;
418 char *payload;
419
420 peer_nr = get_peer_nr_from_tc (tc_h);
421
422 LOG (GNUNET_ERROR_TYPE_DEBUG,
423 "short_test_cb %u/%u for peer %u and handle %p\n",
424 (unsigned int) num_sent_short[peer_nr],
425 (unsigned int) num_received_short[peer_nr],
426 peer_nr,
427 tc_h);
428 payload = make_payload (SHORT_MESSAGE_SIZE);
429 num_sent_short[peer_nr]++;
430 GNUNET_TRANSPORT_TESTING_transport_communicator_send (tc_h,
431 (burst_packets_short ==
432 num_sent_short[peer_nr])
433 ? NULL
434 : &short_test,
435 cls,
436 payload,
437 SHORT_MESSAGE_SIZE);
438 GNUNET_free (payload);
439 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
440 GNUNET_TIME_relative_multiply (
441 GNUNET_TIME_UNIT_SECONDS,
442 TIMEOUT_MULTIPLIER));
443}
444
445static void
446short_test (void *cls)
447{
448 GNUNET_SCHEDULER_add_delayed (delay_short,
449 &short_test_cb,
450 cls);
451}
452
453static void
454size_test (void *cls)
455{
456 unsigned int peer_nr;
457 char *payload;
458 size_t max_size = 64000;
459 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
460
461 peer_nr = get_peer_nr_from_tc (tc_h);
462 LOG (GNUNET_ERROR_TYPE_DEBUG,
463 "size_test_cb %u\n",
464 (unsigned int) num_sent_size[peer_nr]);
465 GNUNET_assert (TP_SIZE_CHECK == phase[peer_nr]);
466 if (LONG_MESSAGE_SIZE != long_message_size)
467 max_size = long_message_size;
468 if (ack[peer_nr] + 10 > max_size)
469 return; /* Leave some room for our protocol, so not 2^16 exactly */
470 ack[peer_nr] += 10;
471 payload = make_payload (ack[peer_nr]);
472 num_sent_size[peer_nr]++;
473 GNUNET_TRANSPORT_TESTING_transport_communicator_send (tc_h,
474 (ack[peer_nr] <
475 max_size)
476 ? &size_test
477 : NULL,
478 cls,
479 payload,
480 ack[peer_nr]);
481 GNUNET_free (payload);
482 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
483 GNUNET_TIME_relative_multiply (
484 GNUNET_TIME_UNIT_SECONDS,
485 TIMEOUT_MULTIPLIER));
486}
487
488static void
489long_test (void *cls);
490
491static void
492long_test_cb (void *cls)
493{
494 unsigned int peer_nr;
495 char *payload;
496 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
497
498 peer_nr = get_peer_nr_from_tc (tc_h);
499
500 LOG (GNUNET_ERROR_TYPE_DEBUG,
501 "long_test_cb %u/%u\n",
502 (unsigned int) num_sent_long[peer_nr],
503 (unsigned int) num_received_long[peer_nr]);
504 payload = make_payload (long_message_size);
505 num_sent_long[peer_nr]++;
506 GNUNET_TRANSPORT_TESTING_transport_communicator_send (tc_h,
507 (burst_packets_long ==
508 num_sent_long[peer_nr])
509 ? NULL
510 : &long_test,
511 cls,
512 payload,
513 long_message_size);
514 GNUNET_free (payload);
515 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
516 GNUNET_TIME_relative_multiply (
517 GNUNET_TIME_UNIT_SECONDS,
518 TIMEOUT_MULTIPLIER));
519}
520
521
522static void
523long_test (void *cls)
524{
525 GNUNET_SCHEDULER_add_delayed (delay_long,
526 &long_test_cb,
527 cls);
528}
529
530static void
531choose_phase (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
532{
533 unsigned int peer_nr;
534
535 peer_nr = get_peer_nr_from_tc (tc_h);
536
537 if (GNUNET_YES == phase_short[peer_nr])
538 {
539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
540 "Choose phase short with peer %u and Handle %p\n",
541 peer_nr,
542 tc_h);
543 phase[peer_nr] = TP_BURST_SHORT;
544 start_short[peer_nr] = GNUNET_TIME_absolute_get ();
545 short_test (tc_h);
546 }
547 else if (GNUNET_YES == phase_long[peer_nr])
548 {
549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
550 "Choose phase long with peer %u\n",
551 peer_nr);
552 phase[peer_nr] = TP_BURST_LONG;
553 start_long[peer_nr] = GNUNET_TIME_absolute_get ();
554 long_test (tc_h);
555 }
556 else if (GNUNET_YES == phase_size[peer_nr])
557 {
558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
559 "Choose phase size\n");
560 phase[peer_nr] = TP_SIZE_CHECK;
561 size_test (tc_h);
562 }
563 else
564 {
565 if ((0 == strcmp ("udp", communicator_name)) && ((0 == strcmp ("rekey",
566 test_name))
567 ||(0 == strcmp (
568 "backchannel",
569 test_name))) )
570 {
571 if (NULL != box_stats[peer_nr])
572 GNUNET_STATISTICS_get_cancel (box_stats[peer_nr]);
573 box_stats[peer_nr] = GNUNET_STATISTICS_get (stats[1],
574 "C-UDP",
575 "# messages decrypted with BOX",
576 process_statistics_box_done,
577 &process_statistics,
578 tc_h);
579 if (NULL != rekey_stats[peer_nr])
580 GNUNET_STATISTICS_get_cancel (rekey_stats[peer_nr]);
581 rekey_stats[peer_nr] = GNUNET_STATISTICS_get (stats[0],
582 "C-UDP",
583 "# rekeying successful",
584 process_statistics_rekey_done,
585 &process_statistics,
586 tc_h);
587 }
588 else
589 {
590 if ((GNUNET_NO == bidirect)|| (((PEER_A == peer_nr) &&
591 finished[PEER_B]) || ((PEER_B ==
592 peer_nr) &&
593 finished
594 [PEER_A])))
595 {
596 LOG (GNUNET_ERROR_TYPE_DEBUG,
597 "Finished\n");
598 GNUNET_SCHEDULER_shutdown ();
599 }
600 finished[peer_nr] = GNUNET_YES;
601 }
602 }
603}
604
605static void finish_phase_long (unsigned int peer_nr)
606{
607 static struct GNUNET_TIME_Relative duration;
608
609 duration = GNUNET_TIME_absolute_get_duration (start_long[peer_nr]);
610 LOG (GNUNET_ERROR_TYPE_MESSAGE,
611 "Long size packet test for peer %u done.\n",
612 peer_nr);
613 char *goodput = GNUNET_STRINGS_byte_size_fancy (
614 (long_message_size * num_received_long[peer_nr] * 1000 * 1000)
615 / duration.
616 rel_value_us);
617
618 LOG (GNUNET_ERROR_TYPE_MESSAGE,
619 "%lu/%lu packets in %llu us (%s/s) -- avg latency: %llu us\n",
620 (unsigned long) num_received_long[peer_nr],
621 (unsigned long) num_sent_long[peer_nr],
622 (unsigned long long) duration.rel_value_us,
623 goodput,
624 (unsigned long long) avg_latency[peer_nr]);
625 GNUNET_free (goodput);
626 ack[peer_nr] = 0;
627 // phase = TP_SIZE_CHECK;
628 // num_received = 0;
629 // num_sent_long = 0;
630 avg_latency[peer_nr] = 0;
631 // size_test (NULL);
632 phase_long[peer_nr] = GNUNET_NO;
633 choose_phase (get_tc_h (peer_nr));
634}
635
636static void
637finish_phase_short (unsigned int peer_nr)
638{
639 static struct GNUNET_TIME_Relative duration;
640
641 duration = GNUNET_TIME_absolute_get_duration (start_short[peer_nr]);
642 LOG (GNUNET_ERROR_TYPE_MESSAGE,
643 "Short size packet test for peer %u done.\n",
644 peer_nr);
645 char *goodput = GNUNET_STRINGS_byte_size_fancy (
646 (SHORT_MESSAGE_SIZE * num_received_short[peer_nr] * 1000 * 1000)
647 / duration.rel_value_us);
648 LOG (GNUNET_ERROR_TYPE_MESSAGE,
649 "%lu/%lu packets in %llu us (%s/s) -- avg latency: %llu us\n",
650 (unsigned long) num_received_short[peer_nr],
651 (unsigned long) num_sent_short[peer_nr],
652 (unsigned long long) duration.rel_value_us,
653 goodput,
654 (unsigned long long) avg_latency[peer_nr]);
655 GNUNET_free (goodput);
656 // start_long = GNUNET_TIME_absolute_get ();
657 // phase = TP_BURST_LONG;
658 // num_sent_short = 0;
659 avg_latency[peer_nr] = 0;
660 // num_received = 0;
661 phase_short[peer_nr] = GNUNET_NO;
662 choose_phase (get_tc_h (peer_nr));
663 // long_test (NULL);
664}
665
666static void
667latency_timeout (void *cls)
668{
669
670 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
671 unsigned int peer_nr;
672 size_t num_sent = 0;
673 size_t num_received = 0;
674
675 peer_nr = get_peer_nr_from_tc (tc_h);
676 to_task[peer_nr] = NULL;
677
678 switch (phase[peer_nr])
679 {
680 case TP_INIT:
681 GNUNET_assert (0);
682 break;
683 case TP_BURST_SHORT:
684 num_sent = num_sent_short[peer_nr];
685 num_received = num_received_short[peer_nr];
686 if ((num_sent_short[peer_nr] == burst_packets_short) &&
687 (num_received_short[peer_nr] >
688 burst_packets_short
689 / 100
690 *
691 allowed_packet_loss_short) )
692 {
693 finish_phase_short (peer_nr);
694 to_task[peer_nr] = GNUNET_SCHEDULER_add_at (timeout[peer_nr],
695 &latency_timeout,
696 cls);
697 return;
698 }
699 break;
700 case TP_BURST_LONG:
701 num_sent = num_sent_long[peer_nr];
702 num_received = num_received_long[peer_nr];
703 if ((num_sent_long[peer_nr] == burst_packets_long) &&
704 (num_received_long[peer_nr] >
705 burst_packets_long
706 / 100
707 *
708 allowed_packet_loss_long) )
709 {
710 finish_phase_long (peer_nr);
711 to_task[peer_nr] = GNUNET_SCHEDULER_add_at (timeout[peer_nr],
712 &latency_timeout,
713 cls);
714 return;
715 }
716 break;
717 case TP_SIZE_CHECK:
718 num_sent = num_sent_size[peer_nr];
719 num_received = num_received_size[peer_nr];
720 break;
721 }
722 if (GNUNET_TIME_absolute_get_remaining (timeout[peer_nr]).rel_value_us > 0)
723 {
724 to_task[peer_nr] = GNUNET_SCHEDULER_add_at (timeout[peer_nr],
725 &latency_timeout,
726 cls);
727 return;
728 }
729 LOG (GNUNET_ERROR_TYPE_ERROR,
730 "Latency too high. Test failed. (Phase: %d. Sent: %lu, Received: %lu)\n",
731 phase[peer_nr], num_sent, num_received);
732 ret = 2;
733 GNUNET_SCHEDULER_shutdown ();
734}
735
736/**
737 * @brief Handle opening of queue
738 *
739 * Issues sending of test data
740 *
741 * Implements #GNUNET_TRANSPORT_TESTING_AddQueueCallback
742 *
743 * @param cls Closure
744 * @param tc_h Communicator handle
745 * @param tc_queue Handle to newly opened queue
746 */
747static void
748add_queue_cb (void *cls,
749 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
750 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *
751 tc_queue,
752 size_t mtu)
753{
754
755 unsigned int peer_nr;
756
757 peer_nr = get_peer_nr (cls, GNUNET_NO);
758 LOG (GNUNET_ERROR_TYPE_DEBUG,
759 "Handle %p add %u %u\n",
760 tc_h,
761 peer_nr,
762 get_peer_nr_from_tc (tc_h));
763 if ((GNUNET_NO == bidirect)&&(0 != strcmp ((char*) cls, cfg_peers_name[0])))
764 {
765 LOG (GNUNET_ERROR_TYPE_DEBUG,
766 "Queue available at receiving peer\n");
767 return; // TODO?
768 }
769 else if (TP_INIT != phase[peer_nr])
770 return;
771 LOG (GNUNET_ERROR_TYPE_DEBUG,
772 "Queue established, starting test...\n");
773 if (UINT32_MAX != mtu) /* Message header overhead */
774 long_message_size = mtu - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
775 - sizeof(struct GNUNET_MessageHeader);
776 else
777 long_message_size = LONG_MESSAGE_SIZE;
778 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
779 GNUNET_TIME_relative_multiply (
780 GNUNET_TIME_UNIT_SECONDS,
781 TIMEOUT_MULTIPLIER));
782 GNUNET_assert (NULL == to_task[peer_nr]);
783 to_task[peer_nr] = GNUNET_SCHEDULER_add_delayed (
784 GNUNET_TIME_relative_multiply (
785 GNUNET_TIME_UNIT_SECONDS,
786 TIMEOUT_MULTIPLIER),
787 &latency_timeout,
788 tc_h);
789 choose_phase (tc_h);
790}
791
792
793static void
794update_avg_latency (const char *payload, unsigned int peer_nr)
795{
796 struct GNUNET_TIME_AbsoluteNBO *ts_n;
797 struct GNUNET_TIME_Absolute ts;
798 struct GNUNET_TIME_Relative latency;
799 size_t num_received = 0;
800
801 ts_n = (struct GNUNET_TIME_AbsoluteNBO *) payload;
802 ts = GNUNET_TIME_absolute_ntoh (*ts_n);
803 latency = GNUNET_TIME_absolute_get_duration (ts);
804
805 switch (phase[peer_nr])
806 {
807 case TP_INIT:
808 GNUNET_assert (0);
809 break;
810 case TP_BURST_SHORT:
811 num_received = num_received_short[peer_nr];
812 break;
813 case TP_BURST_LONG:
814 num_received = num_received_long[peer_nr];
815 break;
816 case TP_SIZE_CHECK:
817 num_received = num_received_size[peer_nr];
818 break;
819 }
820 if (1 >= num_received)
821 avg_latency[peer_nr] = latency.rel_value_us;
822 else
823 avg_latency[peer_nr] = ((avg_latency[peer_nr] * (num_received - 1))
824 + latency.rel_value_us)
825 / num_received;
826 LOG (GNUNET_ERROR_TYPE_DEBUG,
827 "Latency of received packet by peer %u: %s with avg latency %lu\n",
828 peer_nr,
829 GNUNET_STRINGS_relative_time_to_string (latency,
830 GNUNET_YES),
831 avg_latency[peer_nr]);
832}
833
834
835
836
837static void
838load_phase_config ()
839{
840
841 phase_short[0] = GNUNET_CONFIGURATION_get_value_yesno (cfg_peers[0],
842 TEST_SECTION,
843 "PHASE_SHORT");
844 if (GNUNET_SYSERR == phase_short[0])
845 phase_short[0] = GNUNET_YES;
846
847 phase_short[1] = phase_short[0];
848
849 phase_long[0] = GNUNET_CONFIGURATION_get_value_yesno (cfg_peers[0],
850 TEST_SECTION,
851 "PHASE_LONG");
852
853 if (GNUNET_SYSERR == phase_long[0])
854 phase_long[0] = GNUNET_YES;
855
856 phase_long[1] = phase_long[0];
857
858 phase_size[0] = GNUNET_CONFIGURATION_get_value_yesno (cfg_peers[0],
859 TEST_SECTION,
860 "PHASE_SIZE");
861
862 if (GNUNET_SYSERR == phase_size[0])
863 phase_size[0] = GNUNET_YES;
864
865 phase_size[1] = phase_size[0];
866}
867
868
869
870/**
871 * @brief Handle an incoming message
872 *
873 * Implements #GNUNET_TRANSPORT_TESTING_IncomingMessageCallback
874
875 * @param cls Closure
876 * @param tc_h Handle to the receiving communicator
877 * @param msg Received message
878 */
879static void
880incoming_message_cb (
881 void *cls,
882 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
883 const char *payload,
884 size_t payload_len)
885{
886 unsigned int peer_nr;
887
888
889 peer_nr = get_peer_nr (cls, GNUNET_YES);
890
891 if ((GNUNET_NO == bidirect)&&(0 != strcmp ((char*) cls,
892 cfg_peers_name[NUM_PEERS - 1])))
893 {
894 LOG (GNUNET_ERROR_TYPE_WARNING,
895 "unexpected receiver...\n");
896 return;
897 }
898 /* Reset timeout */
899 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
900 GNUNET_TIME_relative_multiply (
901 GNUNET_TIME_UNIT_SECONDS,
902 TIMEOUT_MULTIPLIER));
903 switch (phase[peer_nr])
904 {
905 case TP_INIT:
906 GNUNET_break (0);
907 break;
908 case TP_BURST_SHORT:
909 {
910 GNUNET_assert (SHORT_MESSAGE_SIZE == payload_len);
911 num_received_short[peer_nr]++;
912
913 update_avg_latency (payload, peer_nr);
914 if ((num_sent_short[peer_nr] == burst_packets_short) &&
915 (num_received_short[peer_nr] ==
916 burst_packets_short))
917 {
918 finish_phase_short (peer_nr);
919 }
920 break;
921 }
922 case TP_BURST_LONG:
923 {
924 if (long_message_size != payload_len)
925 {
926 LOG (GNUNET_ERROR_TYPE_WARNING,
927 "Ignoring packet with wrong length\n");
928 return; // Ignore
929 }
930 num_received_long[peer_nr]++;
931
932 update_avg_latency (payload, peer_nr);
933 if ((num_sent_long[peer_nr] == burst_packets_long) &&
934 (num_received_long[peer_nr] >
935 burst_packets_long))
936 {
937 finish_phase_long (peer_nr);
938 }
939 break;
940 }
941 case TP_SIZE_CHECK:
942 {
943 size_t max_size = 64000;
944
945 GNUNET_assert (TP_SIZE_CHECK == phase[peer_nr]);
946 if (LONG_MESSAGE_SIZE != long_message_size)
947 max_size = long_message_size;
948 num_received_size[peer_nr]++;
949 update_avg_latency (payload, peer_nr);
950 if ((GNUNET_YES == phase_size[peer_nr]) && (num_received_size[peer_nr] >=
951 (max_size) / 10) )
952 {
953 LOG (GNUNET_ERROR_TYPE_MESSAGE,
954 "Size packet test for peer %u done.\n",
955 peer_nr);
956 LOG (GNUNET_ERROR_TYPE_MESSAGE,
957 "%lu/%lu packets -- avg latency: %llu us\n",
958 (unsigned long) num_received_size[peer_nr],
959 (unsigned long) num_sent_size[peer_nr],
960 (unsigned long long) avg_latency[peer_nr]);
961 iterations_left[peer_nr]--;
962 phase_size[peer_nr] = GNUNET_NO;
963 if (0 != iterations_left[peer_nr])
964 {
965 // start_short = GNUNET_TIME_absolute_get ();
966 // phase = TP_BURST_SHORT;
967 num_received_size[peer_nr] = 0;
968 num_sent_size[peer_nr] = 0;
969 avg_latency[peer_nr] = 0;
970 num_sent_short[peer_nr] = 0;
971 num_sent_long[peer_nr] = 0;
972 num_received_short[peer_nr] = 0;
973 num_received_long[peer_nr] = 0;
974 // short_test (NULL);
975 if (((PEER_A == peer_nr) && finished[PEER_B]) || ((PEER_B ==
976 peer_nr) &&
977 finished[PEER_A]))
978 {
979 load_phase_config ();
980 }
981 }
982 choose_phase (get_tc_h (peer_nr));
983 }
984 break;
985 }
986 }
987}
988
989
990static void
991do_shutdown (void *cls)
992{
993 LOG (GNUNET_ERROR_TYPE_DEBUG,
994 "shutting down test.\n");
995
996 for (unsigned int i = 0; i < NUM_PEERS; i++)
997 {
998 if (NULL != box_stats[i])
999 {
1000 GNUNET_STATISTICS_get_cancel (box_stats[i]);
1001 box_stats[i] = NULL;
1002 }
1003 if (NULL != rekey_stats[i])
1004 {
1005 GNUNET_STATISTICS_get_cancel (rekey_stats[i]);
1006 rekey_stats[i] = NULL;
1007 }
1008 if (NULL != to_task[i])
1009 {
1010 GNUNET_SCHEDULER_cancel (to_task[i]);
1011 to_task[i] = NULL;
1012 }
1013 GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (tc_hs[i]);
1014 GNUNET_STATISTICS_destroy (stats[i], GNUNET_NO);
1015 }
1016}
1017
1018
1019
1020/**
1021 * @brief Main function called by the scheduler
1022 *
1023 * @param cls Closure - Handle to confiation
1024 */
1025static void
1026run (void *cls)
1027{
1028 ret = 0;
1029 // num_received = 0;
1030 // num_sent = 0;
1031 for (unsigned int i = 0; i < NUM_PEERS; i++)
1032 {
1033 tc_hs[i] = GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
1034 "transport",
1035 communicator_binary,
1036 cfg_peers_name[i],
1037 &peer_id[i],
1038 &communicator_available_cb,
1039 &add_address_cb,
1040 &queue_create_reply_cb,
1041 &add_queue_cb,
1042 &incoming_message_cb,
1043 &handle_backchannel_cb,
1044 cfg_peers_name[i]); /* cls */
1045
1046 if ((0 == strcmp ("udp", communicator_name)) && ((0 == strcmp ("rekey",
1047 test_name))||
1048 (0 == strcmp (
1049 "backchannel",
1050 test_name))) )
1051 {
1052 stats[i] = GNUNET_STATISTICS_create ("C-UDP",
1053 cfg_peers[i]);
1054 }
1055 else if ((0 == strcmp ("bidirect", test_name)))
1056 {
1057 bidirect = GNUNET_YES;
1058 }
1059 }
1060 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1061 NULL);
1062}
1063
1064int
1065main (int argc,
1066 char *const *argv)
1067{
1068 struct GNUNET_CRYPTO_EddsaPrivateKey *private_key;
1069 char *test_mode;
1070 char *cfg_peer;
1071
1072 iterations_left[0] = TOTAL_ITERATIONS;
1073 iterations_left[1] = TOTAL_ITERATIONS;
1074 phase[0] = TP_INIT;
1075 phase[1] = TP_INIT;
1076 ret = 1;
1077 test_name = GNUNET_TESTING_get_testname_from_underscore (argv[0]);
1078 communicator_name = strchr (test_name, '-');
1079 communicator_name[0] = '\0';
1080 communicator_name++;
1081 test_mode = test_name;
1082
1083 GNUNET_asprintf (&communicator_binary,
1084 "gnunet-communicator-%s",
1085 communicator_name);
1086
1087 if (GNUNET_OK !=
1088 GNUNET_log_setup ("test_communicator_basic",
1089 "DEBUG",
1090 NULL))
1091 {
1092 fprintf (stderr, "Unable to setup log\n");
1093 GNUNET_break (0);
1094 return 2;
1095 }
1096 for (unsigned int i = 0; i < NUM_PEERS; i++)
1097 {
1098 GNUNET_asprintf ((&cfg_peer),
1099 "test_communicator_%s_%s_peer%u.conf",
1100 communicator_name, test_mode, i + 1);
1101 cfg_peers_name[i] = cfg_peer;
1102 cfg_peers[i] = GNUNET_CONFIGURATION_create ();
1103 if (GNUNET_YES ==
1104 GNUNET_DISK_file_test (cfg_peers_name[i]))
1105 {
1106 if (GNUNET_SYSERR ==
1107 GNUNET_CONFIGURATION_load (cfg_peers[i],
1108 cfg_peers_name[i]))
1109 {
1110 fprintf (stderr,
1111 "Malformed configuration file `%s', exiting ...\n",
1112 cfg_peers_name[i]);
1113 return 1;
1114 }
1115 }
1116 else
1117 {
1118 if (GNUNET_SYSERR ==
1119 GNUNET_CONFIGURATION_load (cfg_peers[i],
1120 NULL))
1121 {
1122 fprintf (stderr,
1123 "Configuration file %s does not exist, exiting ...\n",
1124 cfg_peers_name[i]);
1125 return 1;
1126 }
1127 }
1128 private_key =
1129 GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg_peers[i]);
1130 if (NULL == private_key)
1131 {
1132 LOG (GNUNET_ERROR_TYPE_ERROR,
1133 "Unable to get peer ID\n");
1134 return 1;
1135 }
1136 GNUNET_CRYPTO_eddsa_key_get_public (private_key,
1137 &peer_id[i].public_key);
1138 GNUNET_free (private_key);
1139 LOG (GNUNET_ERROR_TYPE_INFO,
1140 "Identity of peer %u is %s\n",
1141 i,
1142 GNUNET_i2s_full (&peer_id[i]));
1143 }
1144 if (GNUNET_OK !=
1145 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1146 TEST_SECTION,
1147 "ALLOWED_PACKET_LOSS_SHORT",
1148 &allowed_packet_loss_short))
1149 allowed_packet_loss_short = ALLOWED_PACKET_LOSS;
1150 if (GNUNET_OK !=
1151 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1152 TEST_SECTION,
1153 "ALLOWED_PACKET_LOSS_LONG",
1154 &allowed_packet_loss_long))
1155 allowed_packet_loss_long = ALLOWED_PACKET_LOSS;
1156 if (GNUNET_OK !=
1157 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1158 TEST_SECTION,
1159 "BURST_PACKETS_SHORT",
1160 &burst_packets_short))
1161 burst_packets_short = BURST_PACKETS;
1162 if (GNUNET_OK !=
1163 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1164 TEST_SECTION,
1165 "BURST_ÃœACKETS_LONG",
1166 &burst_packets_long))
1167 burst_packets_long = BURST_PACKETS;
1168 if (GNUNET_OK !=
1169 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1170 TEST_SECTION,
1171 "DELAY_SHORT",
1172 &delay_short_value))
1173 delay_short = DELAY;
1174 else
1175 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,
1176 delay_short_value);
1177 if (GNUNET_OK !=
1178 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1179 TEST_SECTION,
1180 "DELAY_SHORT",
1181 &delay_long_value))
1182 delay_long = DELAY;
1183 else
1184 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,
1185 delay_long_value);
1186 load_phase_config ();
1187 LOG (GNUNET_ERROR_TYPE_MESSAGE, "Starting test...\n");
1188 LOG (GNUNET_ERROR_TYPE_DEBUG,
1189 "argv[0]: %s\n",
1190 argv[0]);
1191 LOG (GNUNET_ERROR_TYPE_DEBUG,
1192 "test_name: %s\n",
1193 test_name);
1194 LOG (GNUNET_ERROR_TYPE_DEBUG,
1195 "communicator_name: %s\n",
1196 communicator_name);
1197 LOG (GNUNET_ERROR_TYPE_DEBUG,
1198 "communicator_binary: %s\n",
1199 communicator_binary);
1200 GNUNET_SCHEDULER_run (&run,
1201 NULL);
1202 return ret;
1203}
diff --git a/src/transport/test_communicator_tcp_basic_peer1.conf b/src/transport/test_communicator_tcp_basic_peer1.conf
deleted file mode 100644
index dbc227ac6..000000000
--- a/src/transport/test_communicator_tcp_basic_peer1.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[test-setup]
4#PHASE_LONG=NO
5#PHASE_SIZE=NO
6#BURST_PACKETS_SHORT=1
7
8[PATHS]
9GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
10
11[PEER]
12PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
13
14[transport-tcp]
15PORT = 52400
16
17[transport-udp]
18PORT = 52401
19
20[transport]
21PORT = 60000
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
23
24[nat]
25UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
26
27[peerstore]
28UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
29
30[statistics]
31PORT = 22461
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
36
37[communicator-tcp]
38#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
39#PREFIX = valgrind --leak-check=full --track-origins=yes
40BINDTO = 60002
41DISABLE_V6 = YES
42
43[communicator-udp]
44BINDTO = 60002
45
46[resolver]
47PORT = 62089
48UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
diff --git a/src/transport/test_communicator_tcp_basic_peer2.conf b/src/transport/test_communicator_tcp_basic_peer2.conf
deleted file mode 100644
index b73157f0d..000000000
--- a/src/transport/test_communicator_tcp_basic_peer2.conf
+++ /dev/null
@@ -1,44 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[communicator-unix]
31UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
32
33[communicator-tcp]
34#PREFIX = xterm -geometry 100x85 -T peer2 -e gdb --args
35#PREFIX = valgrind --leak-check=full --track-origins=yes
36BINDTO = 60003
37DISABLE_V6 = YES
38
39[communicator-udp]
40BINDTO = 60003
41
42[resolver]
43PORT = 62090
44UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
diff --git a/src/transport/test_communicator_tcp_bidirect_peer1.conf b/src/transport/test_communicator_tcp_bidirect_peer1.conf
deleted file mode 100644
index dbc227ac6..000000000
--- a/src/transport/test_communicator_tcp_bidirect_peer1.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[test-setup]
4#PHASE_LONG=NO
5#PHASE_SIZE=NO
6#BURST_PACKETS_SHORT=1
7
8[PATHS]
9GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
10
11[PEER]
12PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
13
14[transport-tcp]
15PORT = 52400
16
17[transport-udp]
18PORT = 52401
19
20[transport]
21PORT = 60000
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
23
24[nat]
25UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
26
27[peerstore]
28UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
29
30[statistics]
31PORT = 22461
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
36
37[communicator-tcp]
38#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
39#PREFIX = valgrind --leak-check=full --track-origins=yes
40BINDTO = 60002
41DISABLE_V6 = YES
42
43[communicator-udp]
44BINDTO = 60002
45
46[resolver]
47PORT = 62089
48UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
diff --git a/src/transport/test_communicator_tcp_bidirect_peer2.conf b/src/transport/test_communicator_tcp_bidirect_peer2.conf
deleted file mode 100644
index b73157f0d..000000000
--- a/src/transport/test_communicator_tcp_bidirect_peer2.conf
+++ /dev/null
@@ -1,44 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[communicator-unix]
31UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
32
33[communicator-tcp]
34#PREFIX = xterm -geometry 100x85 -T peer2 -e gdb --args
35#PREFIX = valgrind --leak-check=full --track-origins=yes
36BINDTO = 60003
37DISABLE_V6 = YES
38
39[communicator-udp]
40BINDTO = 60003
41
42[resolver]
43PORT = 62090
44UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
diff --git a/src/transport/test_communicator_tcp_rekey_peer1.conf b/src/transport/test_communicator_tcp_rekey_peer1.conf
deleted file mode 100644
index 82fbf353a..000000000
--- a/src/transport/test_communicator_tcp_rekey_peer1.conf
+++ /dev/null
@@ -1,45 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
8
9[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52401
14
15[transport]
16PORT = 60000
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
18
19[nat]
20UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
21ENABLE_IPSCAN = YES
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
25
26[statistics]
27PORT = 22461
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
29
30[resolver]
31PORT = 62089
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
36
37[communicator-tcp]
38#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
39#PREFIX = valgrind --leak-check=full --track-origins=yes
40BINDTO = 60002
41DISABLE_V6 = YES
42REKEY_INTERVAL = 100ms
43
44[communicator-udp]
45BINDTO = 60002
diff --git a/src/transport/test_communicator_tcp_rekey_peer2.conf b/src/transport/test_communicator_tcp_rekey_peer2.conf
deleted file mode 100644
index 086a996ae..000000000
--- a/src/transport/test_communicator_tcp_rekey_peer2.conf
+++ /dev/null
@@ -1,45 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[resolver]
31PORT = 62090
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
36
37[communicator-tcp]
38#PREFIX = xterm -geometry 100x85 -T peer2 -e gdb --args
39#PREFIX = valgrind --leak-check=full --track-origins=yes
40BINDTO = 60003
41DISABLE_V6 = YES
42REKEY_INTERVAL = 100ms
43
44[communicator-udp]
45BINDTO = 60003
diff --git a/src/transport/test_communicator_udp_backchannel_peer1.conf b/src/transport/test_communicator_udp_backchannel_peer1.conf
deleted file mode 100644
index 59e6d68e3..000000000
--- a/src/transport/test_communicator_udp_backchannel_peer1.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
8
9[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52401
14
15[transport]
16PORT = 60000
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
18
19[nat]
20UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
21ENABLE_IPSCAN = YES
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
25
26[statistics]
27PORT = 22461
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
29
30[resolver]
31PORT = 62089
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
36
37[communicator-tcp]
38BINDTO = 60002
39DISABLE_V6 = YES
40
41[communicator-udp]
42#PREFIX = valgrind --leak-check=full --track-origins=yes
43BINDTO = 60002
44DISABLE_V6 = YES
45MAX_QUEUE_LENGTH=5000
46
47[communicator-test]
48BACKCHANNEL_ENABLED = YES
diff --git a/src/transport/test_communicator_udp_backchannel_peer2.conf b/src/transport/test_communicator_udp_backchannel_peer2.conf
deleted file mode 100644
index 3abf7999b..000000000
--- a/src/transport/test_communicator_udp_backchannel_peer2.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[resolver]
31PORT = 62090
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
36
37[communicator-tcp]
38BINDTO = 60003
39DISABLE_V6 = YES
40
41[communicator-udp]
42#PREFIX = valgrind --leak-check=full --track-origins=yes
43BINDTO = 60003
44DISABLE_V6 = YES
45MAX_QUEUE_LENGTH=5000
46
47[communicator-test]
48BACKCHANNEL_ENABLED = YES
diff --git a/src/transport/test_communicator_udp_basic_peer1.conf b/src/transport/test_communicator_udp_basic_peer1.conf
deleted file mode 100644
index c6ff024ee..000000000
--- a/src/transport/test_communicator_udp_basic_peer1.conf
+++ /dev/null
@@ -1,38 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
8
9[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52401
14
15[transport]
16#PORT = 60000
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
18
19[nat]
20UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
21ENABLE_IPSCAN = YES
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
25
26[statistics]
27PORT = 22461
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
29
30[resolver]
31PORT = 62089
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
33
34[communicator-udp]
35#PREFIX = valgrind --leak-check=full --track-origins=yes
36BINDTO = 60002
37DISABLE_V6 = YES
38MAX_QUEUE_LENGTH=5000
diff --git a/src/transport/test_communicator_udp_basic_peer2.conf b/src/transport/test_communicator_udp_basic_peer2.conf
deleted file mode 100644
index b353b03e9..000000000
--- a/src/transport/test_communicator_udp_basic_peer2.conf
+++ /dev/null
@@ -1,39 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52402
15
16[transport]
17#PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23
24[peerstore]
25UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
26
27[statistics]
28PORT = 22462
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
30
31[resolver]
32PORT = 62090
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
34
35[communicator-udp]
36#PREFIX = valgrind --leak-check=full --track-origins=yes
37BINDTO = 60003
38DISABLE_V6 = YES
39MAX_QUEUE_LENGTH=5000
diff --git a/src/transport/test_communicator_udp_rekey_peer1.conf b/src/transport/test_communicator_udp_rekey_peer1.conf
deleted file mode 100644
index 6bfeafe33..000000000
--- a/src/transport/test_communicator_udp_rekey_peer1.conf
+++ /dev/null
@@ -1,51 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
8
9[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52401
14
15[transport]
16PORT = 60000
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
18
19[nat]
20UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
21ENABLE_IPSCAN = YES
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
25
26[statistics]
27PORT = 22461
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
29
30[resolver]
31PORT = 62089
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_1.sock
36
37[communicator-tcp]
38BINDTO = 60002
39DISABLE_V6 = YES
40REKEY_INTERVAL = 100ms
41
42[communicator-udp]
43#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
44#PREFIX = valgrind --leak-check=full --track-origins=yes
45BINDTO = 60002
46DISABLE_V6 = YES
47MAX_QUEUE_LENGTH=5000
48REKEY_MAX_BYTES=9MiB
49
50[communicator-test]
51BACKCHANNEL_ENABLED = YES
diff --git a/src/transport/test_communicator_udp_rekey_peer2.conf b/src/transport/test_communicator_udp_rekey_peer2.conf
deleted file mode 100644
index 474ca0c15..000000000
--- a/src/transport/test_communicator_udp_rekey_peer2.conf
+++ /dev/null
@@ -1,51 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[resolver]
31PORT = 62090
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
33
34[communicator-unix]
35UNIXPATH = $GNUNET_RUNTIME_DIR/test_gnunet-communicator-unix_2.sock
36
37[communicator-tcp]
38BINDTO = 60003
39DISABLE_V6 = YES
40REKEY_INTERVAL = 100ms
41
42[communicator-udp]
43#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
44#PREFIX = valgrind --leak-check=full --track-origins=yes
45BINDTO = 60003
46DISABLE_V6 = YES
47MAX_QUEUE_LENGTH=5000
48REKEY_MAX_BYTES=9MiB
49
50[communicator-test]
51BACKCHANNEL_ENABLED = YES
diff --git a/src/transport/test_communicator_unix_basic_peer1.conf b/src/transport/test_communicator_unix_basic_peer1.conf
deleted file mode 100644
index 13ba2d16b..000000000
--- a/src/transport/test_communicator_unix_basic_peer1.conf
+++ /dev/null
@@ -1,43 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-communicator-unix-1/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-1/private.key
8
9[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52401
14
15[transport]
16PORT = 60000
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
18
19[nat]
20UNIXPATH = $GNUNET_TMP/communicator-unix-1/nat.sock
21ENABLE_IPSCAN = YES
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
25
26[statistics]
27PORT = 22461
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
29
30[resolver]
31PORT = 62089
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
33
34[communicator-unix]
35#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
36#PREFIX = valgrind --leak-check=full --track-origins=yes
37UNIXPATH = $GNUNET_RUNTIME_DIR/communicator-unix-1.sock
38
39[communicator-tcp]
40BINDTO = 60002
41
42[communicator-udp]
43BINDTO = 60002
diff --git a/src/transport/test_communicator_unix_basic_peer2.conf b/src/transport/test_communicator_unix_basic_peer2.conf
deleted file mode 100644
index 727e844a7..000000000
--- a/src/transport/test_communicator_unix_basic_peer2.conf
+++ /dev/null
@@ -1,43 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
5
6[PEER]
7PRIVATE_KEY = $GNUNET_TMP/test-communicator-unix-2/private.key
8
9
10[transport-tcp]
11PORT = 52400
12
13[transport-udp]
14PORT = 52401
15
16[transport]
17PORT = 60001
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
19
20[nat]
21UNIXPATH = $GNUNET_TMP/communicator-unix-2/nat.sock
22
23[peerstore]
24UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
25
26[statistics]
27PORT = 22462
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
29
30[resolver]
31PORT = 62090
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
33
34[communicator-unix]
35#PREFIX = xterm -geometry 100x85 -T peer2 -e gdb --args
36#PREFIX = valgrind --leak-check=full --track-origins=yes
37UNIXPATH = $GNUNET_RUNTIME_DIR/communicator-unix-2.sock
38
39[communicator-tcp]
40BINDTO = 60003
41
42[communicator-udp]
43BINDTO = 60003
diff --git a/src/transport/test_delay b/src/transport/test_delay
deleted file mode 100755
index 5f82b65fb..000000000
--- a/src/transport/test_delay
+++ /dev/null
@@ -1,19 +0,0 @@
1#!/bin/sh
2
3TEMP=$(getopt t: "$*")
4
5if [ $? != 0 ] ; then
6 exit 1
7fi
8
9eval set -- "$TEMP"
10
11while true ; do
12 case "$1" in
13 (-t) sleep "$2" ; shift 2 ;;
14 (--) shift ; break ;;
15 (*) echo "Error parsing getopt output" ; exit 1 ;;
16 esac
17done
18echo "exec $@"
19exec "$@"
diff --git a/src/transport/test_http_common.c b/src/transport/test_http_common.c
deleted file mode 100644
index fe6e4faa3..000000000
--- a/src/transport/test_http_common.c
+++ /dev/null
@@ -1,266 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_http_common.c
22 * @brief base test case for common http functionality
23 */
24#include "platform.h"
25#include "gnunet_transport_service.h"
26#include "transport-testing.h"
27#include "plugin_transport_http_common.h"
28
29
30static void
31clean (struct SplittedHTTPAddress *addr)
32{
33 if (NULL == addr)
34 return;
35 GNUNET_free (addr->host);
36 GNUNET_free (addr->path);
37 GNUNET_free (addr->protocol);
38 GNUNET_free (addr);
39}
40
41
42static int
43check (struct SplittedHTTPAddress *addr,
44 const char *protocol,
45 const char *host,
46 int port,
47 const char *path)
48{
49 if (NULL == addr)
50 return GNUNET_NO;
51 if (((NULL == addr->protocol) && (NULL != protocol)) ||
52 ((NULL != addr->protocol) && (NULL == protocol)))
53 {
54 GNUNET_break (0);
55 return GNUNET_NO;
56 }
57 else if ((NULL != addr->protocol) && (NULL != protocol))
58 {
59 if (0 != strcmp (addr->protocol, protocol))
60 {
61 GNUNET_break (0);
62 return GNUNET_NO;
63 }
64 }
65
66 if (((NULL == addr->host) && (NULL != host)) ||
67 ((NULL != addr->host) && (NULL == host)))
68 {
69 GNUNET_break (0);
70 return GNUNET_NO;
71 }
72 else if ((NULL != addr->host) && (NULL != host))
73 {
74 if (0 != strcmp (addr->host, host))
75 {
76 GNUNET_break (0);
77 return GNUNET_NO;
78 }
79 }
80
81 if (((NULL == addr->path) && (NULL != path)) ||
82 ((NULL != addr->path) && (NULL == path)))
83 {
84 GNUNET_break (0);
85 return GNUNET_NO;
86 }
87 else if ((NULL != addr->path) && (NULL != path))
88 {
89 if (0 != strcmp (addr->path, path))
90 {
91 GNUNET_break (0);
92 return GNUNET_NO;
93 }
94 }
95
96 if ((addr->port != port))
97 {
98 GNUNET_break (0);
99 return GNUNET_NO;
100 }
101 return GNUNET_OK;
102}
103
104
105static int
106check_pass (const char *src,
107 const char *protocol,
108 const char *host,
109 int port,
110 const char *path)
111{
112 struct SplittedHTTPAddress *spa;
113
114 spa = http_split_address (src);
115 if (NULL == spa)
116 {
117 GNUNET_break (0);
118 return GNUNET_SYSERR;
119 }
120 if (GNUNET_OK != check (spa, protocol, host, port, path))
121 {
122 clean (spa);
123 GNUNET_break (0);
124 return GNUNET_SYSERR;
125 }
126 clean (spa);
127 return GNUNET_OK;
128}
129
130
131static int
132check_fail (const char *src)
133{
134 struct SplittedHTTPAddress *spa;
135
136 spa = http_split_address (src);
137 if (NULL != spa)
138 {
139 GNUNET_break (0);
140 clean (spa);
141 return GNUNET_SYSERR;
142 }
143 return GNUNET_OK;
144}
145
146
147static void
148test_pass_hostname ()
149{
150 check_pass ("http://test.local", "http", "test.local", HTTP_DEFAULT_PORT, "");
151 check_pass ("http://test.local/", "http", "test.local", HTTP_DEFAULT_PORT,
152 "/");
153 check_pass ("http://test.local/path", "http", "test.local", HTTP_DEFAULT_PORT,
154 "/path");
155 check_pass ("http://test.local/path/", "http", "test.local",
156 HTTP_DEFAULT_PORT, "/path/");
157 check_pass ("http://test.local/path/more", "http", "test.local",
158 HTTP_DEFAULT_PORT, "/path/more");
159 check_pass ("http://test.local:81", "http", "test.local", 81, "");
160 check_pass ("http://test.local:81/", "http", "test.local", 81, "/");
161 check_pass ("http://test.local:81/path", "http", "test.local", 81, "/path");
162 check_pass ("http://test.local:81/path/", "http", "test.local", 81, "/path/");
163 check_pass ("http://test.local:81/path/more", "http", "test.local", 81,
164 "/path/more");
165}
166
167
168static void
169test_pass_ipv4 ()
170{
171 check_pass ("http://127.0.0.1", "http", "127.0.0.1", HTTP_DEFAULT_PORT, "");
172 check_pass ("http://127.0.0.1/", "http", "127.0.0.1", HTTP_DEFAULT_PORT, "/");
173 check_pass ("http://127.0.0.1/path", "http", "127.0.0.1", HTTP_DEFAULT_PORT,
174 "/path");
175 check_pass ("http://127.0.0.1/path/", "http", "127.0.0.1", HTTP_DEFAULT_PORT,
176 "/path/");
177 check_pass ("http://127.0.0.1:81", "http", "127.0.0.1", 81, "");
178 check_pass ("http://127.0.0.1:81/", "http", "127.0.0.1", 81, "/");
179 check_pass ("http://127.0.0.1:81/path", "http", "127.0.0.1", 81, "/path");
180 check_pass ("http://127.0.0.1:81/path/", "http", "127.0.0.1", 81, "/path/");
181 check_pass ("http://127.0.0.1:81/path/more", "http", "127.0.0.1", 81,
182 "/path/more");
183}
184
185
186static void
187test_fail_ipv6 ()
188{
189 check_pass ("http://[::1]", "http", "[::1]", HTTP_DEFAULT_PORT, "");
190 check_pass ("http://[::1]/", "http", "[::1]", HTTP_DEFAULT_PORT, "/");
191 check_pass ("http://[::1]/path", "http", "[::1]", HTTP_DEFAULT_PORT, "/path");
192 check_pass ("http://[::1]/path/", "http", "[::1]", HTTP_DEFAULT_PORT,
193 "/path/");
194 check_pass ("http://[::1]:81", "http", "[::1]", 81, "");
195 check_pass ("http://[::1]:81/", "http", "[::1]", 81, "/");
196 check_pass ("http://[::1]:81/path", "http", "[::1]", 81, "/path");
197 check_pass ("http://[::1]:81/path/", "http", "[::1]", 81, "/path/");
198 check_pass ("http://[::1]:81/path/more", "http", "[::1]", 81, "/path/more");
199}
200
201
202static void
203test_fail ()
204{
205 if (GNUNET_SYSERR == check_fail (""))
206 GNUNET_break (0);
207 if (GNUNET_SYSERR == check_fail ("http"))
208 GNUNET_break (0);
209 if (GNUNET_SYSERR == check_fail ("://"))
210 GNUNET_break (0);
211 if (GNUNET_SYSERR == check_fail ("http://"))
212 GNUNET_break (0);
213 if (GNUNET_SYSERR == check_fail ("//localhost"))
214 GNUNET_break (0);
215 if (GNUNET_SYSERR == check_fail ("//:80"))
216 GNUNET_break (0);
217 if (GNUNET_SYSERR == check_fail ("//:80/"))
218 GNUNET_break (0);
219 if (GNUNET_SYSERR == check_fail ("//:80:"))
220 GNUNET_break (0);
221 if (GNUNET_SYSERR == check_fail ("http://localhost:a/"))
222 GNUNET_break (0);
223 if (GNUNET_SYSERR == check_fail ("http://127.0.0.1:a/"))
224 GNUNET_break (0);
225}
226
227
228int
229main (int argc, char *argv[])
230{
231 int ret = 0;
232 struct SplittedHTTPAddress *spa;
233
234 GNUNET_log_setup ("test", "DEBUG", NULL);
235 spa = http_split_address ("");
236 if (NULL != spa)
237 {
238 clean (spa);
239 spa = NULL;
240 GNUNET_break (0);
241 }
242
243 spa = http_split_address ("http://");
244 if (NULL != spa)
245 {
246 clean (spa);
247 GNUNET_break (0);
248 }
249
250 spa = http_split_address ("://");
251 if (NULL != spa)
252 {
253 clean (spa);
254 GNUNET_break (0);
255 }
256
257 test_pass_hostname ();
258 test_pass_ipv4 ();
259 test_fail_ipv6 ();
260 test_fail ();
261
262 return ret;
263}
264
265
266/* end of test_http_common.c */
diff --git a/src/transport/test_plugin_hostkey b/src/transport/test_plugin_hostkey
deleted file mode 100644
index e7b1ad012..000000000
--- a/src/transport/test_plugin_hostkey
+++ /dev/null
Binary files differ
diff --git a/src/transport/test_plugin_hostkey.ecc b/src/transport/test_plugin_hostkey.ecc
deleted file mode 100644
index 18641b798..000000000
--- a/src/transport/test_plugin_hostkey.ecc
+++ /dev/null
@@ -1 +0,0 @@
1‚”ˆÖ’ÛËy¢/HÒc ȃ§¿±;¼»f?¶@…~áJ \ No newline at end of file
diff --git a/src/transport/test_plugin_transport.c b/src/transport/test_plugin_transport.c
deleted file mode 100644
index 04687d845..000000000
--- a/src/transport/test_plugin_transport.c
+++ /dev/null
@@ -1,797 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_plugin_transport.c
22 * @brief testcase for transport_api.c
23 * @author Sailor Siraj
24 * @author Christian Grothoff
25 */
26
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_hello_lib.h"
30#include "gnunet_peerinfo_service.h"
31#include "gnunet_statistics_service.h"
32#include "gnunet_protocols.h"
33#include "gnunet_transport_plugin.h"
34#include "transport.h"
35
36/**
37 * How long until we give up on transmitting the message?
38 */
39#define WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
40#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
41
42#define HOSTKEY_FILE "test_plugin_hostkey.ecc"
43
44/**
45 * Our public key.
46 */
47static struct GNUNET_PeerIdentity my_identity;
48
49/**
50 * Our private key.
51 */
52static struct GNUNET_CRYPTO_EddsaPrivateKey my_private_key;
53
54/**
55 * Our configuration.
56 */
57const struct GNUNET_CONFIGURATION_Handle *cfg;
58
59/**
60 * Our configuration.
61 */
62struct GNUNET_STATISTICS_Handle *stats;
63
64/**
65 * Our HELLO
66 */
67struct GNUNET_HELLO_Message *hello;
68
69/**
70 * Number of neighbours we'd like to have.
71 */
72static uint32_t max_connect_per_transport;
73
74/**
75 * Environment for this plugin.
76 */
77struct GNUNET_TRANSPORT_PluginEnvironment env;
78
79/**
80 * handle for the api provided by this plugin
81 */
82struct GNUNET_TRANSPORT_PluginFunctions *api;
83
84/**
85 * Helper handler
86 */
87struct GNUNET_HELPER_Handle *suid_helper;
88
89/**
90 * Timeout task
91 */
92static struct GNUNET_SCHEDULER_Task *timeout_endbadly;
93
94/**
95 * Timeout task
96 */
97static struct GNUNET_SCHEDULER_Task *timeout_wait;
98
99/**
100 * Library name
101 */
102static char *libname;
103
104/**
105 * Plugin addresses head
106 */
107struct AddressWrapper *head;
108
109/**
110 * Plugin addresses tail
111 */
112struct AddressWrapper *tail;
113
114unsigned int addresses_reported;
115
116unsigned int pretty_printers_running;
117
118/**
119 * Did the test pass or fail?
120 */
121static int ok;
122
123struct AddressWrapper
124{
125 struct AddressWrapper *next;
126
127 struct AddressWrapper *prev;
128
129 struct GNUNET_HELLO_Address *address;
130
131 char *addrstring;
132
133 struct GNUNET_SCHEDULER_Task *test_task;
134};
135
136
137static void
138end ()
139{
140 struct AddressWrapper *w;
141 int c = 0;
142
143 ok = 0;
144
145 if (NULL != timeout_endbadly)
146 {
147 GNUNET_SCHEDULER_cancel (timeout_endbadly);
148 timeout_endbadly = NULL;
149 }
150 if (NULL != api)
151 GNUNET_PLUGIN_unload (libname, api);
152
153 while (NULL != head)
154 {
155 w = head;
156 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
157 "Plugin did not remove address `%s'\n",
158 w->addrstring);
159 GNUNET_CONTAINER_DLL_remove (head, tail, w);
160 c++;
161 GNUNET_HELLO_address_free (w->address);
162 GNUNET_free (w->addrstring);
163 GNUNET_free (w);
164 }
165 if (c > 0)
166 {
167 GNUNET_break (0);
168 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
169 "Plugin did not remove %u addresses \n",
170 c);
171 ok = 1;
172 }
173
174 GNUNET_free (libname);
175 libname = NULL;
176 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
177 stats = NULL;
178
179 if (NULL != suid_helper)
180 {
181 GNUNET_HELPER_stop (suid_helper, GNUNET_NO);
182 suid_helper = NULL;
183 }
184}
185
186
187static void
188end_badly (void *cls)
189{
190 struct AddressWrapper *w;
191 int c = 0;
192
193 timeout_endbadly = NULL;
194 if (NULL != timeout_wait)
195 {
196 GNUNET_SCHEDULER_cancel (timeout_wait);
197 timeout_wait = NULL;
198 }
199
200 if (pretty_printers_running > 0)
201 {
202 timeout_endbadly = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
203 &end_badly, &ok);
204 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
205 "Have pending calls to pretty_printer ... deferring shutdown\n");
206 return;
207 }
208
209 if (NULL != cls)
210 {
211 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
212 "Test took too long to execute, timeout .... \n");
213 }
214
215 if (NULL != libname)
216 {
217 if (NULL != api)
218 GNUNET_PLUGIN_unload (libname, api);
219 GNUNET_free (libname);
220 libname = NULL;
221 }
222
223 while (NULL != head)
224 {
225 w = head;
226 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Plugin did not remove address `%s'\n",
227 w->addrstring);
228 GNUNET_CONTAINER_DLL_remove (head, tail, w);
229 c++;
230 GNUNET_HELLO_address_free (w->address);
231 if (NULL != w->test_task)
232 GNUNET_SCHEDULER_cancel (w->test_task);
233 GNUNET_free (w->addrstring);
234 GNUNET_free (w);
235 }
236 if (c > 0)
237 {
238 GNUNET_break (0);
239 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Plugin did not remove %u addresses\n",
240 c);
241 }
242
243 if (NULL != stats)
244 {
245 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
246 stats = NULL;
247 }
248
249 if (NULL != suid_helper)
250 {
251 GNUNET_HELPER_stop (suid_helper, GNUNET_NO);
252 suid_helper = NULL;
253 }
254
255 ok = 1;
256}
257
258
259static void
260wait_end (void *cls)
261{
262 timeout_wait = NULL;
263 if (0 == addresses_reported)
264 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
265 "Plugin did not report any addresses, could not check address conversion functions\n");
266 end ();
267}
268
269
270static void
271end_badly_now ()
272{
273 if (NULL != timeout_wait)
274 {
275 GNUNET_SCHEDULER_cancel (timeout_wait);
276 timeout_wait = NULL;
277 }
278 if (NULL != timeout_endbadly)
279 {
280 GNUNET_SCHEDULER_cancel (timeout_endbadly);
281 timeout_endbadly = NULL;
282 }
283 timeout_endbadly = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
284}
285
286
287static struct GNUNET_TIME_Relative
288env_receive (void *cls,
289 const struct GNUNET_HELLO_Address *address,
290 struct GNUNET_ATS_Session *session,
291 const struct GNUNET_MessageHeader *message)
292{
293 /* do nothing */
294 return GNUNET_TIME_relative_get_zero_ ();
295}
296
297
298static int got_reply;
299
300
301/**
302 * Take the given address and append it to the set of results sent back to
303 * the client.
304 *
305 * @param cls closure
306 * @param address the address to print
307 * @param res result code
308 */
309static void
310address_pretty_printer_cb (void *cls, const char *address, int res)
311{
312 if (NULL != address)
313 {
314 got_reply = GNUNET_YES;
315 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Pretty address : `%s'\n", address);
316 pretty_printers_running--;
317 }
318 else
319 {
320 if (GNUNET_NO == got_reply)
321 {
322 pretty_printers_running--;
323 GNUNET_break (0);
324 end_badly_now ();
325 }
326 }
327}
328
329
330static void
331test_addr_string (void *cls)
332{
333 struct AddressWrapper *w = cls;
334 void *s2a;
335 size_t s2a_len;
336
337 w->test_task = NULL;
338
339 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
340 "Testing: address_to_string \n");
341 w->addrstring = GNUNET_strdup (api->address_to_string (api,
342 w->address->address,
343 w->address->
344 address_length));
345 if (NULL == w->addrstring)
346 {
347 GNUNET_break (0);
348 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
349 "Plugin cannot convert address to string!\n");
350 end_badly_now ();
351 return;
352 }
353 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
354 "Plugin added address `%s'\n",
355 w->addrstring);
356 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
357 "Testing address_to_string: OK\n");
358 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
359 "Testing: string_to_address \n");
360 s2a = NULL;
361 s2a_len = 0;
362 if ((GNUNET_OK !=
363 api->string_to_address (api, w->addrstring,
364 strlen (w->addrstring) + 1,
365 &s2a, &s2a_len)) ||
366 (NULL == s2a))
367 {
368 GNUNET_break (0);
369 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
370 "Plugin cannot convert string to address!\n");
371 end_badly_now ();
372 return;
373 }
374
375 /*
376 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
377 "Plugin creates `%s' %u\n",api->address_to_string (api, s2a, s2a_len), s2a_len);
378
379 int c1;
380 for (c1 = 0; c1 < s2a_len; c1++ )
381 fprintf (stderr, "%u == %u\n", ((char *) s2a)[c1], ((char *) w->addr)[c1]);
382 */if (s2a_len != w->address->address_length)
383 {
384 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
385 "Plugin creates different address length when converting address->string->address: %u != %u\n",
386 (unsigned int) w->address->address_length,
387 (unsigned int) s2a_len);
388 }
389 else if (0 != memcmp (s2a, w->address->address, s2a_len))
390 {
391 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
392 "Plugin creates different address length when converting back and forth %i!\n",
393 memcmp (s2a,
394 w->address->address,
395 s2a_len));
396 }
397 else
398 {
399 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
400 "Testing string_to_address: OK\n");
401 }
402 GNUNET_free (s2a);
403
404 pretty_printers_running++;
405 api->address_pretty_printer (api->cls,
406 w->address->transport_name,
407 w->address->address,
408 w->address->address_length,
409 GNUNET_YES,
410 GNUNET_TIME_UNIT_MINUTES,
411 &address_pretty_printer_cb, w);
412
413 if (GNUNET_OK !=
414 api->check_address (api->cls,
415 w->address->address,
416 w->address->address_length))
417 {
418 GNUNET_break (0);
419 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
420 "Plugin refuses added address!\n");
421 end_badly_now ();
422 return;
423 }
424 if (NULL != timeout_wait)
425 {
426 GNUNET_SCHEDULER_cancel (timeout_wait);
427 timeout_wait = NULL;
428 }
429 timeout_wait = GNUNET_SCHEDULER_add_delayed (WAIT, &wait_end, NULL);
430}
431
432
433static void
434env_notify_address (void *cls,
435 int add_remove,
436 const struct GNUNET_HELLO_Address *address)
437{
438 struct AddressWrapper *w;
439 struct AddressWrapper *wtmp;
440
441 if (GNUNET_YES == add_remove)
442 {
443 addresses_reported++;
444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
445 "Adding address of length %u\n",
446 (unsigned int) address->address_length);
447
448 for (wtmp = head; NULL != wtmp; wtmp = wtmp->next)
449 {
450 if ((address->address_length == wtmp->address->address_length) &&
451 (0 == memcmp (address->address, wtmp->address->address,
452 address->address_length)))
453 {
454 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
455 "Duplicate address notification .... \n");
456 return;
457 }
458 }
459
460 w = GNUNET_new (struct AddressWrapper);
461 w->address = GNUNET_HELLO_address_copy (address);
462 GNUNET_CONTAINER_DLL_insert (head, tail, w);
463 got_reply = GNUNET_NO;
464 w->test_task = GNUNET_SCHEDULER_add_now (&test_addr_string,
465 w);
466 return;
467 }
468
469 if (GNUNET_NO == add_remove)
470 {
471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
472 "Removing address of length %u\n",
473 (unsigned int) address->address_length);
474 w = head;
475 while (NULL != w)
476 {
477 if ((address->address_length == w->address->address_length) &&
478 (0 == memcmp (w->address->address, address->address,
479 address->address_length)))
480 {
481 break;
482 }
483 w = w->next;
484 }
485
486 if (w == NULL)
487 {
488 GNUNET_break (0);
489 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
490 "Plugin removes address never added!\n");
491 end_badly_now ();
492 return;
493 }
494
495 GNUNET_CONTAINER_DLL_remove (head, tail, w);
496 GNUNET_HELLO_address_free (w->address);
497 GNUNET_free (w->addrstring);
498 GNUNET_free (w);
499 return;
500 }
501 GNUNET_break (0);
502 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
503 "Invalid operation: %u\n",
504 add_remove);
505 end_badly_now ();
506}
507
508
509static enum GNUNET_NetworkType
510env_get_address_type (void *cls,
511 const struct sockaddr *addr,
512 size_t addrlen)
513{
514 return GNUNET_NT_LOOPBACK;
515}
516
517
518static const struct GNUNET_MessageHeader *
519env_get_our_hello ()
520{
521 return (const struct GNUNET_MessageHeader *) hello;
522}
523
524
525static void
526env_session_end (void *cls,
527 const struct GNUNET_HELLO_Address *address,
528 struct GNUNET_ATS_Session *session)
529{
530}
531
532
533static void
534env_update_distance (void *cls,
535 const struct GNUNET_HELLO_Address *address,
536 uint32_t distance)
537{
538}
539
540
541static void
542setup_plugin_environment ()
543{
544 env.cfg = cfg;
545 env.cls = &env;
546 env.my_identity = &my_identity;
547 env.max_connections = max_connect_per_transport;
548 env.stats = stats;
549 env.receive = &env_receive;
550 env.notify_address = &env_notify_address;
551 env.get_address_type = &env_get_address_type;
552 env.update_address_distance = &env_update_distance;
553 env.get_our_hello = &env_get_our_hello;
554 env.session_end = &env_session_end;
555}
556
557
558static int
559handle_helper_message (void *cls,
560 const struct GNUNET_MessageHeader *hdr)
561{
562 return GNUNET_OK;
563}
564
565
566/**
567 * Runs the test.
568 *
569 * @param cls closure
570 * @param c configuration to use
571 */
572static void
573run (void *cls,
574 char *const *args,
575 const char *cfgfile,
576 const struct GNUNET_CONFIGURATION_Handle *c)
577{
578 char *const *argv = cls;
579 unsigned long long tneigh;
580 char *keyfile;
581 char *plugin;
582 char *sep;
583
584 timeout_endbadly = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
585 &end_badly,
586 &ok);
587 cfg = c;
588 /* parse configuration */
589 if ((GNUNET_OK !=
590 GNUNET_CONFIGURATION_get_value_number (c,
591 "TRANSPORT",
592 "NEIGHBOUR_LIMIT",
593 &tneigh)) ||
594 (GNUNET_OK !=
595 GNUNET_CONFIGURATION_get_value_filename (c,
596 "PEER",
597 "PRIVATE_KEY",
598 &keyfile)))
599 {
600 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
601 "Transport service is lacking key configuration settings. Exiting.\n");
602 return;
603 }
604
605 if (NULL == (stats = GNUNET_STATISTICS_create ("transport",
606 cfg)))
607 {
608 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
609 "Could not create statistics. Exiting.\n");
610 GNUNET_free (keyfile);
611 end_badly_now ();
612 return;
613 }
614
615 if (GNUNET_OK != GNUNET_DISK_file_test (HOSTKEY_FILE))
616 {
617 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
618 "Hostkey `%s' missing. Exiting.\n",
619 HOSTKEY_FILE);
620 GNUNET_free (keyfile);
621 end_badly_now ();
622 return;
623 }
624
625 if (GNUNET_OK !=
626 GNUNET_DISK_directory_create_for_file (keyfile))
627 {
628 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
629 "Could not create a directory for hostkey `%s'. Exiting.\n",
630 keyfile);
631 GNUNET_free (keyfile);
632 end_badly_now ();
633 return;
634 }
635
636 if (GNUNET_OK !=
637 GNUNET_DISK_file_copy (HOSTKEY_FILE,
638 keyfile))
639 {
640 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
641 "Could not copy hostkey `%s' to destination `%s'. Exiting.\n",
642 HOSTKEY_FILE,
643 keyfile);
644 GNUNET_free (keyfile);
645 end_badly_now ();
646 return;
647 }
648
649 max_connect_per_transport = (uint32_t) tneigh;
650 if (GNUNET_SYSERR ==
651 GNUNET_CRYPTO_eddsa_key_from_file (keyfile,
652 GNUNET_YES,
653 &my_private_key))
654 {
655 GNUNET_free (keyfile);
656 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
657 "Could not access hostkey. Exiting.\n");
658 end_badly_now ();
659 return;
660 }
661 GNUNET_free (keyfile);
662 GNUNET_CRYPTO_eddsa_key_get_public (&my_private_key,
663 &my_identity.public_key);
664
665 hello = GNUNET_HELLO_create (&my_identity.public_key, NULL, NULL, GNUNET_NO);
666
667 /* load plugins... */
668 setup_plugin_environment ();
669
670 GNUNET_assert (strlen (argv[0]) > strlen ("test_plugin_"));
671 plugin = strstr (argv[0], "test_plugin_");
672 sep = strrchr (argv[0], '.');
673 if (NULL == plugin)
674 {
675 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Not a valid test name\n");
676 end_badly_now ();
677 return;
678 }
679 plugin += strlen ("test_plugin_");
680 if (NULL != sep)
681 sep[0] = '\0';
682
683 /* Hack for WLAN: start a second helper */
684 if (0 == strcmp (plugin, "wlan"))
685 {
686 char *helper_argv[3];
687 helper_argv[0] = (char *) "gnunet-helper-transport-wlan-dummy";
688 helper_argv[1] = (char *) "2";
689 helper_argv[2] = NULL;
690 suid_helper = GNUNET_HELPER_start (GNUNET_NO,
691 "gnunet-helper-transport-wlan-dummy",
692 helper_argv,
693 &handle_helper_message, NULL, NULL);
694 }
695
696 /* Loading plugin */
697 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Loading transport plugin %s\n", plugin);
698 GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", plugin);
699 api = GNUNET_PLUGIN_load (libname, &env);
700 if (NULL == api)
701 {
702 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
703 "Failed to load transport plugin for %s\n", plugin);
704 end_badly_now ();
705 return;
706 }
707
708 timeout_wait = GNUNET_SCHEDULER_add_delayed (WAIT, &wait_end, NULL);
709
710 /* Check if all functions are implemented */
711 if (NULL == api->address_pretty_printer)
712 {
713 GNUNET_break (0);
714 end_badly_now ();
715 return;
716 }
717 if (NULL == api->address_to_string)
718 {
719 GNUNET_break (0);
720 end_badly_now ();
721 return;
722 }
723 GNUNET_assert (NULL != api->check_address);
724 if (NULL == api->check_address)
725 {
726 GNUNET_break (0);
727 end_badly_now ();
728 return;
729 }
730 GNUNET_assert (NULL != api->disconnect_peer);
731 if (NULL == api->disconnect_peer)
732 {
733 GNUNET_break (0);
734 end_badly_now ();
735 return;
736 }
737 GNUNET_assert (NULL != api->get_session);
738 if (NULL == api->get_session)
739 {
740 GNUNET_break (0);
741 end_badly_now ();
742 return;
743 }
744 if (NULL == api->address_pretty_printer)
745 {
746 GNUNET_break (0);
747 end_badly_now ();
748 return;
749 }
750 if (NULL == api->string_to_address)
751 {
752 GNUNET_break (0);
753 end_badly_now ();
754 return;
755 }
756}
757
758
759/**
760 * The main function for the test
761 *
762 * @param argc number of arguments from the command line
763 * @param argv command line arguments
764 * @return 0 ok, 1 on error
765 */
766int
767main (int argc,
768 char *const *argv)
769{
770 static struct GNUNET_GETOPT_CommandLineOption options[] = {
771 GNUNET_GETOPT_OPTION_END
772 };
773 int ret;
774 char *const argv_prog[] = {
775 "test_plugin_transport",
776 "-c",
777 "test_plugin_transport_data.conf",
778 NULL
779 };
780
781 GNUNET_log_setup ("test-plugin-transport",
782 "WARNING",
783 NULL);
784 GNUNET_DISK_purge_cfg_dir ("test_plugin_transport_data.conf",
785 "GNUNET_TEST_HOME");
786 ok = 1; /* set to fail */
787 ret =
788 (GNUNET_OK
789 == GNUNET_PROGRAM_run (3, argv_prog, "test-plugin-transport",
790 "testcase", options, &run, (void *) argv)) ? ok : 1;
791 GNUNET_DISK_purge_cfg_dir ("test_plugin_transport_data.conf",
792 "GNUNET_TEST_HOME");
793 return ret;
794}
795
796
797/* end of test_plugin_transport.c */
diff --git a/src/transport/test_plugin_transport_data.conf b/src/transport/test_plugin_transport_data.conf
deleted file mode 100644
index b667a4854..000000000
--- a/src/transport/test_plugin_transport_data.conf
+++ /dev/null
@@ -1,47 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
4
5[transport-tcp]
6PORT = 52400
7
8[transport-udp]
9PORT = 52401
10
11[transport-wlan]
12INTERFACE = mon0
13TESTMODE = 1
14
15[transport-bluetooth]
16INTERFACE = hci0
17TESTMODE = 1
18
19[transport-http_server]
20PORT = 52402
21
22[transport-https_server]
23PORT = 52403
24
25[arm]
26PORT = 52360
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-arm.sock
28
29[statistics]
30PORT = 52361
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics.sock
32
33[resolver]
34PORT = 52362
35UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver.sock
36
37[peerinfo]
38PORT = 52363
39UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-peerinfo.sock
40
41[transport]
42PORT = 52364
43UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport.sock
44
45[nat]
46RETURN_LOCAL_ADDRESSES = YES
47DISABLEV6 = NO
diff --git a/src/transport/test_plugin_transport_data_udp.conf b/src/transport/test_plugin_transport_data_udp.conf
deleted file mode 100644
index 8b1378917..000000000
--- a/src/transport/test_plugin_transport_data_udp.conf
+++ /dev/null
@@ -1 +0,0 @@
1
diff --git a/src/transport/test_quota_compliance.c b/src/transport/test_quota_compliance.c
deleted file mode 100644
index c3c46db37..000000000
--- a/src/transport/test_quota_compliance.c
+++ /dev/null
@@ -1,321 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_quota_compliance.c
22 * @brief base test case for transport implementations
23 *
24 * This test case tests quota compliance both on transport level
25 */
26#include "platform.h"
27#include "gnunet_transport_service.h"
28#include "gnunet_ats_service.h"
29#include "gauger.h"
30#include "transport-testing.h"
31
32/**
33 * Testcase timeout
34 */
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 480)
36
37#define DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 80)
38
39
40static struct GNUNET_SCHEDULER_Task *measure_task;
41
42static char *gen_cfgs[2];
43
44static unsigned long long quota_in[] = { 10000, 10000 };
45
46static unsigned long long quota_out[] = { 10000, 10000 };
47
48static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
49
50
51/**
52 * Note that this value must not significantly exceed
53 * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
54 * messages may be dropped even for a reliable transport.
55 */
56#define TOTAL_MSGS (1024 * 32)
57
58static unsigned long long total_bytes_recv;
59
60static struct GNUNET_TIME_Absolute start_time;
61
62
63static void
64report ()
65{
66 unsigned long long delta;
67 unsigned long long datarate;
68
69 delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us;
70 if (0 == delta)
71 delta = 1;
72 datarate = (total_bytes_recv * 1000 * 1000) / delta;
73
74 fprintf (stderr,
75 "Throughput was %llu b/s\n",
76 datarate);
77 ccc->global_ret = GNUNET_OK;
78 if (datarate > 1.5 * quota_in[1])
79 {
80 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
81 "Datarate of %llu b/s significantly higher than allowed inbound quota of %llu b/s\n",
82 datarate,
83 quota_in[1]);
84 ccc->global_ret = GNUNET_SYSERR;
85 }
86 if (datarate > 1.5 * quota_out[0])
87 {
88 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
89 "Datarate of %llu b/s significantly higher than allowed outbound quota of %llu b/s\n",
90 datarate,
91 quota_out[0]);
92 ccc->global_ret = GNUNET_SYSERR;
93 }
94 if (GNUNET_OK == ccc->global_ret)
95 {
96 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
97 "Datarate of %llu b/s complied to allowed outbound quota of %llu b/s and inbound quota of %llu b/s\n",
98 datarate,
99 quota_out[0],
100 quota_in[1]);
101 }
102}
103
104
105static void
106custom_shutdown (void *cls)
107{
108 if (NULL != measure_task)
109 {
110 GNUNET_SCHEDULER_cancel (measure_task);
111 measure_task = NULL;
112 }
113 report ();
114}
115
116
117static size_t
118get_size (unsigned int iter)
119{
120 size_t ret;
121
122 ret = (iter * iter * iter) % 60000;
123 ret += sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage);
124 return ret;
125}
126
127
128static void
129notify_receive (void *cls,
130 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
131 const struct GNUNET_PeerIdentity *sender,
132 const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr)
133{
134 if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
135 return;
136 total_bytes_recv += ntohs (hdr->header.size);
137
138 {
139 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
140
141 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
142 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
143 receiver->no,
144 ps,
145 ntohl (hdr->num),
146 ntohs (hdr->header.size),
147 GNUNET_i2s (sender));
148 GNUNET_free (ps);
149 }
150}
151
152
153static void
154measure (void *cls)
155{
156 static int counter;
157
158 measure_task = NULL;
159 counter++;
160 if ((DURATION.rel_value_us / 1000 / 1000LL) < counter)
161 {
162 fprintf (stderr, "%s", ".\n");
163 GNUNET_SCHEDULER_shutdown ();
164 return;
165 }
166 fprintf (stderr, "%s", ".");
167 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
168 &measure,
169 NULL);
170}
171
172
173static void
174start_task (void *cls)
175{
176 static struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
177 .num_messages = TOTAL_MSGS,
178 .get_size_cb = &get_size
179 };
180
181 sc.ccc = ccc;
182 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
183 &measure,
184 NULL);
185 start_time = GNUNET_TIME_absolute_get ();
186 GNUNET_SCHEDULER_add_now (&GNUNET_TRANSPORT_TESTING_simple_send,
187 &sc);
188}
189
190
191static char *
192generate_config (const char *cfg_file,
193 unsigned long long quota_in,
194 unsigned long long quota_out)
195{
196 char *in_name;
197 char *out_name;
198 char *fname = NULL;
199 struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
200
201 GNUNET_assert (GNUNET_OK ==
202 GNUNET_CONFIGURATION_load (cfg,
203 cfg_file));
204 GNUNET_asprintf (&fname,
205 "q_in_%llu_q_out_%llu_%s",
206 quota_in,
207 quota_out,
208 cfg_file);
209 GNUNET_CONFIGURATION_set_value_string (cfg,
210 "PATHS",
211 "DEFAULTCONFIG",
212 fname);
213 for (int c = 0; c < GNUNET_NT_COUNT; c++)
214 {
215 GNUNET_asprintf (&in_name,
216 "%s_QUOTA_IN",
217 GNUNET_NT_to_string (c));
218 GNUNET_asprintf (&out_name,
219 "%s_QUOTA_OUT",
220 GNUNET_NT_to_string (c));
221 GNUNET_CONFIGURATION_set_value_number (cfg,
222 "ats",
223 in_name,
224 quota_in);
225 GNUNET_CONFIGURATION_set_value_number (cfg,
226 "ats",
227 out_name,
228 quota_out);
229 GNUNET_free (in_name);
230 GNUNET_free (out_name);
231 }
232 GNUNET_assert (GNUNET_OK ==
233 GNUNET_CONFIGURATION_write (cfg,
234 fname));
235 GNUNET_CONFIGURATION_destroy (cfg);
236 return fname;
237}
238
239
240static int
241check (void *cls,
242 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
243 const char *test_plugin_,
244 const char *test_name_,
245 unsigned int num_peers,
246 char *cfg_files[])
247{
248 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
249 .connect_continuation = &start_task,
250 .config_file = "test_quota_compliance_data.conf",
251 .rec = &notify_receive,
252 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
253 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
254 .shutdown_task = &custom_shutdown,
255 .timeout = TIMEOUT
256 };
257
258 ccc = &my_ccc;
259
260 if (NULL != strstr (test_name_,
261 "asymmetric"))
262 {
263 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
264 "Running asymmetric test with sending peer unlimited, receiving peer (in/out): %llu/%llu b/s \n",
265 quota_in[1],
266 quota_out[1]);
267 quota_out[0] = 1024 * 1024 * 1024;
268 quota_in[0] = 1024 * 1024 * 1024;
269 }
270 else
271 {
272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
273 "Running symmetric test with (in/out) %llu/%llu b/s \n",
274 quota_in[1],
275 quota_out[1]);
276 }
277 for (unsigned int i = 0; i < 2; i++)
278 {
279 gen_cfgs[i] = generate_config (cfg_files[i],
280 quota_in[i],
281 quota_out[i]);
282 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
283 "Generated config file `%s'\n",
284 gen_cfgs[i]);
285 }
286
287 return GNUNET_TRANSPORT_TESTING_connect_check (&my_ccc,
288 tth_,
289 test_plugin_,
290 test_name_,
291 num_peers,
292 gen_cfgs);
293}
294
295
296int
297main (int argc,
298 char *argv[])
299{
300 if (GNUNET_OK !=
301 GNUNET_TRANSPORT_TESTING_main (2,
302 &check,
303 NULL))
304 {
305 GNUNET_break (0);
306 return 1;
307 }
308 for (unsigned int i = 0; i < 2; i++)
309 {
310 if ((NULL != gen_cfgs[i]) &&
311 (GNUNET_YES == GNUNET_DISK_file_test (gen_cfgs[i])))
312 {
313 GNUNET_DISK_directory_remove (gen_cfgs[i]);
314 GNUNET_free (gen_cfgs[i]);
315 }
316 }
317 return 0;
318}
319
320
321/* end of test_quota_compliance.c */
diff --git a/src/transport/test_quota_compliance_bluetooth_asymmetric_peer1.conf b/src/transport/test_quota_compliance_bluetooth_asymmetric_peer1.conf
deleted file mode 100644
index 86bdf6db4..000000000
--- a/src/transport/test_quota_compliance_bluetooth_asymmetric_peer1.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[transport]
10PLUGINS = bluetooth
11
12
diff --git a/src/transport/test_quota_compliance_bluetooth_asymmetric_peer2.conf b/src/transport/test_quota_compliance_bluetooth_asymmetric_peer2.conf
deleted file mode 100644
index 086688e73..000000000
--- a/src/transport/test_quota_compliance_bluetooth_asymmetric_peer2.conf
+++ /dev/null
@@ -1,11 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[transport]
10PLUGINS = bluetooth
11
diff --git a/src/transport/test_quota_compliance_bluetooth_peer1.conf b/src/transport/test_quota_compliance_bluetooth_peer1.conf
deleted file mode 100644
index 3f86ee940..000000000
--- a/src/transport/test_quota_compliance_bluetooth_peer1.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
30
diff --git a/src/transport/test_quota_compliance_bluetooth_peer2.conf b/src/transport/test_quota_compliance_bluetooth_peer2.conf
deleted file mode 100644
index 5fc178395..000000000
--- a/src/transport/test_quota_compliance_bluetooth_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_quota_compliance_data.conf b/src/transport/test_quota_compliance_data.conf
deleted file mode 100644
index 1bc607770..000000000
--- a/src/transport/test_quota_compliance_data.conf
+++ /dev/null
@@ -1,24 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-gnunetd-plugin-transport/
4
5[transport-tcp]
6PORT = 52368
7TIMEOUT = 5 s
8
9[arm]
10PORT = 52366
11
12[statistics]
13PORT = 52367
14
15[resolver]
16PORT = 52364
17
18[peerinfo]
19PORT = 52369
20
21[transport]
22PORT = 52365
23
24
diff --git a/src/transport/test_quota_compliance_http_asymmetric_peer1.conf b/src/transport/test_quota_compliance_http_asymmetric_peer1.conf
deleted file mode 100644
index b2ff1913f..000000000
--- a/src/transport/test_quota_compliance_http_asymmetric_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1
4
5[transport-http_client]
6
7[arm]
8PORT = 54015
9UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_arm_peer1.sock
10
11[statistics]
12PORT = 54014
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_statistics_peer1.sock
14
15[resolver]
16PORT = 54013
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_resolver_peer1.sock
18
19[peerinfo]
20PORT = 54012
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_peerinfo_peer1.sock
22
23[transport]
24PORT = 54011
25PLUGINS = http_client
26UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_transport_peer1.sock
27
28
diff --git a/src/transport/test_quota_compliance_http_asymmetric_peer2.conf b/src/transport/test_quota_compliance_http_asymmetric_peer2.conf
deleted file mode 100644
index 3408d9f2e..000000000
--- a/src/transport/test_quota_compliance_http_asymmetric_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-http_server]
6PORT = 53010
7USE_IPv6 = NO
8BINDTO = 127.0.0.1
9
10
11[arm]
12PORT = 53015
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_arm_peer2.sock
14
15[statistics]
16PORT = 53014
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_statistics_peer2.sock
18
19[resolver]
20PORT = 53013
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_resolver_peer2.sock
22
23[peerinfo]
24PORT = 53012
25UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_peerinfo_peer2.sock
26
27[transport]
28PORT = 53011
29PLUGINS = http_server
30UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_transport_peer2.sock
31
32
diff --git a/src/transport/test_quota_compliance_http_peer1.conf b/src/transport/test_quota_compliance_http_peer1.conf
deleted file mode 100644
index b2ff1913f..000000000
--- a/src/transport/test_quota_compliance_http_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1
4
5[transport-http_client]
6
7[arm]
8PORT = 54015
9UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_arm_peer1.sock
10
11[statistics]
12PORT = 54014
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_statistics_peer1.sock
14
15[resolver]
16PORT = 54013
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_resolver_peer1.sock
18
19[peerinfo]
20PORT = 54012
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_peerinfo_peer1.sock
22
23[transport]
24PORT = 54011
25PLUGINS = http_client
26UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_transport_peer1.sock
27
28
diff --git a/src/transport/test_quota_compliance_http_peer2.conf b/src/transport/test_quota_compliance_http_peer2.conf
deleted file mode 100644
index 3408d9f2e..000000000
--- a/src/transport/test_quota_compliance_http_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-http_server]
6PORT = 53010
7USE_IPv6 = NO
8BINDTO = 127.0.0.1
9
10
11[arm]
12PORT = 53015
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_arm_peer2.sock
14
15[statistics]
16PORT = 53014
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_statistics_peer2.sock
18
19[resolver]
20PORT = 53013
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_resolver_peer2.sock
22
23[peerinfo]
24PORT = 53012
25UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_peerinfo_peer2.sock
26
27[transport]
28PORT = 53011
29PLUGINS = http_server
30UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_http_transport_peer2.sock
31
32
diff --git a/src/transport/test_quota_compliance_https_asymmetric_peer1.conf b/src/transport/test_quota_compliance_https_asymmetric_peer1.conf
deleted file mode 100644
index 94aa534ef..000000000
--- a/src/transport/test_quota_compliance_https_asymmetric_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1/
4
5[transport-https_client]
6
7[arm]
8PORT = 54006
9UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_arm_peer1.sock
10
11[statistics]
12PORT = 54005
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_statistics_peer1.sock
14
15[resolver]
16PORT = 54004
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_resolver_peer1.sock
18
19[peerinfo]
20PORT = 54003
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_peerinfo_peer1.sock
22
23[transport]
24PORT = 54002
25PLUGINS = https_client
26UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_transport_peer1.sock
27
28
diff --git a/src/transport/test_quota_compliance_https_asymmetric_peer2.conf b/src/transport/test_quota_compliance_https_asymmetric_peer2.conf
deleted file mode 100644
index 8fb8861cd..000000000
--- a/src/transport/test_quota_compliance_https_asymmetric_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-https_server]
6PORT = 53001
7KEY_FILE = https_key_quota_p2.key
8CERT_FILE = https_cert_qutoa_p2.crt
9
10[arm]
11PORT = 53006
12UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_arm_peer2.sock
13
14[statistics]
15PORT = 53005
16UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_statistics_peer2.sock
17
18[resolver]
19PORT = 53004
20UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_resolver_peer2.sock
21
22[peerinfo]
23PORT = 53003
24UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_peerinfo_peer2.sock
25
26[transport]
27PORT = 53002
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/https_transport_peer2.sock
30
31
diff --git a/src/transport/test_quota_compliance_https_peer1.conf b/src/transport/test_quota_compliance_https_peer1.conf
deleted file mode 100644
index 94aa534ef..000000000
--- a/src/transport/test_quota_compliance_https_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1/
4
5[transport-https_client]
6
7[arm]
8PORT = 54006
9UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_arm_peer1.sock
10
11[statistics]
12PORT = 54005
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_statistics_peer1.sock
14
15[resolver]
16PORT = 54004
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_resolver_peer1.sock
18
19[peerinfo]
20PORT = 54003
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_peerinfo_peer1.sock
22
23[transport]
24PORT = 54002
25PLUGINS = https_client
26UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_transport_peer1.sock
27
28
diff --git a/src/transport/test_quota_compliance_https_peer2.conf b/src/transport/test_quota_compliance_https_peer2.conf
deleted file mode 100644
index 8fb8861cd..000000000
--- a/src/transport/test_quota_compliance_https_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-https_server]
6PORT = 53001
7KEY_FILE = https_key_quota_p2.key
8CERT_FILE = https_cert_qutoa_p2.crt
9
10[arm]
11PORT = 53006
12UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_arm_peer2.sock
13
14[statistics]
15PORT = 53005
16UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_statistics_peer2.sock
17
18[resolver]
19PORT = 53004
20UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_resolver_peer2.sock
21
22[peerinfo]
23PORT = 53003
24UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_https_peerinfo_peer2.sock
25
26[transport]
27PORT = 53002
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/https_transport_peer2.sock
30
31
diff --git a/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf b/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf
deleted file mode 100644
index 0e0cbff24..000000000
--- a/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/quota-tcp-p1/
4
5[transport-tcp]
6PORT = 54094
7
8[transport-udp]
9PORT = 54094
10
11[arm]
12PORT = 54087
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_arm_peer1.sock
14
15[statistics]
16PORT = 54088
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_statistics_peer1.sock
18
19[resolver]
20PORT = 54089
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_resolver_peer1.sock
22
23[peerinfo]
24PORT = 54090
25UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_peerinfo_peer1.sock
26
27[transport]
28PORT = 54091
29PLUGINS = tcp
30UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_transport_peer1.sock
31
32
diff --git a/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf b/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf
deleted file mode 100644
index e9757b080..000000000
--- a/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/quota-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_quota_compliance_tcp_peer1.conf b/src/transport/test_quota_compliance_tcp_peer1.conf
deleted file mode 100644
index 0e0cbff24..000000000
--- a/src/transport/test_quota_compliance_tcp_peer1.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/quota-tcp-p1/
4
5[transport-tcp]
6PORT = 54094
7
8[transport-udp]
9PORT = 54094
10
11[arm]
12PORT = 54087
13UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_arm_peer1.sock
14
15[statistics]
16PORT = 54088
17UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_statistics_peer1.sock
18
19[resolver]
20PORT = 54089
21UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_resolver_peer1.sock
22
23[peerinfo]
24PORT = 54090
25UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_peerinfo_peer1.sock
26
27[transport]
28PORT = 54091
29PLUGINS = tcp
30UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_tcp_transport_peer1.sock
31
32
diff --git a/src/transport/test_quota_compliance_tcp_peer2.conf b/src/transport/test_quota_compliance_tcp_peer2.conf
deleted file mode 100644
index a7b2cf90b..000000000
--- a/src/transport/test_quota_compliance_tcp_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_quota_compliance_udp_peer1.conf b/src/transport/test_quota_compliance_udp_peer1.conf
deleted file mode 100644
index bba75c168..000000000
--- a/src/transport/test_quota_compliance_udp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1/
4
5[transport-udp]
6PORT = 54368
7MAX_BPS = 50000000
8
9[arm]
10PORT = 54087
11UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_arm_peer1.sock
12
13[statistics]
14PORT = 54088
15UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_statistics_peer1.sock
16
17[resolver]
18PORT = 54089
19UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_resolver_peer1.sock
20
21[peerinfo]
22PORT = 54090
23UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_peerinfo_peer1.sock
24
25[transport]
26PORT = 54091
27PLUGINS = udp
28UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_transport_peer1.sock
29
diff --git a/src/transport/test_quota_compliance_udp_peer2.conf b/src/transport/test_quota_compliance_udp_peer2.conf
deleted file mode 100644
index 1cb04038c..000000000
--- a/src/transport/test_quota_compliance_udp_peer2.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-udp]
6PORT = 53368
7MAX_BPS = 50000000
8
9[arm]
10PORT = 53087
11UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_arm_peer2.sock
12
13[statistics]
14PORT = 53088
15UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_statistics_peer2.sock
16
17[resolver]
18PORT = 53089
19UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_resolver_peer2.sock
20
21[peerinfo]
22PORT = 53090
23UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_peerinfo_peer2.sock
24
25[transport]
26PORT = 53091
27PLUGINS = udp
28UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_udp_transport_peer2.sock
29
30
diff --git a/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf b/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf
deleted file mode 100644
index a8ee6d77a..000000000
--- a/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1/
4
5[arm]
6PORT = 54087
7UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_arm_peer1.sock
8
9[statistics]
10PORT = 54088
11UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_statistics_peer1.sock
12
13[resolver]
14PORT = 54089
15UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_resolver_peer1.sock
16
17[peerinfo]
18PORT = 54090
19UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_peerinfo_peer1.sock
20
21[transport]
22PORT = 54091
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_transport_peer1.sock
25
26[transport-unix]
27PORT = 54092
28
diff --git a/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf b/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf
deleted file mode 100644
index 6edbcac9f..000000000
--- a/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[arm]
6PORT = 53087
7UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_arm_peer2.sock
8
9[statistics]
10PORT = 53088
11UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_statistics_peer2.sock
12
13[resolver]
14PORT = 53089
15UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_resolver_peer2.sock
16
17[peerinfo]
18PORT = 53090
19UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_peerinfo_peer2.sock
20
21[transport]
22PORT = 53091
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_transport_peer2.sock
25
26[transport-unix]
27PORT = 53368
28
diff --git a/src/transport/test_quota_compliance_unix_peer1.conf b/src/transport/test_quota_compliance_unix_peer1.conf
deleted file mode 100644
index 59c8d6d9e..000000000
--- a/src/transport/test_quota_compliance_unix_peer1.conf
+++ /dev/null
@@ -1,27 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer1/
4
5[transport-unix]
6PORT = 12120
7
8[arm]
9PORT = 54087
10UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_arm_peer1.sock
11
12[statistics]
13PORT = 54088
14UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_statistics_peer1.sock
15
16[resolver]
17PORT = 54089
18UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_resolver_peer1.sock
19
20[peerinfo]
21PORT = 54090
22UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_peerinfo_peer1.sock
23
24[transport]
25PORT = 54091
26PLUGINS = unix
27UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_transport_peer1.sock
diff --git a/src/transport/test_quota_compliance_unix_peer2.conf b/src/transport/test_quota_compliance_unix_peer2.conf
deleted file mode 100644
index 8c2f9989e..000000000
--- a/src/transport/test_quota_compliance_unix_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test_quota_compliance_peer2
4
5[transport-unix]
6PORT = 12136
7
8[arm]
9PORT = 53087
10UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_arm_peer2.sock
11
12[statistics]
13PORT = 53088
14UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_statistics_peer2.sock
15
16[resolver]
17PORT = 53089
18UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_resolver_peer2.sock
19
20[peerinfo]
21PORT = 53090
22UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_peerinfo_peer2.sock
23
24[transport]
25PORT = 53091
26PLUGINS = unix
27UNIXPATH = $GNUNET_RUNTIME_DIR/test_quota_compliance_unix_transport_peer2.sock
28
29[transport-unix]
30PORT = 53368
31
diff --git a/src/transport/test_quota_compliance_wlan_asymmetric_peer1.conf b/src/transport/test_quota_compliance_wlan_asymmetric_peer1.conf
deleted file mode 100644
index 78e280b68..000000000
--- a/src/transport/test_quota_compliance_wlan_asymmetric_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6TESTMODE = 1
7
8[arm]
9PORT = 12164
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12163
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12162
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12161
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12160
26PLUGINS = wlan
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28
29
diff --git a/src/transport/test_quota_compliance_wlan_asymmetric_peer2.conf b/src/transport/test_quota_compliance_wlan_asymmetric_peer2.conf
deleted file mode 100644
index e97ab3f38..000000000
--- a/src/transport/test_quota_compliance_wlan_asymmetric_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_quota_compliance_wlan_peer1.conf b/src/transport/test_quota_compliance_wlan_peer1.conf
deleted file mode 100644
index 78e280b68..000000000
--- a/src/transport/test_quota_compliance_wlan_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6TESTMODE = 1
7
8[arm]
9PORT = 12164
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12163
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12162
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12161
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12160
26PLUGINS = wlan
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28
29
diff --git a/src/transport/test_quota_compliance_wlan_peer2.conf b/src/transport/test_quota_compliance_wlan_peer2.conf
deleted file mode 100644
index e97ab3f38..000000000
--- a/src/transport/test_quota_compliance_wlan_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_transport_address_switch.c b/src/transport/test_transport_address_switch.c
deleted file mode 100644
index ce5117bd1..000000000
--- a/src/transport/test_transport_address_switch.c
+++ /dev/null
@@ -1,433 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_address_switch.c
22 * @brief base test case for transport implementations
23 *
24 * This test case tests if peers can successfully switch addresses when
25 * connected for plugins supporting multiple addresses by monitoring transport's
26 * statistic values.
27 *
28 * This test starts 2 peers and connects them. When connected test messages
29 * are transmitted from peer 2 to peer 1. The test monitors transport's
30 * statistics values for information about address switch attempts.
31 *
32 * The test passes with success if one of the peers could successfully switch
33 * addresses in connected state and a test message was successfully transmitted
34 * after this switch.
35 *
36 * Since it is not possible to trigger an address switch from outside,
37 * the test returns "77" (skipped) when no address switching attempt
38 * takes place. It fails if an address switch attempt fails.
39 *
40 * NOTE: The test seems largely useless right now, as we simply NEVER
41 * switch addresses under the test conditions. However, it may be a
42 * good starting point for a future test. For now, it always times
43 * out and returns "77" (skipped), so we set the timeout suitably low.
44 */
45#include "platform.h"
46#include "gnunet_transport_service.h"
47#include "gnunet_ats_service.h"
48#include "transport-testing.h"
49
50
51/**
52 * Testcase timeout (set aggressively as we know this test doesn't work right now)
53 */
54#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
55
56
57static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
58
59static struct GNUNET_SCHEDULER_Task *measure_task;
60
61
62/**
63 * Statistics we track per peer.
64 */
65struct PeerStats
66{
67 struct GNUNET_STATISTICS_Handle *stat;
68
69 unsigned int addresses_avail;
70
71 unsigned int switch_attempts;
72
73 unsigned int switch_success;
74
75 unsigned int switch_fail;
76};
77
78static struct PeerStats stats[2];
79
80/* Amount of data transferred since last switch attempt */
81static unsigned long long bytes_sent_after_switch;
82
83static unsigned long long bytes_recv_after_switch;
84
85
86static int
87stat_start_attempt_cb (void *cls,
88 const char *subsystem,
89 const char *name,
90 uint64_t value,
91 int is_persistent)
92{
93 struct PeerStats *stat = cls;
94
95 stat->switch_attempts++;
96 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Switch attempted (%p)", stat);
97 bytes_recv_after_switch = 0;
98 bytes_sent_after_switch = 0;
99
100 return GNUNET_OK;
101}
102
103
104static int
105stat_success_attempt_cb (void *cls,
106 const char *subsystem,
107 const char *name,
108 uint64_t value,
109 int is_persistent)
110{
111 struct PeerStats *stat = cls;
112
113 stat->switch_success++;
114 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Switch succeeded (%p)", stat);
115 return GNUNET_OK;
116}
117
118
119static int
120stat_fail_attempt_cb (void *cls,
121 const char *subsystem,
122 const char *name,
123 uint64_t value,
124 int is_persistent)
125{
126 struct PeerStats *stat = cls;
127
128 if (value == 0)
129 return GNUNET_OK;
130
131 stat->switch_fail++;
132 GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Switch failed (%p)", stat);
133 return GNUNET_OK;
134}
135
136
137static int
138stat_addresses_available (void *cls,
139 const char *subsystem,
140 const char *name,
141 uint64_t value,
142 int is_persistent)
143{
144 struct PeerStats *stat = cls;
145
146 stat->addresses_avail++;
147 return GNUNET_OK;
148}
149
150
151/**
152 * List of statistics entries we care about.
153 */
154static struct WatchEntry
155{
156 /**
157 * Name of the statistic we watch.
158 */
159 const char *stat_name;
160
161 /**
162 * Handler to register;
163 */
164 GNUNET_STATISTICS_Iterator stat_handler;
165} watches[] =
166{ { "# Attempts to switch addresses", &stat_start_attempt_cb },
167 { "# Successful attempts to switch addresses", &stat_success_attempt_cb },
168 { "# Failed attempts to switch addresses (failed to send CONNECT CONT)",
169 &stat_fail_attempt_cb },
170 { "# Failed attempts to switch addresses (failed to send CONNECT)",
171 &stat_fail_attempt_cb },
172 { "# Failed attempts to switch addresses (no response)",
173 &stat_fail_attempt_cb },
174 { "# transport addresses", &stat_addresses_available },
175 { NULL, NULL } };
176
177
178static void
179custom_shutdown (void *cls)
180{
181 int result;
182
183 if (NULL != measure_task)
184 {
185 GNUNET_SCHEDULER_cancel (measure_task);
186 measure_task = NULL;
187 }
188 if (0 == stats[0].switch_attempts + stats[1].switch_attempts)
189 {
190 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
191 "Test did not work, as peers didn't switch (flawed testcase)!\n");
192 ccc->global_ret = 77;
193 }
194 else
195 {
196 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
197 "Fail (timeout)! No transmission after switch! Stopping peers\n");
198 ccc->global_ret = 77; /* GNUNET_SYSERR; */
199 }
200
201 /* stop statistics */
202 for (unsigned int i = 0; i < 2; i++)
203 {
204 if (NULL != stats[i].stat)
205 {
206 for (unsigned int j = 0; NULL != watches[j].stat_name; j++)
207 GNUNET_assert (GNUNET_OK ==
208 GNUNET_STATISTICS_watch_cancel (stats[i].stat,
209 "transport",
210 watches[j].stat_name,
211 watches[j].stat_handler,
212 &stats[i]));
213 GNUNET_STATISTICS_destroy (stats[i].stat, GNUNET_NO);
214 stats[i].stat = NULL;
215 }
216 }
217
218 result = 0;
219 fprintf (stderr, "\n");
220 if (stats[0].switch_attempts > 0)
221 {
222 fprintf (
223 stderr,
224 "Peer 1 tried %u times to switch and succeeded %u times, failed %u times\n",
225 stats[0].switch_attempts,
226 stats[0].switch_success,
227 stats[0].switch_fail);
228 if (stats[0].switch_success != stats[0].switch_attempts)
229 {
230 GNUNET_break (0);
231 result++;
232 }
233 }
234 else if (stats[0].addresses_avail > 1)
235 {
236 fprintf (stderr,
237 "Peer 1 had %u addresses available, but did not try to switch\n",
238 stats[0].addresses_avail);
239 }
240 if (stats[1].switch_attempts > 0)
241 {
242 fprintf (
243 stderr,
244 "Peer 2 tried %u times to switch and succeeded %u times, failed %u times\n",
245 stats[1].switch_attempts,
246 stats[1].switch_success,
247 stats[1].switch_fail);
248 if (stats[1].switch_success != stats[1].switch_attempts)
249 {
250 GNUNET_break (0);
251 result++;
252 }
253 }
254 else if (stats[1].addresses_avail > 1)
255 {
256 fprintf (stderr,
257 "Peer 2 had %u addresses available, but did not try to switch\n",
258 stats[1].addresses_avail);
259 }
260
261 if (((stats[0].switch_attempts > 0) || (stats[1].switch_attempts > 0)) &&
262 (bytes_sent_after_switch == 0))
263 {
264 fprintf (stderr, "No data sent after switching!\n");
265 GNUNET_break (0);
266 result++;
267 }
268 if (((stats[0].switch_attempts > 0) || (stats[1].switch_attempts > 0)) &&
269 (bytes_recv_after_switch == 0))
270 {
271 fprintf (stderr, "No data received after switching!\n");
272 GNUNET_break (0);
273 result++;
274 }
275#if 0
276 /* This test is not really expected to pass right now... */
277 if (0 != result)
278 ccc->global_ret = GNUNET_SYSERR;
279#endif
280}
281
282
283static void
284notify_receive (void *cls,
285 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
286 const struct GNUNET_PeerIdentity *sender,
287 const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr)
288{
289 if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
290 return;
291
292 {
293 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
294
295 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
296 "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
297 receiver->no,
298 ps,
299 (uint32_t) ntohl (hdr->num),
300 ntohs (hdr->header.size),
301 GNUNET_i2s (sender));
302 GNUNET_free (ps);
303 }
304 if (((stats[0].switch_attempts >= 1) || (stats[1].switch_attempts >= 1)) &&
305 (stats[0].switch_attempts ==
306 stats[0].switch_fail + stats[0].switch_success) &&
307 (stats[1].switch_attempts ==
308 stats[1].switch_fail + stats[1].switch_success))
309 {
310 bytes_recv_after_switch += ntohs (hdr->header.size);
311 if ((bytes_sent_after_switch > 0) && (bytes_recv_after_switch > 0))
312 {
313 /* A peer switched addresses and sent and received data after the
314 * switch operations */
315 GNUNET_SCHEDULER_shutdown ();
316 }
317 }
318}
319
320
321static void
322notify_send (void *cls)
323{
324 static uint32_t cnt;
325
326 GNUNET_assert (
327 GNUNET_OK ==
328 GNUNET_TRANSPORT_TESTING_send (ccc->p[1],
329 ccc->p[0],
330 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
331 GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE,
332 ++cnt,
333 &notify_send,
334 NULL));
335 if (((stats[0].switch_attempts >= 1) || (stats[1].switch_attempts >= 1)) &&
336 (stats[0].switch_attempts ==
337 stats[0].switch_fail + stats[0].switch_success) &&
338 (stats[1].switch_attempts ==
339 stats[1].switch_fail + stats[1].switch_success))
340 {
341 bytes_sent_after_switch += GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE;
342 }
343}
344
345
346static void
347progress_indicator (void *cls)
348{
349 static int counter;
350
351 measure_task = NULL;
352 counter++;
353 if ((TIMEOUT.rel_value_us / 1000 / 1000LL) < counter)
354 {
355 fprintf (stderr, "%s", ".\n");
356 }
357 else
358 {
359 fprintf (stderr, "%s", ".");
360 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
361 &progress_indicator,
362 NULL);
363 }
364}
365
366
367static void
368connected_cb (void *cls)
369{
370 for (unsigned int i = 0; i < 2; i++)
371 {
372 stats[i].stat = GNUNET_STATISTICS_create ("transport", ccc->p[i]->cfg);
373 if (NULL == stats[i].stat)
374 {
375 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
376 "Fail! Could not create statistics for peers!\n");
377 ccc->global_ret = GNUNET_SYSERR;
378 GNUNET_SCHEDULER_shutdown ();
379 return;
380 }
381 for (unsigned int j = 0; NULL != watches[j].stat_name; j++)
382 {
383 GNUNET_STATISTICS_watch (stats[i].stat,
384 "transport",
385 watches[j].stat_name,
386 watches[j].stat_handler,
387 &stats[i]);
388 }
389 }
390 /* Show progress */
391 ccc->global_ret = GNUNET_OK;
392 measure_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
393 &progress_indicator,
394 NULL);
395 /* Peers are connected, start transmit test messages */
396 GNUNET_assert (
397 GNUNET_OK ==
398 GNUNET_TRANSPORT_TESTING_send (ccc->p[1],
399 ccc->p[0],
400 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
401 GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE,
402 0,
403 &notify_send,
404 NULL));
405}
406
407
408int
409main (int argc, char *argv[])
410{
411 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc =
412 { .connect_continuation = &connected_cb,
413 .config_file = "test_transport_api_data.conf",
414 .rec = &notify_receive,
415 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
416 .shutdown_task = &custom_shutdown,
417 .timeout = TIMEOUT };
418
419 ccc = &my_ccc;
420 int ret;
421
422 ret = GNUNET_TRANSPORT_TESTING_main (2,
423 &GNUNET_TRANSPORT_TESTING_connect_check,
424 ccc);
425 if (77 == ret)
426 return 77;
427 if (GNUNET_OK != ret)
428 return 1;
429 return 0;
430}
431
432
433/* end of test_transport_address_switch.c */
diff --git a/src/transport/test_transport_address_switch_http_peer1.conf b/src/transport/test_transport_address_switch_http_peer1.conf
deleted file mode 100644
index b48c5f47f..000000000
--- a/src/transport/test_transport_address_switch_http_peer1.conf
+++ /dev/null
@@ -1,26 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[transport]
25PLUGINS = http_server http_client
26
diff --git a/src/transport/test_transport_address_switch_http_peer2.conf b/src/transport/test_transport_address_switch_http_peer2.conf
deleted file mode 100644
index be8fb506c..000000000
--- a/src/transport/test_transport_address_switch_http_peer2.conf
+++ /dev/null
@@ -1,26 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[transport]
25PLUGINS = http_client http_server
26
diff --git a/src/transport/test_transport_address_switch_https_peer1.conf b/src/transport/test_transport_address_switch_https_peer1.conf
deleted file mode 100644
index 1f9210130..000000000
--- a/src/transport/test_transport_address_switch_https_peer1.conf
+++ /dev/null
@@ -1,44 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[arm]
25PORT = 12005
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
27
28[statistics]
29PORT = 12004
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
31
32[resolver]
33PORT = 12003
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
35
36[peerinfo]
37PORT = 12002
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
39
40[transport]
41PORT = 12001
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
43PLUGINS = https_client https_server
44
diff --git a/src/transport/test_transport_address_switch_https_peer2.conf b/src/transport/test_transport_address_switch_https_peer2.conf
deleted file mode 100644
index c58839868..000000000
--- a/src/transport/test_transport_address_switch_https_peer2.conf
+++ /dev/null
@@ -1,44 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[arm]
25PORT = 12014
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
27
28[statistics]
29PORT = 12013
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
31
32[resolver]
33PORT = 12012
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
35
36[peerinfo]
37PORT = 12011
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
39
40[transport]
41PORT = 12010
42PLUGINS = https_client https_server
43UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
44
diff --git a/src/transport/test_transport_address_switch_tcp_peer1.conf b/src/transport/test_transport_address_switch_tcp_peer1.conf
deleted file mode 100644
index cfcbfe41c..000000000
--- a/src/transport/test_transport_address_switch_tcp_peer1.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[transport-tcp]
25PORT = 12000
26TIMEOUT = 5 s
27
28[arm]
29PORT = 12005
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
31
32[statistics]
33PORT = 12004
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
35
36[resolver]
37PORT = 12003
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
39
40[peerinfo]
41PORT = 12002
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
43
44[transport]
45PORT = 12001
46UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
47PLUGINS = tcp
48
diff --git a/src/transport/test_transport_address_switch_tcp_peer2.conf b/src/transport/test_transport_address_switch_tcp_peer2.conf
deleted file mode 100644
index bda2354b6..000000000
--- a/src/transport/test_transport_address_switch_tcp_peer2.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[transport-tcp]
25PORT = 12015
26TIMEOUT = 5 s
27
28[arm]
29PORT = 12014
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
31
32[statistics]
33PORT = 12013
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
35
36[resolver]
37PORT = 12012
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
39
40[peerinfo]
41PORT = 12011
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
43
44[transport]
45PORT = 12010
46PLUGINS = tcp
47UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
48
diff --git a/src/transport/test_transport_address_switch_udp_peer1.conf b/src/transport/test_transport_address_switch_udp_peer1.conf
deleted file mode 100644
index bdc3a2253..000000000
--- a/src/transport/test_transport_address_switch_udp_peer1.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[transport-tcp]
25PORT = 12000
26TIMEOUT = 5 s
27
28[arm]
29PORT = 12005
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
31
32[statistics]
33PORT = 12004
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
35
36[resolver]
37PORT = 12003
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
39
40[peerinfo]
41PORT = 12002
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
43
44[transport]
45PORT = 12001
46UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
47PLUGINS = udp
48
diff --git a/src/transport/test_transport_address_switch_udp_peer2.conf b/src/transport/test_transport_address_switch_udp_peer2.conf
deleted file mode 100644
index ae6397db4..000000000
--- a/src/transport/test_transport_address_switch_udp_peer2.conf
+++ /dev/null
@@ -1,48 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[ats]
6UNSPECIFIED_QUOTA_IN = 8 KiB
7UNSPECIFIED_QUOTA_OUT = 8 KiB
8# LOOPBACK
9LOOPBACK_QUOTA_IN = 8 KiB
10LOOPBACK_QUOTA_OUT = 8 KiB
11# LAN
12LAN_QUOTA_IN = 8 KiB
13LAN_QUOTA_OUT = 8 KiB
14# WAN
15WAN_QUOTA_IN = 8 KiB
16WAN_QUOTA_OUT = 8 KiB
17# WLAN
18WLAN_QUOTA_IN = 8 KiB
19WLAN_QUOTA_OUT = 8 KiB
20# BLUETOOTH
21BLUETOOTH_QUOTA_IN = 8 KiB
22BLUETOOTH_QUOTA_OUT = 8 KiB
23
24[transport-tcp]
25PORT = 12015
26TIMEOUT = 5 s
27
28[arm]
29PORT = 12014
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
31
32[statistics]
33PORT = 12013
34UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
35
36[resolver]
37PORT = 12012
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
39
40[peerinfo]
41PORT = 12011
42UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
43
44[transport]
45PORT = 12010
46PLUGINS = udp
47UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
48
diff --git a/src/transport/test_transport_api.c b/src/transport/test_transport_api.c
deleted file mode 100644
index 5f5e03a9e..000000000
--- a/src/transport/test_transport_api.c
+++ /dev/null
@@ -1,126 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api.c
22 * @brief base test case for transport implementations
23 * @author Christian Grothoff
24 *
25 * This test case serves as a base for tcp, udp, and udp-nat
26 * transport test cases. Based on the executable being run
27 * the correct test case will be performed. Conservation of
28 * C code apparently.
29 */
30#include "platform.h"
31#include "gnunet_transport_service.h"
32#include "transport-testing.h"
33
34/**
35 * How long until we give up on transmitting the message?
36 */
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38
39static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
40
41
42static void
43notify_receive (void *cls,
44 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
45 const struct GNUNET_PeerIdentity *sender,
46 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
47{
48 {
49 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
50
51 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
52 "Peer %u (`%s') received message of type %d and size %u size from peer %s!\n",
53 receiver->no,
54 ps,
55 ntohs (message->header.type),
56 ntohs (message->header.size),
57 GNUNET_i2s (sender));
58 GNUNET_free (ps);
59 }
60
61 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE == ntohs (message->header.type)) &&
62 (GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE == ntohs (
63 message->header.size)))
64 {
65 ccc->global_ret = GNUNET_OK;
66 GNUNET_SCHEDULER_shutdown ();
67 }
68 else
69 {
70 GNUNET_break (0);
71 ccc->global_ret = GNUNET_SYSERR;
72 GNUNET_SCHEDULER_shutdown ();
73 }
74}
75
76
77/**
78 * Runs the test.
79 *
80 * @param argv the argv argument from main()
81 * @param bi_directional should we try to establish connections
82 * in both directions simultaneously?
83 */
84static int
85test (char *argv[],
86 int bi_directional)
87{
88 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
89 .num_messages = 1
90 };
91 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
92 .connect_continuation = &GNUNET_TRANSPORT_TESTING_large_send,
93 .connect_continuation_cls = &sc,
94 .config_file = "test_transport_api_data.conf",
95 .rec = &notify_receive,
96 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
97 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
98 .timeout = TIMEOUT,
99 .bi_directional = bi_directional
100 };
101
102 ccc = &my_ccc;
103 sc.ccc = ccc;
104 if (GNUNET_OK !=
105 GNUNET_TRANSPORT_TESTING_main (2,
106 &GNUNET_TRANSPORT_TESTING_connect_check,
107 ccc))
108 return 1;
109 return 0;
110}
111
112
113int
114main (int argc,
115 char *argv[])
116{
117 if ((0 != test (argv,
118 GNUNET_NO)) ||
119 (0 != test (argv,
120 GNUNET_YES)))
121 return 1;
122 return 0;
123}
124
125
126/* end of test_transport_api.c */
diff --git a/src/transport/test_transport_api2.c b/src/transport/test_transport_api2.c
deleted file mode 100644
index e1606e0be..000000000
--- a/src/transport/test_transport_api2.c
+++ /dev/null
@@ -1,126 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api.c
22 * @brief base test case for transport implementations
23 * @author Christian Grothoff
24 *
25 * This test case serves as a base for tcp, udp, and udp-nat
26 * transport test cases. Based on the executable being run
27 * the correct test case will be performed. Conservation of
28 * C code apparently.
29 */
30#include "platform.h"
31//#include "gnunet_transport_service.h"
32#include "transport-testing2.h"
33
34/**
35 * How long until we give up on transmitting the message?
36 */
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38
39static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
40
41
42static void
43notify_receive (void *cls,
44 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
45 const struct GNUNET_PeerIdentity *sender,
46 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
47{
48 {
49 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
50
51 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
52 "Peer %u (`%s') received message of type %d and size %u size from peer %s!\n",
53 receiver->no,
54 ps,
55 ntohs (message->header.type),
56 ntohs (message->header.size),
57 GNUNET_i2s (sender));
58 GNUNET_free (ps);
59 }
60
61 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE == ntohs (message->header.type)) &&
62 (GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE == ntohs (
63 message->header.size)))
64 {
65 ccc->global_ret = GNUNET_OK;
66 GNUNET_SCHEDULER_shutdown ();
67 }
68 else
69 {
70 GNUNET_break (0);
71 ccc->global_ret = GNUNET_SYSERR;
72 GNUNET_SCHEDULER_shutdown ();
73 }
74}
75
76
77/**
78 * Runs the test.
79 *
80 * @param argv the argv argument from main()
81 * @param bi_directional should we try to establish connections
82 * in both directions simultaneously?
83 */
84static int
85test (char *argv[],
86 int bi_directional)
87{
88 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
89 .num_messages = 1
90 };
91 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
92 .connect_continuation = &GNUNET_TRANSPORT_TESTING_large_send,
93 .connect_continuation_cls = &sc,
94 .config_file = "test_transport_api_data.conf",
95 .rec = &notify_receive,
96 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
97 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
98 .timeout = TIMEOUT,
99 .bi_directional = bi_directional
100 };
101
102 ccc = &my_ccc;
103 sc.ccc = ccc;
104 if (GNUNET_OK !=
105 GNUNET_TRANSPORT_TESTING_main (2,
106 &GNUNET_TRANSPORT_TESTING_connect_check,
107 ccc))
108 return 1;
109 return 0;
110}
111
112
113int
114main (int argc,
115 char *argv[])
116{
117 if ((0 != test (argv,
118 GNUNET_NO)) ||
119 (0 != test (argv,
120 GNUNET_YES)))
121 return 1;
122 return 0;
123}
124
125
126/* end of test_transport_api.c */
diff --git a/src/transport/test_transport_api2_tcp_node1.conf b/src/transport/test_transport_api2_tcp_node1.conf
deleted file mode 100644
index b8a743a3b..000000000
--- a/src/transport/test_transport_api2_tcp_node1.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6BINARY = gnunet-service-tng
7PLUGINS = tcp
8#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=/tmp/vg_peer1-%p
9UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p1.sock
10
11[communicator-tcp]
12BINARY = gnunet-communicator-tcp
13BINDTO = 192.168.15.1:60002
14DISABLE_V6 = YES
15IMMEDIATE_START = YES
16UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p1.sock
17#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=/tmp/vg_ctpeer1-%p
18#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
19
20[communicator-udp]
21#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=/tmp/vg_cupeer1-%p
22BINARY = gnunet-communicator-udp
23BINDTO = 192.168.15.1:60002
24DISABLE_V6 = YES
25IMMEDIATE_START = YES
26UNIXPATH = $GNUNET_RUNTIME_DIR/udp-comm-p1.sock
27
28[peerstore]
29IMMEDIATE_START = YES
30
31#[transport]
32#PREFIX = valgrind
diff --git a/src/transport/test_transport_api2_tcp_node2.conf b/src/transport/test_transport_api2_tcp_node2.conf
deleted file mode 100644
index f94368b3f..000000000
--- a/src/transport/test_transport_api2_tcp_node2.conf
+++ /dev/null
@@ -1,22 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6BINARY = gnunet-service-tng
7#PREFIX = valgrind --log-file=/tmp/vg_peer2-%p
8UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p2.sock
9
10[communicator-tcp]
11BINARY = gnunet-communicator-tcp
12BINDTO = 192.168.15.2:60003
13DISABLE_V6 = YES
14IMMEDIATE_START = YES
15#PREFIX = valgrind --log-file=/tmp/vg_comm2-%p
16UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p2.sock
17
18[peerstore]
19IMMEDIATE_START = YES
20
21#[transport]
22#PREFIX = valgrind
diff --git a/src/transport/test_transport_api2_tcp_peer1.conf b/src/transport/test_transport_api2_tcp_peer1.conf
deleted file mode 100644
index 745ed6887..000000000
--- a/src/transport/test_transport_api2_tcp_peer1.conf
+++ /dev/null
@@ -1,23 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6BINARY = gnunet-service-tng
7PLUGINS = tcp
8#PREFIX = valgrind --log-file=/tmp/vg_peer1-%p
9UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p1.sock
10
11[communicator-tcp]
12BINARY = gnunet-communicator-tcp
13BINDTO = 60002
14DISABLE_V6 = YES
15IMMEDIATE_START = YES
16UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p1.sock
17#PREFIX = valgrind --log-file=/tmp/vg_cpeer1-%p
18
19[peerstore]
20IMMEDIATE_START = YES
21
22#[transport]
23#PREFIX = valgrind
diff --git a/src/transport/test_transport_api2_tcp_peer2.conf b/src/transport/test_transport_api2_tcp_peer2.conf
deleted file mode 100644
index 022468bcd..000000000
--- a/src/transport/test_transport_api2_tcp_peer2.conf
+++ /dev/null
@@ -1,22 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6BINARY = gnunet-service-tng
7#PREFIX = valgrind --log-file=/tmp/vg_peer2-%p
8UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p2.sock
9
10[communicator-tcp]
11BINARY = gnunet-communicator-tcp
12BINDTO = 60003
13DISABLE_V6 = YES
14IMMEDIATE_START = YES
15#PREFIX = valgrind --log-file=/tmp/vg_comm2-%p
16UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p2.sock
17
18[peerstore]
19IMMEDIATE_START = YES
20
21#[transport]
22#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_blacklisting.c b/src/transport/test_transport_api_blacklisting.c
deleted file mode 100644
index 2ba88a863..000000000
--- a/src/transport/test_transport_api_blacklisting.c
+++ /dev/null
@@ -1,206 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/test_transport_api_blacklisting.c
23 * @brief test for the blacklisting API
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#include "platform.h"
28#include "gnunet_transport_service.h"
29#include "transport-testing.h"
30
31#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
32
33static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
34
35static int connected;
36
37static int blacklist_request_p1;
38
39static int blacklist_request_p2;
40
41static struct GNUNET_TRANSPORT_Blacklist *blacklist_p1;
42
43static struct GNUNET_TRANSPORT_Blacklist *blacklist_p2;
44
45static struct GNUNET_SCHEDULER_Task *shutdown_task;
46
47
48static void
49end (void *cls)
50{
51 shutdown_task = NULL;
52 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
53 "Stopping\n");
54 if ((GNUNET_YES == blacklist_request_p1) &&
55 (GNUNET_YES == blacklist_request_p2) &&
56 (GNUNET_NO == connected))
57 {
58 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
59 "Peers were never connected, success\n");
60 ccc->global_ret = GNUNET_OK;
61 }
62 else
63 {
64 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
65 "Peers were not connected, fail\n");
66 ccc->global_ret = GNUNET_SYSERR;
67 }
68 GNUNET_SCHEDULER_shutdown ();
69}
70
71
72static void
73custom_shutdown (void *cls)
74{
75 if (NULL != shutdown_task)
76 {
77 GNUNET_SCHEDULER_cancel (shutdown_task);
78 shutdown_task = NULL;
79 }
80 if (NULL != blacklist_p1)
81 {
82 GNUNET_TRANSPORT_blacklist_cancel (blacklist_p1);
83 blacklist_p1 = NULL;
84 }
85 if (NULL != blacklist_p2)
86 {
87 GNUNET_TRANSPORT_blacklist_cancel (blacklist_p2);
88 blacklist_p2 = NULL;
89 }
90}
91
92
93static void
94notify_receive (void *cls,
95 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
96 const struct GNUNET_PeerIdentity *sender,
97 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
98{
99 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
100 "Unexpectedly even received the message despite blacklist\n");
101 connected = GNUNET_YES;
102 GNUNET_SCHEDULER_cancel (shutdown_task);
103 end (NULL);
104}
105
106
107static void
108notify_connect (void *cls,
109 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
110 const struct GNUNET_PeerIdentity *other)
111{
112 GNUNET_TRANSPORT_TESTING_log_connect (cls,
113 me,
114 other);
115 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
116 "Peers connected despite blacklist!\n");
117 connected = GNUNET_YES; /* this test now failed */
118 GNUNET_SCHEDULER_cancel (shutdown_task);
119 end (NULL);
120}
121
122
123static int
124blacklist_cb (void *cls,
125 const struct GNUNET_PeerIdentity *pid)
126{
127 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
128 int res = GNUNET_SYSERR;
129
130 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
131 "Peer %u: Blacklist request for peer `%s'\n",
132 p->no,
133 GNUNET_i2s (pid));
134
135 if (p == ccc->p[0])
136 {
137 blacklist_request_p1 = GNUNET_YES;
138 res = GNUNET_OK;
139 }
140 if (p == ccc->p[1])
141 {
142 blacklist_request_p2 = GNUNET_YES;
143 res = GNUNET_SYSERR;
144 }
145
146 if ((GNUNET_YES == blacklist_request_p2) &&
147 (GNUNET_YES == blacklist_request_p1) &&
148 (NULL == shutdown_task))
149 {
150 shutdown_task
151 = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply (
152 GNUNET_TIME_UNIT_SECONDS, 3),
153 &end,
154 NULL);
155 }
156 return res;
157}
158
159
160static void
161start_blacklist (void *cls)
162{
163 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
164 "Starting blacklists\n");
165 blacklist_p1 = GNUNET_TRANSPORT_blacklist (ccc->p[0]->cfg,
166 &blacklist_cb,
167 ccc->p[0]);
168 GNUNET_assert (NULL != blacklist_p1);
169 blacklist_p2 = GNUNET_TRANSPORT_blacklist (ccc->p[1]->cfg,
170 &blacklist_cb,
171 ccc->p[1]);
172 GNUNET_assert (NULL != blacklist_p2);
173}
174
175
176int
177main (int argc,
178 char *argv[])
179{
180 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
181 .num_messages = 1
182 };
183 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
184 .pre_connect_task = &start_blacklist,
185 .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
186 .connect_continuation_cls = &sc,
187 .config_file = "test_transport_api_data.conf",
188 .rec = &notify_receive,
189 .nc = &notify_connect,
190 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
191 .shutdown_task = &custom_shutdown,
192 .timeout = TIMEOUT,
193 .bi_directional = GNUNET_YES
194 };
195
196 ccc = &my_ccc;
197 if (GNUNET_OK !=
198 GNUNET_TRANSPORT_TESTING_main (2,
199 &GNUNET_TRANSPORT_TESTING_connect_check,
200 ccc))
201 return 1;
202 return 0;
203}
204
205
206/* end of transport_api_blacklisting.c */
diff --git a/src/transport/test_transport_api_blacklisting_tcp_peer1.conf b/src/transport/test_transport_api_blacklisting_tcp_peer1.conf
deleted file mode 100644
index eabd6b701..000000000
--- a/src/transport/test_transport_api_blacklisting_tcp_peer1.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_blacklisting_tcp_peer2.conf b/src/transport/test_transport_api_blacklisting_tcp_peer2.conf
deleted file mode 100644
index 58ce0777f..000000000
--- a/src/transport/test_transport_api_blacklisting_tcp_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_bluetooth_peer1.conf b/src/transport/test_transport_api_bluetooth_peer1.conf
deleted file mode 100644
index b1209e44b..000000000
--- a/src/transport/test_transport_api_bluetooth_peer1.conf
+++ /dev/null
@@ -1,10 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[transport]
10PLUGINS = bluetooth
diff --git a/src/transport/test_transport_api_bluetooth_peer2.conf b/src/transport/test_transport_api_bluetooth_peer2.conf
deleted file mode 100644
index 371a5d3b0..000000000
--- a/src/transport/test_transport_api_bluetooth_peer2.conf
+++ /dev/null
@@ -1,10 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[transport]
10PLUGINS = bluetooth
diff --git a/src/transport/test_transport_api_data.conf b/src/transport/test_transport_api_data.conf
deleted file mode 100644
index c06235a0a..000000000
--- a/src/transport/test_transport_api_data.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ test_transport_defaults.conf
2[PATHS]
3
4[transport-tcp]
5PORT = 52094
6
7[transport-udp]
8PORT = 52094
9
diff --git a/src/transport/test_transport_api_disconnect.c b/src/transport/test_transport_api_disconnect.c
deleted file mode 100644
index c469f28bc..000000000
--- a/src/transport/test_transport_api_disconnect.c
+++ /dev/null
@@ -1,134 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_disconnect.c
22 * @brief base test case for transport implementations
23 *
24 * This test case tests disconnect notifications in peer shutdown.
25 * Starts two peers, has them connect, sends a message in between,
26 * stops one peer, expects the others to send a disconnect notification.
27 */
28#include "platform.h"
29#include "gnunet_transport_service.h"
30#include "transport-testing.h"
31
32/**
33 * How long until we give up on transmitting the message?
34 */
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
36
37
38static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
39
40static int shutdown_;
41
42
43static void
44notify_disconnect (void *cls,
45 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
46 const struct GNUNET_PeerIdentity *other)
47{
48 if (me != ccc->p[0])
49 return;
50 GNUNET_TRANSPORT_TESTING_log_disconnect (cls,
51 me,
52 other);
53 if (GNUNET_YES == shutdown_)
54 {
55 ccc->global_ret = GNUNET_OK;
56 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
57 "Test good, shutting down...\n");
58 GNUNET_SCHEDULER_shutdown ();
59 }
60}
61
62
63static void
64stop_peer (void *cls)
65{
66 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
67 "Shutting down peer %u (`%s')\n",
68 ccc->p[1]->no,
69 GNUNET_i2s (&ccc->p[1]->id));
70 shutdown_ = GNUNET_YES;
71 GNUNET_TRANSPORT_TESTING_stop_peer (ccc->p[1]);
72 ccc->p[1] = NULL;
73}
74
75
76static void
77notify_receive (void *cls,
78 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
79 const struct GNUNET_PeerIdentity *sender,
80 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
81{
82 {
83 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
84
85 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
86 "Peer %u (`%s') received message of type %d and size %u size from peer %s!\n",
87 receiver->no,
88 ps,
89 ntohs (message->header.type),
90 ntohs (message->header.size),
91 GNUNET_i2s (sender));
92 GNUNET_free (ps);
93 }
94 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE == ntohs (message->header.type)) &&
95 (sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage) == ntohs (
96 message->header.size)))
97 {
98 GNUNET_SCHEDULER_add_now (&stop_peer,
99 NULL);
100 return;
101 }
102}
103
104
105int
106main (int argc,
107 char *argv[])
108{
109 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
110 .num_messages = 1
111 };
112 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
113 .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
114 .connect_continuation_cls = &sc,
115 .config_file = "test_transport_api_data.conf",
116 .rec = &notify_receive,
117 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
118 .nd = &notify_disconnect,
119 .timeout = TIMEOUT,
120 .global_ret = GNUNET_SYSERR
121 };
122
123 ccc = &my_ccc;
124 sc.ccc = ccc;
125 if (GNUNET_OK !=
126 GNUNET_TRANSPORT_TESTING_main (2,
127 &GNUNET_TRANSPORT_TESTING_connect_check,
128 ccc))
129 return 1;
130 return 0;
131}
132
133
134/* end of test_transport_api_disconnect.c */
diff --git a/src/transport/test_transport_api_disconnect_tcp_peer1.conf b/src/transport/test_transport_api_disconnect_tcp_peer1.conf
deleted file mode 100644
index 8530ba310..000000000
--- a/src/transport/test_transport_api_disconnect_tcp_peer1.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
diff --git a/src/transport/test_transport_api_disconnect_tcp_peer2.conf b/src/transport/test_transport_api_disconnect_tcp_peer2.conf
deleted file mode 100644
index ce9c2f885..000000000
--- a/src/transport/test_transport_api_disconnect_tcp_peer2.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8
diff --git a/src/transport/test_transport_api_http_peer1.conf b/src/transport/test_transport_api_http_peer1.conf
deleted file mode 100644
index 2a622ae02..000000000
--- a/src/transport/test_transport_api_http_peer1.conf
+++ /dev/null
@@ -1,6 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p1/
4
5[transport]
6PLUGINS = http_client
diff --git a/src/transport/test_transport_api_http_peer2.conf b/src/transport/test_transport_api_http_peer2.conf
deleted file mode 100644
index aca41804b..000000000
--- a/src/transport/test_transport_api_http_peer2.conf
+++ /dev/null
@@ -1,6 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p2/
4
5[transport]
6PLUGINS = http_server
diff --git a/src/transport/test_transport_api_http_reverse_peer1.conf b/src/transport/test_transport_api_http_reverse_peer1.conf
deleted file mode 100644
index 67640d7bb..000000000
--- a/src/transport/test_transport_api_http_reverse_peer1.conf
+++ /dev/null
@@ -1,11 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p1/
4
5[transport]
6PLUGINS = http_client
7
8[ats]
9WAN_QUOTA_IN = unlimited
10WAN_QUOTA_OUT = unlimited
11
diff --git a/src/transport/test_transport_api_http_reverse_peer2.conf b/src/transport/test_transport_api_http_reverse_peer2.conf
deleted file mode 100644
index 0e7a2ea05..000000000
--- a/src/transport/test_transport_api_http_reverse_peer2.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p2/
4
5[transport-http_server]
6PORT = 8080
7EXTERNAL_HOSTNAME = fulcrum.net.in.tum.de/gnunet
8EXTERNAL_HOSTNAME_ONLY = YES
9
10[transport]
11PLUGINS = http_server
12
diff --git a/src/transport/test_transport_api_https_peer1.conf b/src/transport/test_transport_api_https_peer1.conf
deleted file mode 100644
index 55d119259..000000000
--- a/src/transport/test_transport_api_https_peer1.conf
+++ /dev/null
@@ -1,26 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p1/
4
5[arm]
6PORT = 12105
7
8[statistics]
9PORT = 12104
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
11
12[resolver]
13PORT = 12103
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
15
16[peerinfo]
17PORT = 12102
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
19
20[transport]
21PORT = 12101
22PLUGINS = https_client
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
24#PREFIX = valgrind
25
26
diff --git a/src/transport/test_transport_api_https_peer2.conf b/src/transport/test_transport_api_https_peer2.conf
deleted file mode 100644
index 3b1d55b0a..000000000
--- a/src/transport/test_transport_api_https_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p2/
4
5[transport-https_server]
6EXTERNAL_HOSTNAME = localhost
7EXTERNAL_HOSTNAME_ONLY = yes
8EXTERNAL_HOSTNAME_USE_PORT = YES
9
10[arm]
11PORT = 12115
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12114
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12113
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12112
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12111
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30#PREFIX = valgrind
31
32
diff --git a/src/transport/test_transport_api_limited_sockets.c b/src/transport/test_transport_api_limited_sockets.c
deleted file mode 100644
index 0e47800e8..000000000
--- a/src/transport/test_transport_api_limited_sockets.c
+++ /dev/null
@@ -1,132 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_limited_sockets.c
22 * @brief base test case for transport implementations
23 *
24 * This test case serves as a base for tcp, udp, and udp-nat
25 * transport test cases. Based on the executable being run
26 * the correct test case will be performed. Conservation of
27 * C code apparently.
28 */
29#include "platform.h"
30#include "gnunet_transport_service.h"
31#include "transport-testing.h"
32
33/**
34 * How long until we give up on transmitting the message?
35 */
36#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
37
38#define MAX_FILES 50
39
40
41#if HAVE_SETRLIMIT
42
43static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
44
45
46static void
47notify_receive (void *cls,
48 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
49 const struct GNUNET_PeerIdentity *sender,
50 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
51{
52 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
53 "Received message of type %d from peer %s!\n",
54 ntohs (message->header.type),
55 GNUNET_i2s (sender));
56 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE ==
57 ntohs (message->header.type)) &&
58 (sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage) ==
59 ntohs (message->header.size)))
60 {
61 ccc->global_ret = GNUNET_OK;
62 }
63 else
64 {
65 GNUNET_break (0);
66 }
67 GNUNET_SCHEDULER_shutdown ();
68}
69
70
71int
72main (int argc, char *argv[])
73{
74 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
75 .num_messages = 1
76 };
77 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
78 .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
79 .connect_continuation_cls = &sc,
80 .config_file = "test_transport_api_data.conf",
81 .rec = &notify_receive,
82 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
83 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
84 .timeout = TIMEOUT,
85 .global_ret = GNUNET_SYSERR
86 };
87 struct rlimit r_file_old;
88 struct rlimit r_file_new;
89 int res;
90
91 sc.ccc = &my_ccc;
92 res = getrlimit (RLIMIT_NOFILE,
93 &r_file_old);
94 r_file_new.rlim_cur = MAX_FILES;
95 r_file_new.rlim_max = r_file_old.rlim_max;
96 res = setrlimit (RLIMIT_NOFILE,
97 &r_file_new);
98 if (0 != res)
99 {
100 fprintf (stderr,
101 "Setting limit failed: %s\n",
102 strerror (errno));
103 return 77;
104 }
105
106 ccc = &my_ccc;
107 ccc->global_ret = GNUNET_SYSERR;
108 if (GNUNET_OK !=
109 GNUNET_TRANSPORT_TESTING_main (2,
110 &GNUNET_TRANSPORT_TESTING_connect_check,
111 ccc))
112 return 1;
113 return 0;
114}
115
116
117#else
118/* cannot setrlimit */
119
120
121int
122main (int argc, char *argv[])
123{
124 fprintf (stderr,
125 "Cannot run test on this system\n");
126 return 77;
127}
128
129
130#endif
131
132/* end of test_transport_api_limited_sockets.c */
diff --git a/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf b/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf
deleted file mode 100644
index e0ad5f847..000000000
--- a/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
5
6[transport]
7PLUGINS = tcp
diff --git a/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf b/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf
deleted file mode 100644
index bb466abba..000000000
--- a/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2@INLINE@ ../../contrib/conf/gnunet/no_autostart_above_core.conf
3
4[PATHS]
5GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
6
7[transport]
8PLUGINS = tcp
diff --git a/src/transport/test_transport_api_manipulation_cfg.c b/src/transport/test_transport_api_manipulation_cfg.c
deleted file mode 100644
index 73c81114e..000000000
--- a/src/transport/test_transport_api_manipulation_cfg.c
+++ /dev/null
@@ -1,186 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_manipulation_cfg.c
22 * @brief base test case for transport traffic manipulation implementation
23 * based on cfg
24 *
25 * Peer 1 has inbound and outbound delay of 100ms
26 * Peer 2 has no inbound and outbound delay
27 *
28 * We send a request from P1 to P2 and expect delay of >= TEST_DELAY us
29 * Then we send response from P2 to P1 and expect delay of >= TEST_DELAY us
30 */
31#include "platform.h"
32#include "gnunet_transport_service.h"
33#include "transport-testing.h"
34
35/**
36 * How long until we give up on transmitting the message?
37 */
38#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
39
40
41#define TEST_MESSAGE_SIZE 2600
42
43#define TEST_RESPONSE_MESSAGE_TYPE
44
45/**
46 * Test delay, in microseconds.
47 */
48#define TEST_DELAY 100 * 1000LL
49
50
51static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
52
53static struct GNUNET_TIME_Absolute start_request;
54
55static struct GNUNET_TIME_Absolute start_response;
56
57
58static void
59sendtask_response_task (void *cls)
60{
61 int ret;
62
63 start_response = GNUNET_TIME_absolute_get ();
64 ret = GNUNET_TRANSPORT_TESTING_send (ccc->p[1],
65 ccc->p[0],
66 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2,
67 TEST_MESSAGE_SIZE,
68 1,
69 NULL,
70 NULL);
71 if (GNUNET_NO == ret)
72 {
73 GNUNET_break (0);
74 GNUNET_SCHEDULER_shutdown ();
75 return;
76 }
77 GNUNET_assert (GNUNET_SYSERR != ret);
78}
79
80
81static void
82notify_receive (void *cls,
83 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
84 const struct GNUNET_PeerIdentity *sender,
85 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
86{
87 struct GNUNET_TIME_Relative duration;
88
89 {
90 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
91
92 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
93 "Peer %u (`%s') received message of type %d and size %u size from peer %s)!\n",
94 receiver->no,
95 ps,
96 ntohs (message->header.type),
97 ntohs (message->header.size),
98 GNUNET_i2s (sender));
99 GNUNET_free (ps);
100 }
101
102 switch (ntohs (message->header.type))
103 {
104 case GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE:
105 duration = GNUNET_TIME_absolute_get_difference (start_request,
106 GNUNET_TIME_absolute_get ());
107 if (duration.rel_value_us >= TEST_DELAY)
108 {
109 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
110 "Request message was delayed for %s\n",
111 GNUNET_STRINGS_relative_time_to_string (duration,
112 GNUNET_YES));
113 }
114 else
115 {
116 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
117 "Request message was delayed for unexpected duration %s\n",
118 GNUNET_STRINGS_relative_time_to_string (duration,
119 GNUNET_YES));
120 ccc->global_ret = GNUNET_SYSERR;
121 GNUNET_SCHEDULER_shutdown ();
122 }
123 /* Send response */
124 GNUNET_SCHEDULER_add_now (&sendtask_response_task,
125 NULL);
126 return;
127
128 case GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2:
129 duration = GNUNET_TIME_absolute_get_difference (start_response,
130 GNUNET_TIME_absolute_get ());
131 if (duration.rel_value_us >= TEST_DELAY)
132 {
133 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
134 "Response message was delayed for %s\n",
135 GNUNET_STRINGS_relative_time_to_string (duration,
136 GNUNET_YES));
137 ccc->global_ret = GNUNET_OK;
138 }
139 else
140 {
141 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
142 "Response message was delayed for unexpected duration %s\n",
143 GNUNET_STRINGS_relative_time_to_string (duration,
144 GNUNET_YES));
145 ccc->global_ret = GNUNET_SYSERR;
146 }
147 GNUNET_SCHEDULER_shutdown ();
148 break;
149
150 default:
151 GNUNET_break (0);
152 break;
153 }
154}
155
156
157int
158main (int argc,
159 char *argv[])
160{
161 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
162 .num_messages = 1
163 };
164 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
165 .connect_continuation = &GNUNET_TRANSPORT_TESTING_large_send,
166 .connect_continuation_cls = &sc,
167 .config_file = "test_transport_api_data.conf",
168 .rec = &notify_receive,
169 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
170 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
171 .timeout = TIMEOUT
172 };
173
174 ccc = &my_ccc;
175 sc.ccc = ccc;
176 start_request = GNUNET_TIME_absolute_get ();
177 if (GNUNET_OK !=
178 GNUNET_TRANSPORT_TESTING_main (2,
179 &GNUNET_TRANSPORT_TESTING_connect_check,
180 ccc))
181 return 1;
182 return 0;
183}
184
185
186/* end of test_transport_api_manipulation_cfg.c */
diff --git a/src/transport/test_transport_api_manipulation_cfg_peer1.conf b/src/transport/test_transport_api_manipulation_cfg_peer1.conf
deleted file mode 100644
index 77cdce2e2..000000000
--- a/src/transport/test_transport_api_manipulation_cfg_peer1.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7MANIPULATE_DELAY_IN = 100 ms
8MANIPULATE_DELAY_OUT = 100 ms
diff --git a/src/transport/test_transport_api_manipulation_cfg_peer2.conf b/src/transport/test_transport_api_manipulation_cfg_peer2.conf
deleted file mode 100644
index 9cbaaddef..000000000
--- a/src/transport/test_transport_api_manipulation_cfg_peer2.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7#MANIPULATE_DELAY_IN = 0 ms
8#MANIPULATE_DELAY_OUT = 0 ms
diff --git a/src/transport/test_transport_api_manipulation_recv_tcp.c b/src/transport/test_transport_api_manipulation_recv_tcp.c
deleted file mode 100644
index 207c4416f..000000000
--- a/src/transport/test_transport_api_manipulation_recv_tcp.c
+++ /dev/null
@@ -1,203 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_manipulation_recv_tcp.c
22 * @brief base test case for transport traffic manipulation implementation
23 *
24 * This test case will setup 2 peers and connect them, the first message
25 * will be sent without manipulation, then a receive delay of 1 second will
26 * be configured and 2 more message will be sent. Time will be measured
27 *
28 * In addition the distance on receiver side will be manipulated to be 10
29 */
30#include "platform.h"
31#include "gnunet_transport_service.h"
32#include "transport-testing.h"
33
34/**
35 * How long until we give up on transmitting the message?
36 */
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
38
39
40static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
41
42static int messages_recv;
43
44static struct GNUNET_TIME_Absolute start_normal;
45
46static struct GNUNET_TIME_Relative dur_normal;
47
48static struct GNUNET_TIME_Absolute start_delayed;
49
50static struct GNUNET_TIME_Relative dur_delayed;
51
52
53static void
54do_free (void *cls)
55{
56 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
57
58 GNUNET_free (sc);
59}
60
61
62static void
63delayed_transmit (void *cls)
64{
65 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
66
67 start_delayed = GNUNET_TIME_absolute_get ();
68 GNUNET_TRANSPORT_TESTING_large_send (sc);
69}
70
71
72static void
73sendtask (void *cls)
74{
75 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc;
76 struct GNUNET_ATS_Properties prop;
77 struct GNUNET_TIME_Relative delay;
78
79 sc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_SendClosure);
80 sc->num_messages = 1;
81 sc->ccc = ccc;
82 sc->cont = &do_free;
83 sc->cont_cls = sc;
84 if (0 == messages_recv)
85 {
86 start_normal = GNUNET_TIME_absolute_get ();
87 }
88 if (0 < messages_recv)
89 {
90 memset (&prop,
91 0,
92 sizeof(prop));
93 delay = GNUNET_TIME_UNIT_SECONDS;
94 GNUNET_TRANSPORT_manipulation_set (ccc->p[1]->tmh,
95 &ccc->p[0]->id,
96 &prop,
97 delay,
98 GNUNET_TIME_UNIT_ZERO);
99 /* wait 1s to allow manipulation to go into effect */
100 if (1 == messages_recv)
101 {
102 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
103 &delayed_transmit,
104 sc);
105 return;
106 }
107 }
108 GNUNET_TRANSPORT_TESTING_large_send (sc);
109}
110
111
112static void
113notify_receive (void *cls,
114 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
115 const struct GNUNET_PeerIdentity *sender,
116 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
117{
118 {
119 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
120
121 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
122 "Peer %u (`%s') received message of type %d and size %u size from peer %s)!\n",
123 receiver->no,
124 ps,
125 ntohs (message->header.type),
126 ntohs (message->header.size),
127 GNUNET_i2s (sender));
128 GNUNET_free (ps);
129 }
130 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (message->header.type)) ||
131 (GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE != ntohs (
132 message->header.size)))
133 {
134 GNUNET_break (0);
135 ccc->global_ret = GNUNET_SYSERR;
136 GNUNET_SCHEDULER_shutdown ();
137 return;
138 }
139
140 if (messages_recv <= 2)
141 {
142 /* Received non-delayed message */
143 dur_normal = GNUNET_TIME_absolute_get_duration (start_normal);
144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
145 "Received non-delayed message %u after %s\n",
146 messages_recv,
147 GNUNET_STRINGS_relative_time_to_string (dur_normal,
148 GNUNET_YES));
149 GNUNET_SCHEDULER_add_now (&sendtask,
150 NULL);
151 messages_recv++;
152 return;
153 }
154 /* Received manipulated message */
155 dur_delayed = GNUNET_TIME_absolute_get_duration (start_delayed);
156 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
157 "Received delayed message %u after %s\n",
158 messages_recv,
159 GNUNET_STRINGS_relative_time_to_string (dur_delayed,
160 GNUNET_YES));
161 if (dur_delayed.rel_value_us < GNUNET_TIME_UNIT_SECONDS.rel_value_us)
162 {
163 GNUNET_break (0);
164 ccc->global_ret = GNUNET_SYSERR;
165 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
166 "Delayed message was not delayed correctly: took only %s\n",
167 GNUNET_STRINGS_relative_time_to_string (dur_delayed,
168 GNUNET_YES));
169 }
170 else
171 {
172 ccc->global_ret = GNUNET_OK;
173 }
174 /* shutdown */
175 GNUNET_SCHEDULER_shutdown ();
176}
177
178
179int
180main (int argc,
181 char *argv[])
182{
183 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
184 .connect_continuation = &sendtask,
185 .config_file = "test_transport_api_data.conf",
186 .rec = &notify_receive,
187 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
188 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
189 .timeout = TIMEOUT,
190 .global_ret = GNUNET_NO
191 };
192
193 ccc = &my_ccc;
194 if (GNUNET_OK !=
195 GNUNET_TRANSPORT_TESTING_main (2,
196 &GNUNET_TRANSPORT_TESTING_connect_check,
197 ccc))
198 return 1;
199 return 0;
200}
201
202
203/* end of test_transport_api_manipulation_recv_tcp.c */
diff --git a/src/transport/test_transport_api_manipulation_recv_tcp_peer1.conf b/src/transport/test_transport_api_manipulation_recv_tcp_peer1.conf
deleted file mode 100644
index 9150c7faf..000000000
--- a/src/transport/test_transport_api_manipulation_recv_tcp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12005
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12004
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12003
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12002
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12001
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28PLUGINS = tcp
29
diff --git a/src/transport/test_transport_api_manipulation_recv_tcp_peer2.conf b/src/transport/test_transport_api_manipulation_recv_tcp_peer2.conf
deleted file mode 100644
index a7b2cf90b..000000000
--- a/src/transport/test_transport_api_manipulation_recv_tcp_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_transport_api_manipulation_send_tcp.c b/src/transport/test_transport_api_manipulation_send_tcp.c
deleted file mode 100644
index ea735cfc6..000000000
--- a/src/transport/test_transport_api_manipulation_send_tcp.c
+++ /dev/null
@@ -1,199 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_manipulation_send_tcp.c
22 * @brief base test case for transport traffic manipulation implementation
23 *
24 * This test case will setup 2 peers and connect them, the first message
25 * will be sent without manipulation, then a send delay of 1 second will
26 * be configured and 1 more message will be sent. Time will be measured.
27 *
28 * In addition the distance on receiver side will be manipulated to be 10
29 */
30#include "platform.h"
31#include "gnunet_transport_service.h"
32#include "transport-testing.h"
33
34/**
35 * How long until we give up on transmitting the message?
36 */
37#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38
39static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
40
41static int messages_recv;
42
43static struct GNUNET_TIME_Absolute start_normal;
44
45static struct GNUNET_TIME_Relative dur_normal;
46
47static struct GNUNET_TIME_Absolute start_delayed;
48
49static struct GNUNET_TIME_Relative dur_delayed;
50
51
52static void
53do_free (void *cls)
54{
55 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
56
57 GNUNET_free (sc);
58}
59
60
61static void
62delayed_transmit (void *cls)
63{
64 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
65
66 start_delayed = GNUNET_TIME_absolute_get ();
67 GNUNET_TRANSPORT_TESTING_large_send (sc);
68}
69
70
71static void
72sendtask (void *cls)
73{
74 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc;
75 struct GNUNET_TIME_Relative delay;
76 struct GNUNET_ATS_Properties prop;
77
78 sc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_SendClosure);
79 sc->num_messages = 1;
80 sc->ccc = ccc;
81 sc->cont = &do_free;
82 sc->cont_cls = sc;
83 if (0 == messages_recv)
84 {
85 start_normal = GNUNET_TIME_absolute_get ();
86 }
87 if (1 == messages_recv)
88 {
89 memset (&prop,
90 0,
91 sizeof(prop));
92 delay = GNUNET_TIME_UNIT_SECONDS;
93 GNUNET_TRANSPORT_manipulation_set (ccc->p[0]->tmh,
94 &ccc->p[1]->id,
95 &prop,
96 GNUNET_TIME_UNIT_ZERO,
97 delay);
98 /* wait 1s to allow manipulation to go into effect */
99 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
100 &delayed_transmit,
101 sc);
102 return;
103 }
104 GNUNET_TRANSPORT_TESTING_large_send (sc);
105}
106
107
108static void
109notify_receive (void *cls,
110 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
111 const struct GNUNET_PeerIdentity *sender,
112 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
113{
114 {
115 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
116
117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
118 "Peer %u (`%s') received message of type %d and size %u size from peer %s)!\n",
119 receiver->no,
120 ps,
121 ntohs (message->header.type),
122 ntohs (message->header.size),
123 GNUNET_i2s (sender));
124 GNUNET_free (ps);
125 }
126
127 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (message->header.type)) ||
128 (GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE != ntohs (
129 message->header.size)))
130 {
131 GNUNET_break (0);
132 ccc->global_ret = GNUNET_SYSERR;
133 GNUNET_SCHEDULER_shutdown ();
134 return;
135 }
136
137 if (0 == messages_recv)
138 {
139 /* Received non-delayed message */
140 dur_normal = GNUNET_TIME_absolute_get_duration (start_normal);
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "Received non-delayed message %u after %s\n",
143 messages_recv,
144 GNUNET_STRINGS_relative_time_to_string (dur_normal,
145 GNUNET_YES));
146 GNUNET_SCHEDULER_add_now (&sendtask,
147 NULL);
148 messages_recv++;
149 return;
150 }
151 /* Received manipulated message */
152 dur_delayed = GNUNET_TIME_absolute_get_duration (start_delayed);
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "Received delayed message %u after %s\n",
155 messages_recv,
156 GNUNET_STRINGS_relative_time_to_string (dur_delayed,
157 GNUNET_YES));
158 if (dur_delayed.rel_value_us < GNUNET_TIME_UNIT_SECONDS.rel_value_us)
159 {
160 GNUNET_break (0);
161 ccc->global_ret = GNUNET_SYSERR;
162 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
163 "Delayed message was not delayed correctly: took only %s\n",
164 GNUNET_STRINGS_relative_time_to_string (dur_delayed,
165 GNUNET_YES));
166 }
167 else
168 {
169 ccc->global_ret = GNUNET_OK;
170 }
171 GNUNET_SCHEDULER_shutdown ();
172}
173
174
175int
176main (int argc,
177 char *argv[])
178{
179 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
180 .connect_continuation = &sendtask,
181 .config_file = "test_transport_api_data.conf",
182 .rec = &notify_receive,
183 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
184 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
185 .timeout = TIMEOUT,
186 .global_ret = GNUNET_NO
187 };
188
189 ccc = &my_ccc;
190 if (GNUNET_OK !=
191 GNUNET_TRANSPORT_TESTING_main (2,
192 &GNUNET_TRANSPORT_TESTING_connect_check,
193 ccc))
194 return 1;
195 return 0;
196}
197
198
199/* end of test_transport_api_manipulation_send_tcp.c */
diff --git a/src/transport/test_transport_api_manipulation_send_tcp_peer1.conf b/src/transport/test_transport_api_manipulation_send_tcp_peer1.conf
deleted file mode 100644
index 9150c7faf..000000000
--- a/src/transport/test_transport_api_manipulation_send_tcp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12005
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12004
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12003
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12002
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12001
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28PLUGINS = tcp
29
diff --git a/src/transport/test_transport_api_manipulation_send_tcp_peer2.conf b/src/transport/test_transport_api_manipulation_send_tcp_peer2.conf
deleted file mode 100644
index a7b2cf90b..000000000
--- a/src/transport/test_transport_api_manipulation_send_tcp_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_transport_api_monitor_peers.c b/src/transport/test_transport_api_monitor_peers.c
deleted file mode 100644
index c09e3782d..000000000
--- a/src/transport/test_transport_api_monitor_peers.c
+++ /dev/null
@@ -1,226 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_monitor_peers.c
22 * @brief base test case for transport peer monitor API
23 */
24#include "platform.h"
25#include "gnunet_transport_service.h"
26#include "transport-testing.h"
27
28/**
29 * How long until we give up on transmitting the message?
30 */
31#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
32
33/**
34 * How long until we give up on transmitting the message?
35 */
36#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply ( \
37 GNUNET_TIME_UNIT_SECONDS, 30)
38
39#define TEST_MESSAGE_SIZE 2600
40
41#define TEST_MESSAGE_TYPE 12345
42
43static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
44
45static struct GNUNET_TRANSPORT_PeerMonitoringContext *pmc_p1;
46
47static struct GNUNET_TRANSPORT_PeerMonitoringContext *pmc_p2;
48
49static int p1_c;
50
51static int p2_c;
52
53static int p1_c_notify;
54
55static int p2_c_notify;
56
57
58static void
59custom_shutdown (void *cls)
60{
61 if (NULL != pmc_p1)
62 {
63 GNUNET_TRANSPORT_monitor_peers_cancel (pmc_p1);
64 pmc_p1 = NULL;
65 }
66 if (NULL != pmc_p2)
67 {
68 GNUNET_TRANSPORT_monitor_peers_cancel (pmc_p2);
69 pmc_p2 = NULL;
70 }
71}
72
73
74static void
75notify_receive (void *cls,
76 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
77 const struct GNUNET_PeerIdentity *sender,
78 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
79{
80 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
81
82 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
83 "Peer %u (`%s') received message of type %d and size %u size from peer %s!\n",
84 receiver->no,
85 ps,
86 ntohs (message->header.type),
87 ntohs (message->header.size),
88 GNUNET_i2s (sender));
89 GNUNET_free (ps);
90}
91
92
93static void
94sendtask (void *cls)
95{
96 /* intentionally empty */
97}
98
99
100static void
101check_done ()
102{
103 if ((GNUNET_YES == p1_c) &&
104 (GNUNET_YES == p2_c) &&
105 p1_c_notify &&
106 p2_c_notify)
107 {
108 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
109 "Both peers state to be connected\n");
110 ccc->global_ret = GNUNET_OK;
111 GNUNET_SCHEDULER_shutdown ();
112 }
113}
114
115
116static void
117notify_connect (void *cls,
118 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
119 const struct GNUNET_PeerIdentity *other)
120{
121 GNUNET_TRANSPORT_TESTING_log_connect (cls,
122 me,
123 other);
124 if (0 == memcmp (other, &ccc->p[0]->id, sizeof(struct GNUNET_PeerIdentity)))
125 {
126 p1_c_notify = GNUNET_YES;
127 }
128 if (0 == memcmp (other, &ccc->p[1]->id, sizeof(struct GNUNET_PeerIdentity)))
129 {
130 p2_c_notify = GNUNET_YES;
131 }
132 check_done ();
133}
134
135
136static void
137monitor1_cb (void *cls,
138 const struct GNUNET_PeerIdentity *peer,
139 const struct GNUNET_HELLO_Address *address,
140 enum GNUNET_TRANSPORT_PeerState state,
141 struct GNUNET_TIME_Absolute state_timeout)
142{
143 if ((NULL == address) || (NULL == ccc->p[0]))
144 return;
145
146 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
147 "Monitor 1: %s %s %s\n",
148 GNUNET_i2s (&address->peer),
149 GNUNET_TRANSPORT_ps2s (state),
150 GNUNET_STRINGS_absolute_time_to_string (state_timeout));
151 if ((0 == memcmp (&address->peer, &ccc->p[1]->id, sizeof(ccc->p[1]->id))) &&
152 (GNUNET_YES == GNUNET_TRANSPORT_is_connected (state)) &&
153 (GNUNET_NO == p1_c))
154 {
155 p1_c = GNUNET_YES;
156 check_done ();
157 }
158}
159
160
161static void
162monitor2_cb (void *cls,
163 const struct GNUNET_PeerIdentity *peer,
164 const struct GNUNET_HELLO_Address *address,
165 enum GNUNET_TRANSPORT_PeerState state,
166 struct GNUNET_TIME_Absolute state_timeout)
167{
168 if ((NULL == address) || (NULL == ccc->p[1]))
169 return;
170
171 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
172 "Monitor 2: %s %s %s\n",
173 GNUNET_i2s (&address->peer),
174 GNUNET_TRANSPORT_ps2s (state),
175 GNUNET_STRINGS_absolute_time_to_string (state_timeout));
176 if ((0 == memcmp (&address->peer, &ccc->p[0]->id, sizeof(ccc->p[0]->id))) &&
177 (GNUNET_YES == GNUNET_TRANSPORT_is_connected (state)) &&
178 (GNUNET_NO == p2_c))
179 {
180 p2_c = GNUNET_YES;
181 check_done ();
182 }
183}
184
185
186static void
187start_monitors (void *cls)
188{
189 pmc_p1 = GNUNET_TRANSPORT_monitor_peers (ccc->p[0]->cfg,
190 NULL,
191 GNUNET_NO,
192 &monitor1_cb,
193 NULL);
194 pmc_p2 = GNUNET_TRANSPORT_monitor_peers (ccc->p[1]->cfg,
195 NULL,
196 GNUNET_NO,
197 &monitor2_cb,
198 NULL);
199}
200
201
202int
203main (int argc, char *argv[])
204{
205 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
206 .pre_connect_task = &start_monitors,
207 .connect_continuation = &sendtask,
208 .config_file = "test_transport_api_data.conf",
209 .rec = &notify_receive,
210 .nc = &notify_connect,
211 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
212 .shutdown_task = &custom_shutdown,
213 .timeout = TIMEOUT
214 };
215
216 ccc = &my_ccc;
217 if (GNUNET_OK !=
218 GNUNET_TRANSPORT_TESTING_main (2,
219 &GNUNET_TRANSPORT_TESTING_connect_check,
220 ccc))
221 return 1;
222 return 0;
223}
224
225
226/* end of test_transport_api_monitor_peers.c */
diff --git a/src/transport/test_transport_api_monitor_peers_peer1.conf b/src/transport/test_transport_api_monitor_peers_peer1.conf
deleted file mode 100644
index bc9eee19b..000000000
--- a/src/transport/test_transport_api_monitor_peers_peer1.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-monitoring-p1/
4
diff --git a/src/transport/test_transport_api_monitor_peers_peer2.conf b/src/transport/test_transport_api_monitor_peers_peer2.conf
deleted file mode 100644
index 5225a5a87..000000000
--- a/src/transport/test_transport_api_monitor_peers_peer2.conf
+++ /dev/null
@@ -1,5 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-monitoring-p2/
4
5
diff --git a/src/transport/test_transport_api_monitor_validation_peer1.conf b/src/transport/test_transport_api_monitor_validation_peer1.conf
deleted file mode 100644
index 02f7bc2f0..000000000
--- a/src/transport/test_transport_api_monitor_validation_peer1.conf
+++ /dev/null
@@ -1,6 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-monitoring-val-p1/
4
5[transport]
6PLUGINS=tcp
diff --git a/src/transport/test_transport_api_monitor_validation_peer2.conf b/src/transport/test_transport_api_monitor_validation_peer2.conf
deleted file mode 100644
index d4e0874f0..000000000
--- a/src/transport/test_transport_api_monitor_validation_peer2.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-monitoring-val-p2/
4
5[TRANSPORT]
6PLUGINS=tcp
7
diff --git a/src/transport/test_transport_api_multi_peer1.conf b/src/transport/test_transport_api_multi_peer1.conf
deleted file mode 100644
index b7cb98777..000000000
--- a/src/transport/test_transport_api_multi_peer1.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-multi-p1/
4
5[transport]
6PLUGINS = tcp udp
7
diff --git a/src/transport/test_transport_api_multi_peer2.conf b/src/transport/test_transport_api_multi_peer2.conf
deleted file mode 100644
index f69e0abd9..000000000
--- a/src/transport/test_transport_api_multi_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-multi-p2/
4
5[nat]
6ALLOW_NAT = NO
7
8[transport]
9PLUGINS = tcp udp
diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c
deleted file mode 100644
index 508fed4f5..000000000
--- a/src/transport/test_transport_api_reliability.c
+++ /dev/null
@@ -1,321 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_reliability.c
22 * @brief base test case for transport implementations
23 *
24 * This test case serves ensures that messages are reliably sent between peers
25 *
26 * This test sends TOTAL_MSGS with message type MTYPE from peer 1 to peer 2
27 * and ensures that all message were received.
28 */
29#include "platform.h"
30#include "gnunet_transport_service.h"
31#include "gauger.h"
32#include "transport-testing.h"
33
34/**
35 * Allow making the problem "bigger".
36 */
37#define FACTOR 1
38
39/**
40 * Total number of messages to send
41 *
42 * Note that this value must not significantly exceed
43 * 'MAX_PENDING' in 'gnunet-service-transport_clients.c', otherwise
44 * messages may be dropped even for a reliable transport.
45 */
46#define TOTAL_MSGS (1024 * 3 * FACTOR)
47
48/**
49 * Testcase timeout
50 */
51#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 450 \
52 * FACTOR)
53
54/**
55 * If we are in an "xhdr" test, the factor by which we divide
56 * #TOTAL_MSGS for a more sane test duration.
57 */
58static unsigned int xhdr = 1;
59
60static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
61
62/**
63 * Total amount of bytes sent
64 */
65static unsigned long long total_bytes;
66
67/**
68 * Time of start
69 */
70static struct GNUNET_TIME_Absolute start_time;
71
72/**
73 * No. of last message received
74 */
75static unsigned int msg_recv;
76
77/**
78 * Bitmap storing which messages were received
79 */
80static char bitmap[TOTAL_MSGS / 8];
81
82
83/**
84 * Get the desired message size for message number @a iter.
85 */
86static size_t
87get_size (unsigned int iter)
88{
89 size_t ret;
90
91 ret = (iter * iter * iter);
92#ifndef __linux__
93 /* FreeBSD/OSX etc. Unix DGRAMs do not work
94 * with large messages */
95 if (0 == strcmp ("unix", ccc->test_plugin))
96 return sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage) + (ret % 1024);
97#endif
98 return sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage) + (ret % 60000);
99}
100
101
102/**
103 * Implementation of the callback for obtaining the
104 * size of messages for transmission. Counts the total
105 * number of bytes sent as a side-effect.
106 *
107 * @param cnt_down count down from `TOTAL_MSGS - 1`
108 * @return message size of the message
109 */
110static size_t
111get_size_cnt (unsigned int cnt_down)
112{
113 size_t ret = get_size (TOTAL_MSGS / xhdr - 1 - cnt_down);
114
115 total_bytes += ret;
116 return ret;
117}
118
119
120/**
121 * Sets a bit active in the bitmap.
122 *
123 * @param bitIdx which bit to set
124 * @return #GNUNET_SYSERR on error, #GNUNET_OK on success
125 */
126static int
127set_bit (unsigned int bitIdx)
128{
129 size_t arraySlot;
130 unsigned int targetBit;
131
132 if (bitIdx >= sizeof(bitmap) * 8)
133 {
134 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
135 "tried to set bit %u of %u(!?!?)\n",
136 bitIdx,
137 (unsigned int) sizeof(bitmap) * 8);
138 return GNUNET_SYSERR;
139 }
140 arraySlot = bitIdx / 8;
141 targetBit = (1L << (bitIdx % 8));
142 bitmap[arraySlot] |= targetBit;
143 return GNUNET_OK;
144}
145
146
147/**
148 * Obtain a bit from bitmap.
149 * @param map the bitmap
150 * @param bit index from bitmap
151 *
152 * @return Bit @a bit from @a map
153 */
154static int
155get_bit (const char *map,
156 unsigned int bit)
157{
158 if (bit > TOTAL_MSGS)
159 {
160 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
161 "get bit %u of %u(!?!?)\n",
162 bit,
163 (unsigned int) sizeof(bitmap) * 8);
164 return 0;
165 }
166 return ((map)[bit >> 3] & (1 << (bit & 7))) > 0;
167}
168
169
170static void
171custom_shutdown (void *cls)
172{
173 unsigned long long delta;
174 unsigned long long rate;
175 int ok;
176
177 /* Calculate statistics */
178 delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value_us;
179 if (0 == delta)
180 delta = 1;
181 rate = (1000LL * 1000ll * total_bytes) / (1024 * delta);
182 fprintf (stderr,
183 "\nThroughput was %llu KiBytes/s\n",
184 rate);
185 {
186 char *value_name;
187
188 GNUNET_asprintf (&value_name,
189 "unreliable_%s",
190 ccc->test_plugin);
191 GAUGER ("TRANSPORT",
192 value_name,
193 (int) rate,
194 "kb/s");
195 GNUNET_free (value_name);
196 }
197
198 ok = 0;
199 for (unsigned int i = 0; i < TOTAL_MSGS / xhdr; i++)
200 {
201 if (get_bit (bitmap, i) == 0)
202 {
203 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
204 "Did not receive message %d\n",
205 i);
206 ok = -1;
207 }
208 }
209 if (0 != ok)
210 ccc->global_ret = GNUNET_SYSERR; /* fail: messages missing! */
211}
212
213
214static void
215notify_receive (void *cls,
216 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
217 const struct GNUNET_PeerIdentity *sender,
218 const struct GNUNET_TRANSPORT_TESTING_TestMessage *hdr)
219{
220 static int n;
221 unsigned int s;
222 char cbuf[GNUNET_MAX_MESSAGE_SIZE - 1];
223
224 if (GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE != ntohs (hdr->header.type))
225 return;
226 msg_recv = ntohl (hdr->num);
227 s = get_size (ntohl (hdr->num));
228
229 if (ntohs (hdr->header.size) != s)
230 {
231 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
232 "Expected message %u of size %u, got %u bytes of message %u\n",
233 (uint32_t) ntohl (hdr->num),
234 s,
235 ntohs (hdr->header.size),
236 (uint32_t) ntohl (hdr->num));
237 ccc->global_ret = GNUNET_SYSERR;
238 GNUNET_SCHEDULER_shutdown ();
239 return;
240 }
241
242 memset (cbuf,
243 ntohl (hdr->num),
244 s - sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage));
245 if (0 !=
246 memcmp (cbuf,
247 &hdr[1],
248 s - sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage)))
249 {
250 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
251 "Expected message %u with bits %u, but body did not match\n",
252 (uint32_t) ntohl (hdr->num),
253 (unsigned char) ntohl (hdr->num));
254 ccc->global_ret = GNUNET_SYSERR;
255 GNUNET_SCHEDULER_shutdown ();
256 return;
257 }
258#if VERBOSE
259 if (0 == ntohl (hdr->num) % 5)
260 {
261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
262 "Got message %u of size %u\n",
263 (uint32_t) ntohl (hdr->num),
264 ntohs (hdr->header.size));
265 }
266#endif
267 n++;
268 if (GNUNET_SYSERR == set_bit (ntohl (hdr->num)))
269 {
270 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
271 "Message id %u is bigger than maxmimum number of messages %u expected\n",
272 (uint32_t) ntohl (hdr->num),
273 TOTAL_MSGS / xhdr);
274 }
275 if (0 == (n % (TOTAL_MSGS / xhdr / 100)))
276 {
277 fprintf (stderr, "%s", ".");
278 }
279 if (n == TOTAL_MSGS / xhdr)
280 {
281 /* end testcase with success */
282 ccc->global_ret = GNUNET_OK;
283 GNUNET_SCHEDULER_shutdown ();
284 }
285}
286
287
288int
289main (int argc, char *argv[])
290{
291 if (0 == strstr (argv[0], "xhdr"))
292 xhdr = 30;
293 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
294 .num_messages = TOTAL_MSGS / xhdr,
295 .get_size_cb = &get_size_cnt
296 };
297 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
298 .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
299 .connect_continuation_cls = &sc,
300 .config_file = "test_transport_api_data.conf",
301 .rec = &notify_receive,
302 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
303 .nd = &GNUNET_TRANSPORT_TESTING_log_disconnect,
304 .shutdown_task = &custom_shutdown,
305 .timeout = TIMEOUT,
306 .global_ret = GNUNET_SYSERR
307 };
308
309 ccc = &my_ccc;
310 sc.ccc = ccc;
311 start_time = GNUNET_TIME_absolute_get ();
312 if (GNUNET_OK !=
313 GNUNET_TRANSPORT_TESTING_main (2,
314 &GNUNET_TRANSPORT_TESTING_connect_check,
315 ccc))
316 return 1;
317 return 0;
318}
319
320
321/* end of test_transport_api_reliability.c */
diff --git a/src/transport/test_transport_api_reliability_bluetooth_peer1.conf b/src/transport/test_transport_api_reliability_bluetooth_peer1.conf
deleted file mode 100644
index 738255235..000000000
--- a/src/transport/test_transport_api_reliability_bluetooth_peer1.conf
+++ /dev/null
@@ -1,33 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
30
31[ats]
32BLUETOOTH_QUOTA_IN = unlimited
33BLUETOOTH_QUOTA_OUT = unlimited
diff --git a/src/transport/test_transport_api_reliability_bluetooth_peer2.conf b/src/transport/test_transport_api_reliability_bluetooth_peer2.conf
deleted file mode 100644
index 9c68b5fbc..000000000
--- a/src/transport/test_transport_api_reliability_bluetooth_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
30[ats]
31BLUETOOTH_QUOTA_IN = unlimited
32BLUETOOTH_QUOTA_OUT = unlimited
diff --git a/src/transport/test_transport_api_reliability_http_peer1.conf b/src/transport/test_transport_api_reliability_http_peer1.conf
deleted file mode 100644
index a1e5c96ac..000000000
--- a/src/transport/test_transport_api_reliability_http_peer1.conf
+++ /dev/null
@@ -1,33 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p1/
4
5[transport-http_client]
6
7[transport-tcp]
8TIMEOUT = 5 s
9
10[transport-http]
11PORT = 12180
12
13[arm]
14PORT = 12185
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
16
17[statistics]
18PORT = 12184
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
20
21[resolver]
22PORT = 12183
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
24
25[peerinfo]
26PORT = 12182
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
28
29[transport]
30PORT = 12181
31PLUGINS = http_client
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
33
diff --git a/src/transport/test_transport_api_reliability_http_peer2.conf b/src/transport/test_transport_api_reliability_http_peer2.conf
deleted file mode 100644
index 25a554f94..000000000
--- a/src/transport/test_transport_api_reliability_http_peer2.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p2/
4
5[transport-http_server]
6PORT = 12090
7USE_IPv6 = NO
8BINDTO = 127.0.0.1
9
10[arm]
11PORT = 12195
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12194
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12193
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12192
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12191
28PLUGINS = http_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
diff --git a/src/transport/test_transport_api_reliability_http_xhr_peer1.conf b/src/transport/test_transport_api_reliability_http_xhr_peer1.conf
deleted file mode 100644
index ba4101ebe..000000000
--- a/src/transport/test_transport_api_reliability_http_xhr_peer1.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p1/
4
5[transport-http_client]
6EMULATE_XHR = YES
7
8[transport-tcp]
9TIMEOUT = 5 s
10
11[transport-http]
12PORT = 12180
13
14[arm]
15PORT = 12185
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
17
18[statistics]
19PORT = 12184
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
21
22[resolver]
23PORT = 12183
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
25
26[peerinfo]
27PORT = 12182
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
29
30[transport]
31PORT = 12181
32PLUGINS = http_client
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
34
diff --git a/src/transport/test_transport_api_reliability_http_xhr_peer2.conf b/src/transport/test_transport_api_reliability_http_xhr_peer2.conf
deleted file mode 100644
index 25a554f94..000000000
--- a/src/transport/test_transport_api_reliability_http_xhr_peer2.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p2/
4
5[transport-http_server]
6PORT = 12090
7USE_IPv6 = NO
8BINDTO = 127.0.0.1
9
10[arm]
11PORT = 12195
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12194
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12193
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12192
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12191
28PLUGINS = http_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
diff --git a/src/transport/test_transport_api_reliability_https_peer1.conf b/src/transport/test_transport_api_reliability_https_peer1.conf
deleted file mode 100644
index 1b51da130..000000000
--- a/src/transport/test_transport_api_reliability_https_peer1.conf
+++ /dev/null
@@ -1,27 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p1/
4
5[transport-https_client]
6
7[arm]
8PORT = 12305
9UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
10
11[statistics]
12PORT = 12304
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
14
15[resolver]
16PORT = 12303
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
18
19[peerinfo]
20PORT = 12302
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
22
23[transport]
24PORT = 12301
25PLUGINS = https_client
26UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
27
diff --git a/src/transport/test_transport_api_reliability_https_peer2.conf b/src/transport/test_transport_api_reliability_https_peer2.conf
deleted file mode 100644
index 3dfb87a6d..000000000
--- a/src/transport/test_transport_api_reliability_https_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p2/
4
5[transport-https_server]
6PORT = 12310
7KEY_FILE = $GNUNET_TEST_HOME/https_key_p2.key
8CERT_FILE = $GNUNET_TEST_HOME/https_cert_p2.crt
9
10[arm]
11PORT = 12315
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12314
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12313
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12312
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12311
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
31
diff --git a/src/transport/test_transport_api_reliability_https_xhr_peer1.conf b/src/transport/test_transport_api_reliability_https_xhr_peer1.conf
deleted file mode 100644
index 5d042f2f9..000000000
--- a/src/transport/test_transport_api_reliability_https_xhr_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p1/
4
5[transport-https_client]
6EMULATE_XHR = YES
7
8[arm]
9PORT = 12305
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12304
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12303
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12302
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12301
26PLUGINS = https_client
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28
diff --git a/src/transport/test_transport_api_reliability_https_xhr_peer2.conf b/src/transport/test_transport_api_reliability_https_xhr_peer2.conf
deleted file mode 100644
index 3dfb87a6d..000000000
--- a/src/transport/test_transport_api_reliability_https_xhr_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p2/
4
5[transport-https_server]
6PORT = 12310
7KEY_FILE = $GNUNET_TEST_HOME/https_key_p2.key
8CERT_FILE = $GNUNET_TEST_HOME/https_cert_p2.crt
9
10[arm]
11PORT = 12315
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12314
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12313
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12312
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12311
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
31
diff --git a/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf b/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf
deleted file mode 100644
index 6a2029b09..000000000
--- a/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf
+++ /dev/null
@@ -1,35 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-reliability-tcp-nat-p1/
4
5[nat]
6BEHIND_NAT = YES
7ENABLE_NAT_SERVER = YES
8DISABLEV6 = YES
9
10[transport-tcp]
11PORT = 0
12TIMEOUT = 5 s
13
14[arm]
15PORT = 51204
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
17
18[statistics]
19PORT = 12023
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
21
22[resolver]
23PORT = 12022
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
25
26[peerinfo]
27PORT = 12021
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
29
30[transport]
31PORT = 29542
32PLUGINS = tcp
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
34
35
diff --git a/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf b/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf
deleted file mode 100644
index 2de9026f5..000000000
--- a/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-reliability-tcp-nat-p2/
4
5[nat]
6DISABLEV6 = YES
7ENABLE_NAT_CLIENT = YES
8
9[transport-tcp]
10PORT = 12030
11TIMEOUT = 5 s
12
13[arm]
14PORT = 12034
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
16
17[statistics]
18PORT = 12033
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
20
21[resolver]
22PORT = 12032
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
24
25[peerinfo]
26PORT = 12031
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
28
29[transport]
30PORT = 45923
31PLUGINS = tcp
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
33
34
diff --git a/src/transport/test_transport_api_reliability_tcp_peer1.conf b/src/transport/test_transport_api_reliability_tcp_peer1.conf
deleted file mode 100644
index 305605d63..000000000
--- a/src/transport/test_transport_api_reliability_tcp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12005
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12004
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12003
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12002
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12001
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
diff --git a/src/transport/test_transport_api_reliability_tcp_peer2.conf b/src/transport/test_transport_api_reliability_tcp_peer2.conf
deleted file mode 100644
index 43bb4ae37..000000000
--- a/src/transport/test_transport_api_reliability_tcp_peer2.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
diff --git a/src/transport/test_transport_api_reliability_udp_peer1.conf b/src/transport/test_transport_api_reliability_udp_peer1.conf
deleted file mode 100644
index 141fb0840..000000000
--- a/src/transport/test_transport_api_reliability_udp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p1/
4
5[transport-udp]
6PORT = 12040
7# Override 1MB/s default limit.
8MAX_BPS = 500000000
9
10[arm]
11PORT = 12045
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
13
14[statistics]
15PORT = 12044
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
17
18[resolver]
19PORT = 12043
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
21
22[peerinfo]
23PORT = 12042
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
25
26[transport]
27PORT = 12041
28PLUGINS = udp
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
diff --git a/src/transport/test_transport_api_reliability_udp_peer2.conf b/src/transport/test_transport_api_reliability_udp_peer2.conf
deleted file mode 100644
index 7523db854..000000000
--- a/src/transport/test_transport_api_reliability_udp_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p2/
4
5[transport-udp]
6PORT = 12050
7# Override 1MB/s default limit.
8MAX_BPS = 500000000
9
10[arm]
11PORT = 12055
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12054
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12053
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12052
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12051
28PLUGINS = udp
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
diff --git a/src/transport/test_transport_api_reliability_unix_peer1.conf b/src/transport/test_transport_api_reliability_unix_peer1.conf
deleted file mode 100644
index e253aad8c..000000000
--- a/src/transport/test_transport_api_reliability_unix_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p1/
4
5[arm]
6PORT = 12125
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
8
9[statistics]
10PORT = 12124
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
12
13[resolver]
14PORT = 12123
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
16
17[peerinfo]
18PORT = 12122
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
20
21[transport]
22PORT = 12121
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
25
26[transport-unix]
27PORT = 12120
28
diff --git a/src/transport/test_transport_api_reliability_unix_peer2.conf b/src/transport/test_transport_api_reliability_unix_peer2.conf
deleted file mode 100644
index e0df47c07..000000000
--- a/src/transport/test_transport_api_reliability_unix_peer2.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p2/
4
5[arm]
6PORT = 12135
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
8
9[statistics]
10PORT = 12134
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
12
13[resolver]
14PORT = 12133
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
16
17[peerinfo]
18PORT = 12132
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
20
21[transport]
22PORT = 12131
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
25
26[transport-unix]
27PORT = 12131
28
diff --git a/src/transport/test_transport_api_reliability_wlan_peer1.conf b/src/transport/test_transport_api_reliability_wlan_peer1.conf
deleted file mode 100644
index 19eb21456..000000000
--- a/src/transport/test_transport_api_reliability_wlan_peer1.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6TESTMODE = 1
7
8[arm]
9PORT = 12164
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12163
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12162
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12161
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12160
26PLUGINS = wlan
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28
29[ats]
30WLAN_QUOTA_IN = unlimited
31WLAN_QUOTA_OUT = unlimited \ No newline at end of file
diff --git a/src/transport/test_transport_api_reliability_wlan_peer2.conf b/src/transport/test_transport_api_reliability_wlan_peer2.conf
deleted file mode 100644
index d5c269b43..000000000
--- a/src/transport/test_transport_api_reliability_wlan_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
30[ats]
31WLAN_QUOTA_IN = unlimited
32WLAN_QUOTA_OUT = unlimited
diff --git a/src/transport/test_transport_api_restart_1peer_peer1.conf b/src/transport/test_transport_api_restart_1peer_peer1.conf
deleted file mode 100644
index eabd6b701..000000000
--- a/src/transport/test_transport_api_restart_1peer_peer1.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_restart_1peer_peer2.conf b/src/transport/test_transport_api_restart_1peer_peer2.conf
deleted file mode 100644
index 58ce0777f..000000000
--- a/src/transport/test_transport_api_restart_1peer_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_restart_2peers_peer1.conf b/src/transport/test_transport_api_restart_2peers_peer1.conf
deleted file mode 100644
index eabd6b701..000000000
--- a/src/transport/test_transport_api_restart_2peers_peer1.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_restart_2peers_peer2.conf b/src/transport/test_transport_api_restart_2peers_peer2.conf
deleted file mode 100644
index 58ce0777f..000000000
--- a/src/transport/test_transport_api_restart_2peers_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_restart_reconnect.c b/src/transport/test_transport_api_restart_reconnect.c
deleted file mode 100644
index d58c1de54..000000000
--- a/src/transport/test_transport_api_restart_reconnect.c
+++ /dev/null
@@ -1,217 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_restart_reconnect.c
22 * @brief base test case for transport implementations
23 *
24 * This test case starts 2 peers, connects and exchanges a message.
25 * Then, 1 or 2 peers are restarted and it is tested if peers reconnect.
26 * How many peers are restarted is determined by the name of the binary.
27 */
28#include "platform.h"
29#include "gnunet_transport_service.h"
30#include "transport-testing.h"
31
32/**
33 * How long until we give up on transmitting the message?
34 */
35#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
36
37
38static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
39
40static struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
41
42static int p1_connected;
43
44static int p2_connected;
45
46static int restarted;
47
48
49static void
50custom_shutdown (void *cls)
51{
52 if (NULL != ats_sh)
53 {
54 GNUNET_ATS_connectivity_suggest_cancel (ats_sh);
55 ats_sh = NULL;
56 }
57}
58
59
60static void
61restart_cb (void *cls)
62{
63 static unsigned int c;
64 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
65
66 c++;
67 if ((2 != c) &&
68 (NULL != strstr (ccc->test_name,
69 "2peers")))
70 return;
71 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
72 "Restarted peer %u (`%s'), issuing reconnect\n",
73 p->no,
74 GNUNET_i2s (&p->id));
75 ats_sh = GNUNET_ATS_connectivity_suggest (p->ats,
76 &ccc->p[1]->id,
77 1);
78}
79
80
81static void
82restart (struct GNUNET_TRANSPORT_TESTING_PeerContext *p)
83{
84 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
85 "Restarting peer %u (`%s')\n",
86 p->no,
87 GNUNET_i2s (&p->id));
88 GNUNET_assert (GNUNET_OK ==
89 GNUNET_TRANSPORT_TESTING_restart_peer (p,
90 &restart_cb,
91 p));
92}
93
94
95static void
96notify_receive (void *cls,
97 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
98 const struct GNUNET_PeerIdentity *sender,
99 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
100{
101 {
102 char *ps = GNUNET_strdup (GNUNET_i2s (&receiver->id));
103
104 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
105 "Peer %u (`%s') received message of type %d and size %u size from peer %s!\n",
106 receiver->no,
107 ps,
108 ntohs (message->header.type),
109 ntohs (message->header.size),
110 GNUNET_i2s (sender));
111 GNUNET_free (ps);
112 }
113 if ((GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE == ntohs (message->header.type)) &&
114 (sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage) == ntohs (
115 message->header.size)))
116 {
117 if (GNUNET_NO == restarted)
118 {
119 restarted = GNUNET_YES;
120 fprintf (stderr, "TN: %s\n", ccc->test_name);
121 restart (ccc->p[0]);
122 if (NULL != strstr (ccc->test_name,
123 "2peers"))
124 restart (ccc->p[1]);
125 return;
126 }
127 else
128 {
129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
130 "Restarted peers connected and message was sent, stopping test...\n");
131 ccc->global_ret = GNUNET_OK;
132 GNUNET_SCHEDULER_shutdown ();
133 }
134 }
135 else
136 {
137 GNUNET_break (0);
138 ccc->global_ret = GNUNET_SYSERR;
139 GNUNET_SCHEDULER_shutdown ();
140 }
141}
142
143
144static void
145notify_connect (void *cls,
146 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
147 const struct GNUNET_PeerIdentity *other)
148{
149 static struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
150 .num_messages = 1
151 };
152
153 sc.ccc = ccc;
154 GNUNET_TRANSPORT_TESTING_log_connect (cls,
155 me,
156 other);
157 if (me == ccc->p[0])
158 p1_connected = GNUNET_YES;
159 if (me == ccc->p[1])
160 p2_connected = GNUNET_YES;
161
162 if ((GNUNET_YES == restarted) &&
163 (GNUNET_YES == p1_connected) &&
164 (GNUNET_YES == p2_connected))
165 {
166 /* Peer was restarted and we received 3 connect messages (2 from first connect, 1 from reconnect) */
167 GNUNET_SCHEDULER_add_now (&GNUNET_TRANSPORT_TESTING_simple_send,
168 &sc);
169 }
170}
171
172
173static void
174notify_disconnect (void *cls,
175 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
176 const struct GNUNET_PeerIdentity *other)
177{
178 GNUNET_TRANSPORT_TESTING_log_disconnect (cls,
179 me,
180 other);
181 if (me == ccc->p[0])
182 p1_connected = GNUNET_NO;
183 if (me == ccc->p[1])
184 p2_connected = GNUNET_NO;
185}
186
187
188int
189main (int argc,
190 char *argv[])
191{
192 struct GNUNET_TRANSPORT_TESTING_SendClosure sc = {
193 .num_messages = 1
194 };
195 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
196 .connect_continuation = &GNUNET_TRANSPORT_TESTING_simple_send,
197 .connect_continuation_cls = &sc,
198 .config_file = "test_transport_api_data.conf",
199 .rec = &notify_receive,
200 .nc = &notify_connect,
201 .nd = &notify_disconnect,
202 .shutdown_task = &custom_shutdown,
203 .timeout = TIMEOUT
204 };
205
206 ccc = &my_ccc;
207 sc.ccc = ccc;
208 if (GNUNET_OK !=
209 GNUNET_TRANSPORT_TESTING_main (2,
210 &GNUNET_TRANSPORT_TESTING_connect_check,
211 ccc))
212 return 1;
213 return 0;
214}
215
216
217/* end of test_transport_api_restart_1peer.c */
diff --git a/src/transport/test_transport_api_slow_ats_peer1.conf b/src/transport/test_transport_api_slow_ats_peer1.conf
deleted file mode 100644
index a96f5e263..000000000
--- a/src/transport/test_transport_api_slow_ats_peer1.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-slow-ats-p1/
4
5[transport]
6PLUGINS = tcp
7
diff --git a/src/transport/test_transport_api_slow_ats_peer2.conf b/src/transport/test_transport_api_slow_ats_peer2.conf
deleted file mode 100644
index 3a6ed05d3..000000000
--- a/src/transport/test_transport_api_slow_ats_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-slow-ats-p2/
4
5[transport]
6PLUGINS = tcp
7
8[ats]
9PREFIX = ./test_delay -t 10 --
diff --git a/src/transport/test_transport_api_tcp_nat_peer1.conf b/src/transport/test_transport_api_tcp_nat_peer1.conf
deleted file mode 100644
index fb2fcecc6..000000000
--- a/src/transport/test_transport_api_tcp_nat_peer1.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-nat-p1/
4
5[nat]
6BEHIND_NAT = YES
7ENABLE_NAT_SERVER = YES
8DISABLEV6 = YES
9
10[transport-tcp]
11PORT = 0
12TIMEOUT = 5 s
13
14[arm]
15PORT = 51204
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
17
18[statistics]
19PORT = 12023
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
21
22[resolver]
23PORT = 12022
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
25
26[peerinfo]
27PORT = 12021
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
29
30[transport]
31PORT = 29542
32PLUGINS = tcp
33UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
34
diff --git a/src/transport/test_transport_api_tcp_nat_peer2.conf b/src/transport/test_transport_api_tcp_nat_peer2.conf
deleted file mode 100644
index 1faefc195..000000000
--- a/src/transport/test_transport_api_tcp_nat_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-nat-p2/
4
5[nat]
6DISABLEV6 = YES
7ENABLE_NAT_CLIENT = YES
8
9[transport-tcp]
10PORT = 12030
11TIMEOUT = 5 s
12
13[arm]
14PORT = 12034
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
16
17[statistics]
18PORT = 12033
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
20
21[resolver]
22PORT = 12032
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
24
25[peerinfo]
26PORT = 12031
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
28
29[transport]
30PORT = 45923
31PLUGINS = tcp
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
diff --git a/src/transport/test_transport_api_tcp_peer1.conf b/src/transport/test_transport_api_tcp_peer1.conf
deleted file mode 100644
index eabd6b701..000000000
--- a/src/transport/test_transport_api_tcp_peer1.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_tcp_peer2.conf b/src/transport/test_transport_api_tcp_peer2.conf
deleted file mode 100644
index 58ce0777f..000000000
--- a/src/transport/test_transport_api_tcp_peer2.conf
+++ /dev/null
@@ -1,9 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#[transport]
9#PREFIX = valgrind
diff --git a/src/transport/test_transport_api_timeout.c b/src/transport/test_transport_api_timeout.c
deleted file mode 100644
index 9f8d3bb2b..000000000
--- a/src/transport/test_transport_api_timeout.c
+++ /dev/null
@@ -1,164 +0,0 @@
1/*
2 This file is part of GNUnet.x
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_api_timeout.c
22 * @brief test case for transport plugin implementations complying timeout
23 * settings
24 *
25 *
26 * This test case serves ensures that no peer disconnect events occurs
27 * while plugins are idle
28 */
29
30#include "platform.h"
31#include "gnunet_transport_service.h"
32#include "transport-testing.h"
33
34/**
35 * How long until we give up on transmitting the message?
36 */
37#define WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
38
39#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90)
40
41#define MTYPE 12345
42
43static struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
44
45static struct GNUNET_TIME_Relative time_running;
46
47static struct GNUNET_SCHEDULER_Task *timer_task;
48
49static int shutdown_flag;
50
51static unsigned int disconnects;
52
53
54static void
55custom_shutdown (void *cls)
56{
57 if (NULL != timer_task)
58 {
59 GNUNET_SCHEDULER_cancel (timer_task);
60 timer_task = NULL;
61 }
62 if (0 == disconnects)
63 {
64 ccc->global_ret = GNUNET_OK;
65 }
66 else
67 {
68 ccc->global_ret = -GNUNET_SYSERR;
69 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
70 "Fail! Had %u disconnects while waiting %s\n",
71 disconnects,
72 GNUNET_STRINGS_relative_time_to_string (WAIT,
73 GNUNET_YES));
74 }
75}
76
77
78static void
79notify_receive (void *cls,
80 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
81 const struct GNUNET_PeerIdentity *sender,
82 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
83{
84 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
85 "Received message of type %d from peer %s!\n",
86 ntohs (message->header.type),
87 GNUNET_i2s (sender));
88}
89
90
91static void
92notify_disconnect (void *cls,
93 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
94 const struct GNUNET_PeerIdentity *other)
95{
96 GNUNET_TRANSPORT_TESTING_log_disconnect (cls,
97 me,
98 other);
99 if (shutdown_flag != GNUNET_YES)
100 {
101 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
102 "FAIL! Peer `%s' disconnected during waiting period!\n",
103 GNUNET_i2s (other));
104 disconnects++;
105 }
106}
107
108
109static void
110timer (void *cls)
111{
112 static unsigned int percentage;
113
114 timer_task = NULL;
115 percentage += 10;
116 time_running = GNUNET_TIME_relative_add (time_running,
117 GNUNET_TIME_relative_divide (WAIT,
118 10));
119
120 if (time_running.rel_value_us ==
121 GNUNET_TIME_relative_max (time_running, WAIT).rel_value_us)
122 {
123 fprintf (stderr, "%s", "100%%\n");
124 shutdown_flag = GNUNET_YES;
125 GNUNET_SCHEDULER_shutdown ();
126 }
127 else
128 {
129 fprintf (stderr,
130 "%u%%..",
131 percentage);
132 timer_task =
133 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (WAIT, 10),
134 &timer,
135 NULL);
136 }
137}
138
139
140int
141main (int argc,
142 char *argv[])
143{
144 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext my_ccc = {
145 .connect_continuation = &timer,
146 .config_file = "test_transport_api_data.conf",
147 .rec = &notify_receive,
148 .nc = &GNUNET_TRANSPORT_TESTING_log_connect,
149 .nd = &notify_disconnect,
150 .shutdown_task = &custom_shutdown,
151 .timeout = TIMEOUT
152 };
153
154 ccc = &my_ccc;
155 if (GNUNET_OK !=
156 GNUNET_TRANSPORT_TESTING_main (2,
157 &GNUNET_TRANSPORT_TESTING_connect_check,
158 ccc))
159 return 1;
160 return 0;
161}
162
163
164/* end of test_transport_api_timeout.c*/
diff --git a/src/transport/test_transport_api_timeout_bluetooth_peer1.conf b/src/transport/test_transport_api_timeout_bluetooth_peer1.conf
deleted file mode 100644
index dcc159e45..000000000
--- a/src/transport/test_transport_api_timeout_bluetooth_peer1.conf
+++ /dev/null
@@ -1,35 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
35
diff --git a/src/transport/test_transport_api_timeout_bluetooth_peer2.conf b/src/transport/test_transport_api_timeout_bluetooth_peer2.conf
deleted file mode 100644
index 5cd550d0e..000000000
--- a/src/transport/test_transport_api_timeout_bluetooth_peer2.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
diff --git a/src/transport/test_transport_api_timeout_http_peer1.conf b/src/transport/test_transport_api_timeout_http_peer1.conf
deleted file mode 100644
index d7bc59ea3..000000000
--- a/src/transport/test_transport_api_timeout_http_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p1/
4
5[arm]
6PORT = 12085
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
8
9[statistics]
10PORT = 12084
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
12
13[resolver]
14PORT = 12083
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
16
17[peerinfo]
18PORT = 12082
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
20
21[transport]
22PORT = 12081
23PLUGINS = http_client
24#BINARY = .libs/gnunet-service-transport
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
26#PREFIX = valgrind --leak-check=full
27#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
28
diff --git a/src/transport/test_transport_api_timeout_http_peer2.conf b/src/transport/test_transport_api_timeout_http_peer2.conf
deleted file mode 100644
index 453c6d0c5..000000000
--- a/src/transport/test_transport_api_timeout_http_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-http-p2/
4
5[transport-http_server]
6PORT = 12090
7USE_IPv6 = NO
8BINDTO = 127.0.0.1
9
10
11[arm]
12PORT = 12095
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
14
15[statistics]
16PORT = 12094
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
18
19[resolver]
20PORT = 12093
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
22
23[peerinfo]
24PORT = 12092
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
26
27[transport]
28PORT = 12091
29PLUGINS = http_server
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
31#PREFIX = valgrind --leak-check=full
diff --git a/src/transport/test_transport_api_timeout_https_peer1.conf b/src/transport/test_transport_api_timeout_https_peer1.conf
deleted file mode 100644
index c4f96814c..000000000
--- a/src/transport/test_transport_api_timeout_https_peer1.conf
+++ /dev/null
@@ -1,25 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p1/
4
5[arm]
6PORT = 12105
7
8[statistics]
9PORT = 12104
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
11
12[resolver]
13PORT = 12103
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
15
16[peerinfo]
17PORT = 12102
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
19
20[transport]
21PORT = 12101
22PLUGINS = https_client
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
24
25
diff --git a/src/transport/test_transport_api_timeout_https_peer2.conf b/src/transport/test_transport_api_timeout_https_peer2.conf
deleted file mode 100644
index bfdf0caec..000000000
--- a/src/transport/test_transport_api_timeout_https_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-https-p2/
4
5[transport-https_server]
6PORT = 12110
7KEY_FILE = $GNUNET_TEST_HOME/https_key_p2.key
8CERT_FILE = $GNUNET_TEST_HOME/https_cert_p2.crt
9
10[arm]
11PORT = 12115
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12114
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12113
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12112
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12111
28PLUGINS = https_server
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
31
diff --git a/src/transport/test_transport_api_timeout_tcp_peer1.conf b/src/transport/test_transport_api_timeout_tcp_peer1.conf
deleted file mode 100644
index 389250bec..000000000
--- a/src/transport/test_transport_api_timeout_tcp_peer1.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12005
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12004
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12003
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12002
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12001
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
30
diff --git a/src/transport/test_transport_api_timeout_tcp_peer2.conf b/src/transport/test_transport_api_timeout_tcp_peer2.conf
deleted file mode 100644
index 225b8fac2..000000000
--- a/src/transport/test_transport_api_timeout_tcp_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[nat]
6ALLOW_NAT = NO
7
8[transport-tcp]
9PORT = 12100
10
11[arm]
12PORT = 12014
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
14
15[statistics]
16PORT = 12013
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
18
19[resolver]
20PORT = 12012
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
22
23[peerinfo]
24PORT = 12011
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
26
27[transport]
28PORT = 12010
29PLUGINS = tcp
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
31
32
diff --git a/src/transport/test_transport_api_timeout_udp_peer1.conf b/src/transport/test_transport_api_timeout_udp_peer1.conf
deleted file mode 100644
index e28e3a2e0..000000000
--- a/src/transport/test_transport_api_timeout_udp_peer1.conf
+++ /dev/null
@@ -1,33 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p1/
4
5[transport-udp]
6PORT = 12040
7BROADCAST = NO
8BROADCAST_INTERVAL = 30000
9MAX_BPS = 50000000
10
11[arm]
12PORT = 12045
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
14
15[statistics]
16PORT = 12044
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
18
19[resolver]
20PORT = 12043
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
22
23[peerinfo]
24PORT = 12042
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
26
27[transport]
28#PREFIX = valgrind --leak-check=full
29PORT = 12041
30PLUGINS = udp
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
32
33
diff --git a/src/transport/test_transport_api_timeout_udp_peer2.conf b/src/transport/test_transport_api_timeout_udp_peer2.conf
deleted file mode 100644
index 434ef4853..000000000
--- a/src/transport/test_transport_api_timeout_udp_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p2/
4
5[transport-udp]
6PORT = 12050
7BROADCAST = NO
8MAX_BPS = 50000000
9
10[arm]
11PORT = 12055
12UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
13
14[statistics]
15PORT = 12054
16UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
17
18[resolver]
19PORT = 12053
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
21
22[peerinfo]
23PORT = 12052
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
25
26[transport]
27PORT = 12051
28PLUGINS = udp
29UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
30
31
diff --git a/src/transport/test_transport_api_timeout_unix_peer1.conf b/src/transport/test_transport_api_timeout_unix_peer1.conf
deleted file mode 100644
index e253aad8c..000000000
--- a/src/transport/test_transport_api_timeout_unix_peer1.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p1/
4
5[arm]
6PORT = 12125
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
8
9[statistics]
10PORT = 12124
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
12
13[resolver]
14PORT = 12123
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
16
17[peerinfo]
18PORT = 12122
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
20
21[transport]
22PORT = 12121
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
25
26[transport-unix]
27PORT = 12120
28
diff --git a/src/transport/test_transport_api_timeout_unix_peer2.conf b/src/transport/test_transport_api_timeout_unix_peer2.conf
deleted file mode 100644
index bd3fccbb3..000000000
--- a/src/transport/test_transport_api_timeout_unix_peer2.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p2/
4
5[arm]
6PORT = 12135
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
8
9[statistics]
10PORT = 12134
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
12
13[resolver]
14PORT = 12133
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
16
17[peerinfo]
18PORT = 12132
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
20
21[transport]
22PORT = 12131
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
25
26[transport-unix]
27PORT = 12136
28
diff --git a/src/transport/test_transport_api_timeout_wlan_peer1.conf b/src/transport/test_transport_api_timeout_wlan_peer1.conf
deleted file mode 100644
index 68716d287..000000000
--- a/src/transport/test_transport_api_timeout_wlan_peer1.conf
+++ /dev/null
@@ -1,35 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6INTERFACE = mon0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
35
diff --git a/src/transport/test_transport_api_timeout_wlan_peer2.conf b/src/transport/test_transport_api_timeout_wlan_peer2.conf
deleted file mode 100644
index 98bbc6e2b..000000000
--- a/src/transport/test_transport_api_timeout_wlan_peer2.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
diff --git a/src/transport/test_transport_api_udp_nat_peer1.conf b/src/transport/test_transport_api_udp_nat_peer1.conf
deleted file mode 100644
index 7bbcaa628..000000000
--- a/src/transport/test_transport_api_udp_nat_peer1.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-nat-p1/
4
5[nat]
6BEHIND_NAT = YES
7ALLOW_NAT = NO
8ONLY_NAT_ADDRESSES = YES
9
10[transport-udp]
11PORT = 0
12
13[arm]
14PORT = 12065
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
16
17[statistics]
18PORT = 12064
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
20
21[resolver]
22PORT = 12063
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
24
25[peerinfo]
26PORT = 12062
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
28
29[transport]
30PORT = 12061
31PLUGINS = udp
32UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
33
34
diff --git a/src/transport/test_transport_api_udp_nat_peer2.conf b/src/transport/test_transport_api_udp_nat_peer2.conf
deleted file mode 100644
index 8bdb8c293..000000000
--- a/src/transport/test_transport_api_udp_nat_peer2.conf
+++ /dev/null
@@ -1,32 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-nat-p2/
4
5[nat]
6ALLOW_NAT = YES
7
8[transport-udp]
9PORT = 12070
10
11[arm]
12PORT = 12075
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
14
15[statistics]
16PORT = 12074
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
18
19[resolver]
20PORT = 12073
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
22
23[peerinfo]
24PORT = 12072
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
26
27[transport]
28PORT = 12071
29PLUGINS = udp
30UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
31
32
diff --git a/src/transport/test_transport_api_udp_peer1.conf b/src/transport/test_transport_api_udp_peer1.conf
deleted file mode 100644
index 4684b77f2..000000000
--- a/src/transport/test_transport_api_udp_peer1.conf
+++ /dev/null
@@ -1,17 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p1/
4
5[transport-udp]
6PORT = 0
7BROADCAST = NO
8MAX_BPS = 50000000
9BINDTO = 127.0.0.1
10BINDTO6 = ::1
11
12[transport]
13PORT = 12041
14PLUGINS = udp
15
16
17
diff --git a/src/transport/test_transport_api_udp_peer2.conf b/src/transport/test_transport_api_udp_peer2.conf
deleted file mode 100644
index 96706ce49..000000000
--- a/src/transport/test_transport_api_udp_peer2.conf
+++ /dev/null
@@ -1,15 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p2/
4
5[transport-udp]
6PORT = 12050
7BROADCAST = NO
8MAX_BPS = 50000000
9BINDTO = 127.0.0.1
10BINDTO6 = ::1
11
12[transport]
13PLUGINS = udp
14
15
diff --git a/src/transport/test_transport_api_unix_abstract_peer1.conf b/src/transport/test_transport_api_unix_abstract_peer1.conf
deleted file mode 100644
index 103a483b4..000000000
--- a/src/transport/test_transport_api_unix_abstract_peer1.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p1/
4
5[arm]
6PORT = 12125
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
8
9[statistics]
10PORT = 12124
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
12
13[resolver]
14PORT = 12123
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
16
17[peerinfo]
18PORT = 12122
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
20
21[transport]
22PORT = 12121
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
25
26[transport-unix]
27PORT = 12120
28
29[testing]
30USE_ABSTRACT_SOCKETS = YES
31
diff --git a/src/transport/test_transport_api_unix_abstract_peer2.conf b/src/transport/test_transport_api_unix_abstract_peer2.conf
deleted file mode 100644
index c3a5525d9..000000000
--- a/src/transport/test_transport_api_unix_abstract_peer2.conf
+++ /dev/null
@@ -1,31 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p2/
4
5[arm]
6PORT = 12135
7UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
8
9[statistics]
10PORT = 12134
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
12
13[resolver]
14PORT = 12133
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
16
17[peerinfo]
18PORT = 12132
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
20
21[transport]
22PORT = 12131
23PLUGINS = unix
24UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
25
26[transport-unix]
27PORT = 12136
28
29[testing]
30USE_ABSTRACT_SOCKETS = YES
31
diff --git a/src/transport/test_transport_api_unix_peer1.conf b/src/transport/test_transport_api_unix_peer1.conf
deleted file mode 100644
index 005558bcc..000000000
--- a/src/transport/test_transport_api_unix_peer1.conf
+++ /dev/null
@@ -1,10 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p1/
4
5[transport]
6PLUGINS = unix
7
8[transport-unix]
9PORT = 12120
10
diff --git a/src/transport/test_transport_api_unix_peer2.conf b/src/transport/test_transport_api_unix_peer2.conf
deleted file mode 100644
index 840ed81c7..000000000
--- a/src/transport/test_transport_api_unix_peer2.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-unix-p2/
4
5[transport]
6PLUGINS = unix
7
diff --git a/src/transport/test_transport_api_unreliability_bluetooth_peer1.conf b/src/transport/test_transport_api_unreliability_bluetooth_peer1.conf
deleted file mode 100644
index 3f86ee940..000000000
--- a/src/transport/test_transport_api_unreliability_bluetooth_peer1.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p1/
4
5[transport-bluetooth]
6INTERFACE = hci0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
30
diff --git a/src/transport/test_transport_api_unreliability_bluetooth_peer2.conf b/src/transport/test_transport_api_unreliability_bluetooth_peer2.conf
deleted file mode 100644
index 5fc178395..000000000
--- a/src/transport/test_transport_api_unreliability_bluetooth_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-bluetooth-p2/
4
5[transport-bluetooth]
6INTERFACE = hci1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = bluetooth
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf b/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf
deleted file mode 100644
index 9f63c0ced..000000000
--- a/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p1/
4
5[transport-udp]
6PORT = 12040
7MAX_BPS = 1073741824
8
9[arm]
10PORT = 12045
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12044
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12043
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12042
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12041
27PLUGINS = udp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29
30
diff --git a/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf b/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf
deleted file mode 100644
index cdf3d7bb4..000000000
--- a/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf
+++ /dev/null
@@ -1,30 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-udp-p2/
4
5[transport-udp]
6PORT = 12050
7MAX_BPS = 1073741824
8
9[arm]
10PORT = 12055
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12054
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12053
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12052
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12051
27PLUGINS = udp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
30
diff --git a/src/transport/test_transport_api_unreliability_wlan_peer1.conf b/src/transport/test_transport_api_unreliability_wlan_peer1.conf
deleted file mode 100644
index 78e280b68..000000000
--- a/src/transport/test_transport_api_unreliability_wlan_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6TESTMODE = 1
7
8[arm]
9PORT = 12164
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
11
12[statistics]
13PORT = 12163
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
15
16[resolver]
17PORT = 12162
18UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
19
20[peerinfo]
21PORT = 12161
22UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
23
24[transport]
25PORT = 12160
26PLUGINS = wlan
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28
29
diff --git a/src/transport/test_transport_api_unreliability_wlan_peer2.conf b/src/transport/test_transport_api_unreliability_wlan_peer2.conf
deleted file mode 100644
index e97ab3f38..000000000
--- a/src/transport/test_transport_api_unreliability_wlan_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29
diff --git a/src/transport/test_transport_api_wlan_peer1.conf b/src/transport/test_transport_api_wlan_peer1.conf
deleted file mode 100644
index 68716d287..000000000
--- a/src/transport/test_transport_api_wlan_peer1.conf
+++ /dev/null
@@ -1,35 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p1/
4
5[transport-wlan]
6INTERFACE = mon0
7TESTMODE = 1
8
9[arm]
10PORT = 12164
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12163
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12162
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12161
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12160
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
35
diff --git a/src/transport/test_transport_api_wlan_peer2.conf b/src/transport/test_transport_api_wlan_peer2.conf
deleted file mode 100644
index 98bbc6e2b..000000000
--- a/src/transport/test_transport_api_wlan_peer2.conf
+++ /dev/null
@@ -1,34 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-wlan-p2/
4
5[transport-wlan]
6INTERFACE = mon1
7TESTMODE = 2
8
9[arm]
10PORT = 12174
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12173
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12172
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12171
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12170
27PLUGINS = wlan
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
29#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
30#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
31#PREFIX = valgrind --leak-check=full --show-reachable=yes
32#PREFIX = valgrind --leak-check=full
33#PREFIX = valgrind --tool=massif
34#PREFIX = gdbserver :2345
diff --git a/src/transport/test_transport_blacklisting.c b/src/transport/test_transport_blacklisting.c
deleted file mode 100644
index 204935dcb..000000000
--- a/src/transport/test_transport_blacklisting.c
+++ /dev/null
@@ -1,582 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2011 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_blacklisting.c
23 * @brief test for the blacklisting with blacklistings defined in cfg
24 *
25 * this file contains multiple tests:
26 *
27 * test_transport_blacklisting_no_bl:
28 * no blacklisting entries
29 * peers are expected to connect
30 * test_transport_blacklisting_outbound_bl_full:
31 * both peers contain bl entries for full peer
32 * test is expected to not connect
33 * test_transport_blacklisting_outbound_bl_plugin:
34 * both peers contain bl entries for plugin
35 * test is expected to not connect
36 * test_transport_blacklisting_inbound_bl_plugin:
37 * peer 1 contains no bl entries
38 * peer 2 contain bl entries for full peer
39 * test is expected to not connect
40 * test_transport_blacklisting_inbound_bl_full:
41 * peer 1 contains no bl entries
42 * peer 2 contain bl entries for plugin
43 * test is expected to not connect
44 * test_transport_blacklisting_multiple_plugins:
45 * both peers contain bl entries for plugin
46 * test is expected to connect with not bl'ed plugin
47 *
48 * @author Matthias Wachs
49 *
50 */
51#include "platform.h"
52#include "gnunet_transport_service.h"
53#include "transport-testing.h"
54
55char *test_name;
56
57struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
58
59struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
60
61static struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
62
63struct GNUNET_TRANSPORT_TESTING_Handle *tth;
64
65/**
66 * How long until we give up on transmitting the message?
67 */
68#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
69
70#define CONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, \
71 10)
72
73static int stage;
74static int ok;
75static int connected;
76
77static struct GNUNET_SCHEDULER_Task *die_task;
78
79static struct GNUNET_SCHEDULER_Task *timeout_task;
80
81static struct GNUNET_SCHEDULER_Task *stage_task;
82
83#if VERBOSE
84#define OKPP do { ok++; fprintf (stderr, "Now at stage %u at %s:%u\n", ok, \
85 __FILE__, __LINE__); } while (0)
86#else
87#define OKPP do { ok++; } while (0)
88#endif
89
90
91static void
92run_stage (void *cls);
93
94
95static void
96end (void *cls)
97{
98 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping\n");
99
100 if (die_task != NULL)
101 {
102 GNUNET_SCHEDULER_cancel (die_task);
103 die_task = NULL;
104 }
105
106 if (timeout_task != NULL)
107 {
108 GNUNET_SCHEDULER_cancel (timeout_task);
109 timeout_task = NULL;
110 }
111
112 if (stage_task != NULL)
113 {
114 GNUNET_SCHEDULER_cancel (stage_task);
115 stage_task = NULL;
116 }
117
118 if (cc != NULL)
119 {
120 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
121 cc = NULL;
122 }
123
124 if (p1 != NULL)
125 {
126 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
127 p1 = NULL;
128 }
129 if (p2 != NULL)
130 {
131 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
132 p2 = NULL;
133 }
134}
135
136
137static void
138end_badly (void *cls)
139{
140 die_task = NULL;
141
142 if (timeout_task != NULL)
143 {
144 GNUNET_SCHEDULER_cancel (timeout_task);
145 timeout_task = NULL;
146 }
147
148 if (stage_task != NULL)
149 {
150 GNUNET_SCHEDULER_cancel (stage_task);
151 stage_task = NULL;
152 }
153
154 if (cc != NULL)
155 {
156 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
157 cc = NULL;
158 }
159 if (p1 != NULL)
160 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
161 if (p2 != NULL)
162 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
163
164 ok = GNUNET_SYSERR;
165}
166
167
168static void
169testing_connect_cb (void *cls)
170{
171 cc = NULL;
172 char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
173
174 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Peers connected: %u (%s) <-> %u (%s)\n",
175 p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
176 GNUNET_free (p1_c);
177 connected = GNUNET_YES;
178 stage_task = GNUNET_SCHEDULER_add_now (&run_stage, NULL);
179}
180
181
182static void
183connect_timeout (void *cls)
184{
185 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
186 "Peers not connected, next stage\n");
187 timeout_task = NULL;
188 stage_task = GNUNET_SCHEDULER_add_now (&run_stage,
189 NULL);
190}
191
192
193static int started;
194
195
196static void
197start_cb (void *cls)
198{
199 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
200
201 started++;
202 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
203 "Peer %u (`%s') started\n",
204 p->no,
205 GNUNET_i2s_full (&p->id));
206
207 if (started != 2)
208 return;
209
210 char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
211
212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213 "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
214 p1->no,
215 sender_c,
216 p2->no,
217 GNUNET_i2s (&p2->id));
218 GNUNET_free (sender_c);
219
220 cc = GNUNET_TRANSPORT_TESTING_connect_peers (p1,
221 p2,
222 &testing_connect_cb,
223 NULL);
224}
225
226
227static int
228check_blacklist_config (const char *cfg_file,
229 struct GNUNET_PeerIdentity *peer,
230 struct GNUNET_PeerIdentity *bl_peer)
231{
232 struct GNUNET_CONFIGURATION_Handle *cfg;
233 char *section;
234 char *peer_str;
235
236 cfg = GNUNET_CONFIGURATION_create ();
237 if (GNUNET_OK != GNUNET_CONFIGURATION_load (cfg, cfg_file))
238 {
239 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Could not load configuration `%s'\n",
240 cfg_file);
241 GNUNET_CONFIGURATION_destroy (cfg);
242 return GNUNET_SYSERR;
243 }
244
245 peer_str = GNUNET_strdup (GNUNET_i2s_full (peer));
246 GNUNET_asprintf (&section, "transport-blacklist-%s", peer_str);
247
248 if (GNUNET_NO == GNUNET_CONFIGURATION_have_value (cfg, section,
249 GNUNET_i2s_full (bl_peer)))
250 {
251 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
252 "Configuration `%s' does not have blacklisting section for peer `%s' blacklisting `%s'\n",
253 cfg_file, peer_str, GNUNET_i2s_full (bl_peer));
254 GNUNET_CONFIGURATION_destroy (cfg);
255 GNUNET_free (section);
256 GNUNET_free (peer_str);
257 return GNUNET_SYSERR;
258 }
259
260 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
261 "Configuration `%s' does have blacklisting section for peer `%s' blacklisting `%s'\n",
262 cfg_file, peer_str, GNUNET_i2s_full (bl_peer));
263
264 GNUNET_CONFIGURATION_destroy (cfg);
265 GNUNET_free (section);
266 GNUNET_free (peer_str);
267 return GNUNET_OK;
268}
269
270
271static void
272run_stage (void *cls)
273{
274 stage_task = NULL;
275 if (NULL != die_task)
276 GNUNET_SCHEDULER_cancel (die_task);
277 die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
278 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Running stage %u\n", stage);
279
280 if (0 == stage)
281 {
282 started = GNUNET_NO;
283 connected = GNUNET_NO;
284 if (0 == strcmp (test_name, "test_transport_blacklisting_no_bl"))
285 {
286 /* Try to connect peers successfully */
287 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
288 "test_transport_blacklisting_cfg_peer1.conf",
289 1,
290 NULL,
291 NULL,
292 NULL,
293 NULL,
294 &start_cb,
295 NULL);
296
297 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
298 "test_transport_blacklisting_cfg_peer2.conf",
299 2,
300 NULL,
301 NULL,
302 NULL,
303 NULL,
304 &start_cb,
305 NULL);
306 }
307 else if (0 == strcmp (test_name,
308 "test_transport_blacklisting_outbound_bl_full"))
309 {
310 const char *cfg_p1 =
311 "test_transport_blacklisting_cfg_blp_peer1_full.conf";
312 const char *cfg_p2 =
313 "test_transport_blacklisting_cfg_blp_peer2_full.conf";
314
315 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
316 cfg_p1,
317 1, NULL, NULL, NULL,
318 NULL,
319 &start_cb, NULL);
320 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
321 cfg_p2, 2,
322 NULL, NULL, NULL,
323 NULL,
324 &start_cb, NULL);
325
326 /* check if configuration contain correct blacklist entries */
327 if ((GNUNET_SYSERR ==
328 check_blacklist_config (cfg_p1, &p1->id, &p2->id)) ||
329 (GNUNET_SYSERR ==
330 check_blacklist_config (cfg_p2, &p2->id, &p1->id)))
331 {
332 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
333 p1 = NULL;
334 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
335 p2 = NULL;
336 ok = 1;
337 GNUNET_SCHEDULER_add_now (&end, NULL);
338 }
339 }
340 else if (0
341 == strcmp (test_name,
342 "test_transport_blacklisting_outbound_bl_plugin"))
343 {
344 const char *cfg_p1 =
345 "test_transport_blacklisting_cfg_blp_peer1_plugin.conf";
346 const char *cfg_p2 =
347 "test_transport_blacklisting_cfg_blp_peer2_plugin.conf";
348
349 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
350 cfg_p1,
351 1,
352 NULL,
353 NULL,
354 NULL,
355 NULL,
356 &start_cb,
357 NULL);
358
359 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
360 cfg_p2, 2,
361 NULL,
362 NULL,
363 NULL,
364 NULL,
365 &start_cb,
366 NULL);
367
368 /* check if configuration contain correct blacklist entries */
369 if ((GNUNET_SYSERR ==
370 check_blacklist_config (cfg_p1, &p1->id, &p2->id)) ||
371 (GNUNET_SYSERR ==
372 check_blacklist_config (cfg_p2, &p2->id, &p1->id)))
373 {
374 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
375 p1 = NULL;
376 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
377 p2 = NULL;
378 ok = 1;
379 GNUNET_SCHEDULER_add_now (&end, NULL);
380 }
381 }
382 else if (0 == strcmp (test_name,
383 "test_transport_blacklisting_inbound_bl_full"))
384 {
385 const char *cfg_p1 = "test_transport_blacklisting_cfg_peer1.conf";
386 const char *cfg_p2 =
387 "test_transport_blacklisting_cfg_blp_peer2_full.conf";
388
389 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
390 cfg_p1, 1,
391 NULL,
392 NULL, NULL, NULL,
393 &start_cb, NULL);
394
395 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
396 cfg_p2, 2,
397 NULL,
398 NULL, NULL, NULL,
399 &start_cb, NULL);
400
401 /* check if configuration contain correct blacklist entries */
402 if ((GNUNET_SYSERR ==
403 check_blacklist_config (cfg_p2, &p2->id, &p1->id)))
404 {
405 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
406 p1 = NULL;
407 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
408 p2 = NULL;
409 ok = 1;
410 GNUNET_SCHEDULER_add_now (&end, NULL);
411 }
412 }
413 else if (0 == strcmp (test_name,
414 "test_transport_blacklisting_inbound_bl_plugin"))
415 {
416 const char *cfg_p1 = "test_transport_blacklisting_cfg_peer1.conf";
417 const char *cfg_p2 =
418 "test_transport_blacklisting_cfg_blp_peer2_plugin.conf";
419
420 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
421 cfg_p1, 1,
422 NULL,
423 NULL, NULL, NULL,
424 &start_cb, NULL);
425
426 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
427 cfg_p2, 2,
428 NULL,
429 NULL, NULL,
430 NULL,
431 &start_cb, NULL);
432
433 /* check if configuration contain correct blacklist entries */
434 if ((GNUNET_SYSERR ==
435 check_blacklist_config (cfg_p2, &p2->id, &p1->id)))
436 {
437 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
438 p1 = NULL;
439 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
440 p2 = NULL;
441 ok = 1;
442 GNUNET_SCHEDULER_add_now (&end, NULL);
443 }
444 }
445 else if (0 == strcmp (test_name,
446 "test_transport_blacklisting_multiple_plugins"))
447 {
448 const char *cfg_p1 =
449 "test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf";
450 const char *cfg_p2 =
451 "test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf";
452
453 p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
454 cfg_p1, 1,
455 NULL,
456 NULL, NULL, NULL,
457 &start_cb, NULL);
458
459 p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
460 cfg_p2, 2,
461 NULL,
462 NULL, NULL, NULL,
463 &start_cb, NULL);
464
465 /* check if configuration contain correct blacklist entries */
466 if ((GNUNET_SYSERR ==
467 check_blacklist_config (cfg_p1, &p1->id, &p2->id)) ||
468 (GNUNET_SYSERR ==
469 check_blacklist_config (cfg_p2, &p2->id, &p1->id)))
470 {
471 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
472 p1 = NULL;
473 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
474 p2 = NULL;
475 ok = 1;
476 GNUNET_SCHEDULER_add_now (&end, NULL);
477 }
478 }
479 else
480 {
481 GNUNET_break (0);
482 GNUNET_SCHEDULER_add_now (&end, NULL);
483 }
484
485 if ((NULL == p1) || (NULL == p2))
486 {
487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start peers\n");
488 ok = 1;
489 GNUNET_SCHEDULER_add_now (&end, NULL);
490 }
491
492 timeout_task = GNUNET_SCHEDULER_add_delayed (CONNECT_TIMEOUT,
493 &connect_timeout,
494 NULL);
495 stage++;
496 return;
497 }
498
499 if (cc != NULL)
500 {
501 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
502 cc = NULL;
503 }
504
505 if (p1 != NULL)
506 {
507 GNUNET_TRANSPORT_TESTING_stop_peer (p1);
508 p1 = NULL;
509 }
510 if (p2 != NULL)
511 {
512 GNUNET_TRANSPORT_TESTING_stop_peer (p2);
513 p2 = NULL;
514 }
515
516 GNUNET_log (GNUNET_ERROR_TYPE_INFO, "Done in stage %u: Peers %s and %s!\n",
517 stage, (GNUNET_NO == started) ? "NOT STARTED" : "STARTED",
518 (GNUNET_YES == connected) ? "CONNECTED" : "NOT CONNECTED");
519
520 if ((0 == strcmp (test_name, "test_transport_blacklisting_no_bl"))
521 || (0 == strcmp (test_name,
522 "test_transport_blacklisting_multiple_plugins")))
523 {
524 if ((GNUNET_NO != started) && (GNUNET_YES == connected))
525 ok = 0;
526 else
527 {
528 GNUNET_break (0);
529 ok = 1;
530 }
531 }
532 else
533 {
534 if ((GNUNET_NO != started) && (GNUNET_YES != connected))
535 ok = 0;
536 else
537 {
538 ok = 1;
539 }
540 }
541 GNUNET_SCHEDULER_add_now (&end, NULL);
542}
543
544
545static void
546run (void *cls, char *const *args, const char *cfgfile,
547 const struct GNUNET_CONFIGURATION_Handle *cfg)
548{
549 connected = GNUNET_NO;
550 stage = 0;
551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Running test `%s'!\n", test_name);
552 stage_task = GNUNET_SCHEDULER_add_now (&run_stage, NULL);
553}
554
555
556int
557main (int argc, char *argv0[])
558{
559 ok = 1;
560
561 test_name = GNUNET_TRANSPORT_TESTING_get_test_name (argv0[0]);
562
563 GNUNET_log_setup ("test-transport-api-blacklisting", "WARNING", NULL);
564
565 static char *const argv[] =
566 { "date", "-c", "test_transport_api_data.conf", NULL };
567 static struct GNUNET_GETOPT_CommandLineOption options[] =
568 { GNUNET_GETOPT_OPTION_END };
569
570 tth = GNUNET_TRANSPORT_TESTING_init ();
571
572 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1, argv,
573 "test-transport-api-blacklisting", "nohelp", options,
574 &run, NULL);
575
576 GNUNET_TRANSPORT_TESTING_done (tth);
577
578 return ok;
579}
580
581
582/* end of transport_api_blacklisting.c */
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer1_full.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer1_full.conf
deleted file mode 100644
index 19bff8fcc..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer1_full.conf
+++ /dev/null
@@ -1,16 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[transport]
10PLUGINS = tcp
11
12#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
13#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
14
15[transport-blacklist-4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730]
16F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0 =
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf
deleted file mode 100644
index 79bc90469..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer1_multiple_plugins.conf
+++ /dev/null
@@ -1,13 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp unix
7
8#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
9#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
10
11[transport-blacklist-4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730]
12F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0 = tcp
13
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer1_plugin.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer1_plugin.conf
deleted file mode 100644
index b328dd5cf..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer1_plugin.conf
+++ /dev/null
@@ -1,13 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6PLUGINS = tcp
7
8#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
9#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
10
11[transport-blacklist-4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730]
12F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0 = tcp
13
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer2_full.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer2_full.conf
deleted file mode 100644
index 862209d2c..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer2_full.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
9#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
10
11[transport-blacklist-F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0]
124TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730 =
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf
deleted file mode 100644
index 3134f9d81..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer2_multiple_plugins.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp unix
7
8#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
9#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
10
11[transport-blacklist-F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0]
124TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730 = tcp
diff --git a/src/transport/test_transport_blacklisting_cfg_blp_peer2_plugin.conf b/src/transport/test_transport_blacklisting_cfg_blp_peer2_plugin.conf
deleted file mode 100644
index dd582125d..000000000
--- a/src/transport/test_transport_blacklisting_cfg_blp_peer2_plugin.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6PLUGINS = tcp
7
8#Peer 1: 4TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730
9#Peer 2: F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0
10
11[transport-blacklist-F7B5NX6KCPG8SAKYSGV0E94Y5NXR9JE3HCGQ5YGH1H04WFQWMWT0]
124TTC9WBSVP9RJT6DVEZ7E0TDW7TQXC11NR1EMR2F8ARS87WZ2730 = tcp
diff --git a/src/transport/test_transport_blacklisting_cfg_peer1.conf b/src/transport/test_transport_blacklisting_cfg_peer1.conf
deleted file mode 100644
index 9150c7faf..000000000
--- a/src/transport/test_transport_blacklisting_cfg_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport-tcp]
6PORT = 12000
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12005
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
12
13[statistics]
14PORT = 12004
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
16
17[resolver]
18PORT = 12003
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
20
21[peerinfo]
22PORT = 12002
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
24
25[transport]
26PORT = 12001
27UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
28PLUGINS = tcp
29
diff --git a/src/transport/test_transport_blacklisting_cfg_peer2.conf b/src/transport/test_transport_blacklisting_cfg_peer2.conf
deleted file mode 100644
index 43bb4ae37..000000000
--- a/src/transport/test_transport_blacklisting_cfg_peer2.conf
+++ /dev/null
@@ -1,28 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport-tcp]
6PORT = 12015
7TIMEOUT = 5 s
8
9[arm]
10PORT = 12014
11UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-arm.sock
12
13[statistics]
14PORT = 12013
15UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-statistics.sock
16
17[resolver]
18PORT = 12012
19UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-resolver.sock
20
21[peerinfo]
22PORT = 12011
23UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-peerinfo.sock
24
25[transport]
26PORT = 12010
27PLUGINS = tcp
28UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p2-service-transport.sock
diff --git a/src/transport/test_transport_defaults.conf b/src/transport/test_transport_defaults.conf
deleted file mode 100644
index 3aed73f0c..000000000
--- a/src/transport/test_transport_defaults.conf
+++ /dev/null
@@ -1,20 +0,0 @@
1@INLINE@ ../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-tng/
5
6[transport-tcp]
7TIMEOUT = 300 s
8
9[transport]
10# PREFIX = valgrind
11
12[nat]
13DISABLEV6 = NO
14RETURN_LOCAL_ADDRESSES = YES
15BINDTO = 127.0.0.1
16INTERNAL_ADDRESS = 127.0.0.1
17EXTERNAL_ADDRESS = 127.0.0.1
18
19[transport-udp]
20BROADCAST_RECEIVE = no
diff --git a/src/transport/test_transport_distance_vector_circle_topo.conf b/src/transport/test_transport_distance_vector_circle_topo.conf
deleted file mode 100644
index 210179291..000000000
--- a/src/transport/test_transport_distance_vector_circle_topo.conf
+++ /dev/null
@@ -1,12 +0,0 @@
1M:1
2N:3
3X:0
4AC:1
5B:0
6T:libgnunet_test_transport_plugin_cmd_simple_send_dv
7R:1|{tcp_port:0}|{udp_port:1}
8R:2|{tcp_port:0}|{udp_port:1}
9R:3|{tcp_port:0}|{udp_port:1}
10P:1:1|{connect:{P:2:1:udp}}
11P:2:1|{connect:{P:3:1:udp}}
12P:3:1|{connect:{P:1:1:udp}}
diff --git a/src/transport/test_transport_distance_vector_topo.conf b/src/transport/test_transport_distance_vector_topo.conf
deleted file mode 100644
index ead3e0a0a..000000000
--- a/src/transport/test_transport_distance_vector_topo.conf
+++ /dev/null
@@ -1,8 +0,0 @@
1M:2
2N:2
3X:0
4T:libgnunet_test_transport_plugin_cmd_simple_send_dv
5R:1|{tcp_port:1}|{udp_port:0}
6R:2|{tcp_port:1}|{udp_port:0}
7P:1:1|{connect:{P:2:1:tcp}}
8P:2:1|{connect:{P:1:1:tcp}}
diff --git a/src/transport/test_transport_plugin_cmd_simple_send.c b/src/transport/test_transport_plugin_cmd_simple_send.c
deleted file mode 100644
index 154c0abca..000000000
--- a/src/transport/test_transport_plugin_cmd_simple_send.c
+++ /dev/null
@@ -1,369 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/plugin_cmd_simple_send.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "transport-testing2.h"
32#include "transport-testing-cmds.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39#define BASE_DIR "testdir"
40
41#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
42
43struct TestState
44{
45 /**
46 * Callback to write messages to the master loop.
47 *
48 */
49 TESTING_CMD_HELPER_write_cb write_message;
50
51 /**
52 * The name for a specific test environment directory.
53 *
54 */
55 char *testdir;
56
57 /**
58 * The name for the configuration file of the specific node.
59 *
60 */
61 char *cfgname;
62
63 /**
64 * The complete topology information.
65 */
66 struct GNUNET_TESTING_NetjailTopology *topology;
67};
68
69static struct GNUNET_TESTING_Command block_send;
70
71static struct GNUNET_TESTING_Command block_receive;
72
73static struct GNUNET_TESTING_Command connect_peers;
74
75static struct GNUNET_TESTING_Command local_prepared;
76
77
78/**
79 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
80 * received.
81 *
82 */
83static int
84check_test (void *cls,
85 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
86{
87 return GNUNET_OK;
88}
89
90
91/**
92 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
93 * being received.
94 *
95 */
96static void
97handle_test (void *cls,
98 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
99{
100 const struct GNUNET_TESTING_AsyncContext *ac;
101
102 GNUNET_TESTING_get_trait_async_context (&block_receive,
103 &ac);
104 GNUNET_assert (NULL != ac);
105 if (NULL == ac->cont)
106 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
107 else
108 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
109}
110
111
112/**
113 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
114 *
115 */
116static void
117all_peers_started ()
118{
119 const struct GNUNET_TESTING_AsyncContext *ac;
120
121 GNUNET_TESTING_get_trait_async_context (&block_send,
122 &ac);
123 GNUNET_assert (NULL != ac);
124 if (NULL == ac->cont)
125 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
126 else
127 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
128}
129
130
131/**
132 * Function called with the final result of the test.
133 *
134 * @param cls the `struct MainParams`
135 * @param rv #GNUNET_OK if the test passed
136 */
137static void
138handle_result (void *cls,
139 enum GNUNET_GenericReturnValue rv)
140{
141 struct TestState *ts = cls;
142 struct GNUNET_MessageHeader *reply;
143
144 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
145 "Local test exits with status %d\n",
146 rv);
147 reply = GNUNET_TESTING_send_local_test_finished_msg (rv);
148
149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
150 "message prepared\n");
151 ts->write_message (reply,
152 ntohs (reply->size));
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "message send\n");
155 GNUNET_free (ts->testdir);
156 GNUNET_free (ts->cfgname);
157 GNUNET_TESTING_free_topology (ts->topology);
158 GNUNET_free (ts);
159}
160
161
162/**
163 * Callback from start peer cmd for signaling a peer got connected.
164 *
165 */
166static void *
167notify_connect (struct GNUNET_TESTING_Interpreter *is,
168 const struct GNUNET_PeerIdentity *peer)
169{
170 const struct ConnectPeersState *cps;
171 const struct GNUNET_TESTING_Command *cmd;
172
173 cmd = GNUNET_TESTING_interpreter_lookup_command (is,
174 "connect-peers");
175 GNUNET_TRANSPORT_get_trait_connect_peer_state (cmd,
176 &cps);
177 void *ret = NULL;
178
179 cps->notify_connect (is,
180 peer);
181 return ret;
182}
183
184
185/**
186 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
187 */
188static void
189all_local_tests_prepared ()
190{
191 const struct LocalPreparedState *lfs;
192
193 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
194 &lfs);
195 GNUNET_assert (NULL != &lfs->ac);
196 if (NULL == lfs->ac.cont)
197 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
198 else
199 GNUNET_TESTING_async_finish ((struct
200 GNUNET_TESTING_AsyncContext *) &lfs->ac);
201}
202
203
204/**
205 * Function to start a local test case.
206 *
207 * @param write_message Callback to send a message to the master loop.
208 * @param router_ip Global address of the network namespace.
209 * @param node_ip Local address of a node i a network namespace.
210 * @param m The number of the node in a network namespace.
211 * @param n The number of the network namespace.
212 * @param local_m The number of nodes in a network namespace.
213 */
214static void
215start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
216 char *node_ip,
217 char *m,
218 char *n,
219 char *local_m,
220 char *topology_data,
221 unsigned int *read_file)
222{
223
224 unsigned int n_int;
225 unsigned int m_int;
226 unsigned int local_m_int;
227 unsigned int num;
228 struct TestState *ts = GNUNET_new (struct TestState);
229 struct GNUNET_TESTING_NetjailTopology *topology;
230
231 if (GNUNET_YES == *read_file)
232 {
233 LOG (GNUNET_ERROR_TYPE_DEBUG,
234 "read from file\n");
235 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
236 }
237 else
238 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
239
240 ts->topology = topology;
241
242 sscanf (m, "%u", &m_int);
243 sscanf (n, "%u", &n_int);
244 sscanf (local_m, "%u", &local_m_int);
245
246 if (0 == n_int)
247 num = m_int;
248 else
249 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
250
251 block_send = GNUNET_TESTING_cmd_block_until_external_trigger (
252 "block");
253 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
254 "block-receive");
255 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
256 "start-peer",
257 "system-create",
258 num,
259 topology,
260 0);
261 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
262 "local-test-prepared",
263 write_message);
264
265
266 GNUNET_asprintf (&ts->cfgname,
267 "test_transport_api2_tcp_node1.conf");
268
269 LOG (GNUNET_ERROR_TYPE_DEBUG,
270 "plugin cfgname: %s\n",
271 ts->cfgname);
272
273 LOG (GNUNET_ERROR_TYPE_DEBUG,
274 "node ip: %s\n",
275 node_ip);
276
277 GNUNET_asprintf (&ts->testdir,
278 "%s%s%s",
279 BASE_DIR,
280 m,
281 n);
282
283 struct GNUNET_MQ_MessageHandler handlers[] = {
284 GNUNET_MQ_hd_var_size (test,
285 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
286 struct GNUNET_TRANSPORT_TESTING_TestMessage,
287 ts),
288 GNUNET_MQ_handler_end ()
289 };
290
291 struct GNUNET_TESTING_Command commands[] = {
292 GNUNET_TESTING_cmd_system_create ("system-create",
293 ts->testdir),
294 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
295 "system-create",
296 num,
297 node_ip,
298 handlers,
299 ts->cfgname,
300 notify_connect,
301 GNUNET_NO),
302 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
303 write_message),
304 block_send,
305 connect_peers,
306 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
307 "start-peer",
308 "system-create",
309 num,
310 topology),
311 block_receive,
312 local_prepared,
313 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
314 "start-peer"),
315 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
316 "system-create"),
317 GNUNET_TESTING_cmd_end ()
318 };
319
320 ts->write_message = write_message;
321
322 GNUNET_TESTING_run (commands,
323 GNUNET_TIME_UNIT_FOREVER_REL,
324 &handle_result,
325 ts);
326
327}
328
329
330/**
331 * Entry point for the plugin.
332 *
333 * @param cls NULL
334 * @return the exported block API
335 */
336void *
337libgnunet_test_transport_plugin_cmd_simple_send_init (void *cls)
338{
339 struct GNUNET_TESTING_PluginFunctions *api;
340
341 GNUNET_log_setup ("simple-send",
342 "DEBUG",
343 NULL);
344
345 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
346 api->start_testcase = &start_testcase;
347 api->all_peers_started = &all_peers_started;
348 api->all_local_tests_prepared = all_local_tests_prepared;
349 return api;
350}
351
352
353/**
354 * Exit point from the plugin.
355 *
356 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
357 * @return NULL
358 */
359void *
360libgnunet_test_transport_plugin_cmd_simple_send_done (void *cls)
361{
362 struct GNUNET_TESTING_PluginFunctions *api = cls;
363
364 GNUNET_free (api);
365 return NULL;
366}
367
368
369/* end of plugin_cmd_simple_send.c */
diff --git a/src/transport/test_transport_plugin_cmd_simple_send_broadcast.c b/src/transport/test_transport_plugin_cmd_simple_send_broadcast.c
deleted file mode 100644
index 9d6844be1..000000000
--- a/src/transport/test_transport_plugin_cmd_simple_send_broadcast.c
+++ /dev/null
@@ -1,398 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/plugin_cmd_simple_send_broadcast.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "transport-testing2.h"
32#include "transport-testing-cmds.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39#define BASE_DIR "testdir"
40
41#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
42
43struct TestState
44{
45 /**
46 * Callback to write messages to the master loop.
47 *
48 */
49 TESTING_CMD_HELPER_write_cb write_message;
50
51 /**
52 * The name for a specific test environment directory.
53 *
54 */
55 char *testdir;
56
57 /**
58 * The name for the configuration file of the specific node.
59 *
60 */
61 char *cfgname;
62
63 /**
64 * The complete topology information.
65 */
66 struct GNUNET_TESTING_NetjailTopology *topology;
67};
68
69static struct GNUNET_TESTING_Command block_send;
70
71static struct GNUNET_TESTING_Command block_receive;
72
73static struct GNUNET_TESTING_Command connect_peers;
74
75static struct GNUNET_TESTING_Command local_prepared;
76
77/**
78 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
79 * received.
80 *
81 */
82static int
83check_test (void *cls,
84 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
85{
86 return GNUNET_OK;
87}
88
89
90/**
91 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
92 * being received.
93 *
94 */
95static void
96handle_test (void *cls,
97 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
98{
99 const struct GNUNET_TESTING_AsyncContext *ac;
100
101 GNUNET_TESTING_get_trait_async_context (&block_receive,
102 &ac);
103 GNUNET_assert (NULL != ac);
104 if ((GNUNET_NO == ac->finished) && (NULL == ac->cont))
105 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
106 else if (GNUNET_NO == ac->finished)
107 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
108}
109
110
111/**
112 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
113 *
114 */
115static void
116all_peers_started ()
117{
118 const struct GNUNET_TESTING_AsyncContext *ac;
119
120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
121 "Received message\n");
122 GNUNET_TESTING_get_trait_async_context (&block_send,
123 &ac);
124 GNUNET_assert (NULL != ac);
125 if (NULL == ac->cont)
126 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
127 else
128 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
129}
130
131
132/**
133 * Function called with the final result of the test.
134 *
135 * @param cls the `struct MainParams`
136 * @param rv #GNUNET_OK if the test passed
137 */
138static void
139handle_result (void *cls,
140 enum GNUNET_GenericReturnValue rv)
141{
142 struct TestState *ts = cls;
143 struct GNUNET_MessageHeader *reply;
144
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146 "Local test exits with status %d\n",
147 rv);
148 reply = GNUNET_TESTING_send_local_test_finished_msg (rv);
149
150 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
151 "message prepared\n");
152 ts->write_message (reply,
153 ntohs (reply->size));
154 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
155 "message send\n");
156 GNUNET_free (ts->testdir);
157 GNUNET_free (ts->cfgname);
158 GNUNET_TESTING_free_topology (ts->topology);
159 GNUNET_free (ts);
160}
161
162
163/**
164 * Callback from start peer cmd for signaling a peer got connected.
165 *
166 */
167static void *
168notify_connect (struct GNUNET_TESTING_Interpreter *is,
169 const struct GNUNET_PeerIdentity *peer)
170{
171 const struct GNUNET_TESTING_AsyncContext *ac;
172 void *ret = NULL;
173 const struct GNUNET_TESTING_Command *cmd;
174 struct BlockState *bs;
175
176
177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178 "notify_connect\n");
179
180 GNUNET_TESTING_get_trait_async_context (&connect_peers,
181 &ac);
182
183 if (NULL != ac->is)
184 {
185 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
186 "notify_connect running\n");
187 GNUNET_assert (NULL != ac);
188 if (NULL == ac->cont)
189 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
190 else
191 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
192 }
193 else
194 {
195 cmd = GNUNET_TESTING_interpreter_lookup_future_command (is,
196 "connect-peers");
197
198 LOG (GNUNET_ERROR_TYPE_DEBUG,
199 "block state %s\n",
200 cmd->label);
201 GNUNET_TESTING_get_trait_block_state (
202 cmd,
203 (const struct BlockState **) &bs);
204
205 LOG (GNUNET_ERROR_TYPE_DEBUG,
206 "block state %u\n",
207 bs->asynchronous_finish);
208 bs->asynchronous_finish = GNUNET_YES;
209 LOG (GNUNET_ERROR_TYPE_DEBUG,
210 "block state %u\n",
211 bs->asynchronous_finish);
212 }
213
214 return ret;
215}
216
217
218/**
219 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
220 */
221static void
222all_local_tests_prepared ()
223{
224 const struct LocalPreparedState *lfs;
225
226 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
227 &lfs);
228 GNUNET_assert (NULL != &lfs->ac);
229 if (NULL == lfs->ac.cont)
230 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
231 else
232 GNUNET_TESTING_async_finish ((struct
233 GNUNET_TESTING_AsyncContext *) &lfs->ac);
234}
235
236
237/**
238 * Function to start a local test case.
239 *
240 * @param write_message Callback to send a message to the master loop.
241 * @param router_ip Global address of the network namespace.
242 * @param node_ip Local address of a node i a network namespace.
243 * @param m The number of the node in a network namespace.
244 * @param n The number of the network namespace.
245 * @param local_m The number of nodes in a network namespace.
246 */
247static void
248start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
249 char *node_ip,
250 char *m,
251 char *n,
252 char *local_m,
253 char *topology_data,
254 unsigned int *read_file)
255{
256 unsigned int n_int;
257 unsigned int m_int;
258 unsigned int local_m_int;
259 unsigned int num;
260 struct TestState *ts = GNUNET_new (struct TestState);
261 struct GNUNET_TESTING_NetjailTopology *topology;
262
263
264
265 if (GNUNET_YES == *read_file)
266 {
267 LOG (GNUNET_ERROR_TYPE_DEBUG,
268 "read from file\n");
269 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
270 }
271 else
272 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
273
274 ts->topology = topology;
275
276 sscanf (m, "%u", &m_int);
277 sscanf (n, "%u", &n_int);
278 sscanf (local_m, "%u", &local_m_int);
279
280 if (0 == n_int)
281 num = m_int;
282 else
283 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
284
285 block_send = GNUNET_TESTING_cmd_block_until_external_trigger ("block");
286 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
287 "block-receive");
288 connect_peers = GNUNET_TESTING_cmd_block_until_external_trigger (
289 "connect-peers");
290 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
291 "local-test-prepared",
292 write_message);
293
294
295 GNUNET_asprintf (&ts->cfgname,
296 "test_transport_api2_tcp_node1.conf");
297
298 LOG (GNUNET_ERROR_TYPE_DEBUG,
299 "plugin cfgname: %s\n",
300 ts->cfgname);
301
302 LOG (GNUNET_ERROR_TYPE_DEBUG,
303 "node ip: %s\n",
304 node_ip);
305
306 GNUNET_asprintf (&ts->testdir,
307 "%s%s%s",
308 BASE_DIR,
309 m,
310 n);
311
312 struct GNUNET_MQ_MessageHandler handlers[] = {
313 GNUNET_MQ_hd_var_size (test,
314 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
315 struct GNUNET_TRANSPORT_TESTING_TestMessage,
316 ts),
317 GNUNET_MQ_handler_end ()
318 };
319
320 struct GNUNET_TESTING_Command commands[] = {
321 GNUNET_TESTING_cmd_system_create ("system-create",
322 ts->testdir),
323 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
324 "system-create",
325 num,
326 node_ip,
327 handlers,
328 ts->cfgname,
329 notify_connect,
330 GNUNET_YES),
331 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
332 write_message),
333 block_send,
334 connect_peers,
335 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
336 "start-peer",
337 "system-create",
338 num,
339 topology),
340 block_receive,
341 local_prepared,
342 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
343 "start-peer"),
344 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
345 "system-create"),
346 GNUNET_TESTING_cmd_end ()
347 };
348
349 ts->write_message = write_message;
350
351 GNUNET_TESTING_run (commands,
352 GNUNET_TIME_UNIT_FOREVER_REL,
353 &handle_result,
354 ts);
355
356}
357
358
359/**
360 * Entry point for the plugin.
361 *
362 * @param cls NULL
363 * @return the exported block API
364 */
365void *
366libgnunet_test_transport_plugin_cmd_simple_send_broadcast_init (void *cls)
367{
368 struct GNUNET_TESTING_PluginFunctions *api;
369
370 GNUNET_log_setup ("simple-send",
371 "DEBUG",
372 NULL);
373
374 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
375 api->start_testcase = &start_testcase;
376 api->all_peers_started = &all_peers_started;
377 api->all_local_tests_prepared = all_local_tests_prepared;
378 return api;
379}
380
381
382/**
383 * Exit point from the plugin.
384 *
385 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
386 * @return NULL
387 */
388void *
389libgnunet_test_transport_plugin_cmd_simple_send_broadcast_done (void *cls)
390{
391 struct GNUNET_TESTING_PluginFunctions *api = cls;
392
393 GNUNET_free (api);
394 return NULL;
395}
396
397
398/* end of plugin_cmd_simple_send_broadcast.c */
diff --git a/src/transport/test_transport_plugin_cmd_simple_send_dv.c b/src/transport/test_transport_plugin_cmd_simple_send_dv.c
deleted file mode 100644
index f1f168102..000000000
--- a/src/transport/test_transport_plugin_cmd_simple_send_dv.c
+++ /dev/null
@@ -1,427 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/plugin_cmd_simple_send_broadcast.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "transport-testing2.h"
32#include "transport-testing-cmds.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39#define BASE_DIR "testdir"
40
41#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
42
43struct TestState
44{
45 /**
46 * Callback to write messages to the master loop.
47 *
48 */
49 TESTING_CMD_HELPER_write_cb write_message;
50
51 /**
52 * The name for a specific test environment directory.
53 *
54 */
55 char *testdir;
56
57 /**
58 * The name for the configuration file of the specific node.
59 *
60 */
61 char *cfgname;
62
63 /**
64 * The complete topology information.
65 */
66 struct GNUNET_TESTING_NetjailTopology *topology;
67
68};
69
70/**
71 * The number of messages received.
72 */
73static unsigned int number_received;
74
75static struct GNUNET_TESTING_Command block_send;
76
77static struct GNUNET_TESTING_Command block_receive;
78
79static struct GNUNET_TESTING_Command connect_peers;
80
81static struct GNUNET_TESTING_Command local_prepared;
82
83static struct GNUNET_TESTING_Command start_peer;
84
85/**
86 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
87 * received.
88 *
89 */
90static int
91check_test (void *cls,
92 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
93{
94 GNUNET_assert (NULL != cls);
95 return GNUNET_OK;
96}
97
98
99/**
100 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
101 * being received.
102 *
103 */
104static void
105handle_test (void *cls,
106 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
107{
108 struct GNUNET_PeerIdentity *peer = cls;
109 const struct GNUNET_TESTING_AsyncContext *ac_block;
110 const struct GNUNET_TESTING_AsyncContext *ac_start;
111 const struct GNUNET_TESTING_Command *cmd;
112 const struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
113 unsigned int connected;
114 struct BlockState *bs;
115 struct GNUNET_TRANSPORT_CoreHandle *ch;
116 const struct StartPeerState *sps;
117
118
119 GNUNET_TRANSPORT_get_trait_state (&start_peer,
120 &sps);
121 ch = sps->th;
122 GNUNET_TRANSPORT_get_trait_connected_peers_map (&start_peer,
123 &connected_peers_map);
124
125 if (NULL != connected_peers_map)
126 {
127 connected = GNUNET_CONTAINER_multishortmap_size (
128 connected_peers_map);
129
130 number_received++;
131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
132 "Received %u test message(s) from %s, %u connected peer(s)\n",
133 number_received,
134 GNUNET_i2s (peer),
135 connected);
136
137 GNUNET_TESTING_get_trait_async_context (&block_receive,
138 &ac_block);
139
140 if ( connected == number_received)
141 {
142 if (NULL != ac_block->is)
143 {
144 GNUNET_assert (NULL != ac_block);
145 if (NULL == ac_block->cont)
146 GNUNET_TESTING_async_fail ((struct
147 GNUNET_TESTING_AsyncContext *) ac_block);
148 else
149 GNUNET_TESTING_async_finish ((struct
150 GNUNET_TESTING_AsyncContext *) ac_block);
151 }
152 else
153 {
154 GNUNET_TESTING_get_trait_block_state (
155 &block_receive,
156 (const struct BlockState **) &bs);
157 bs->asynchronous_finish = GNUNET_YES;
158 }
159
160 }
161 }
162 GNUNET_TRANSPORT_core_receive_continue (ch, peer);
163}
164
165
166/**
167 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
168 *
169 */
170static void
171all_peers_started ()
172{
173 const struct GNUNET_TESTING_AsyncContext *ac;
174
175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
176 "Received message\n");
177 GNUNET_TESTING_get_trait_async_context (&block_send,
178 &ac);
179 GNUNET_assert (NULL != ac);
180 if (NULL == ac->cont)
181 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
182 else
183 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
184}
185
186
187/**
188 * Function called with the final result of the test.
189 *
190 * @param cls the `struct MainParams`
191 * @param rv #GNUNET_OK if the test passed
192 */
193static void
194handle_result (void *cls,
195 enum GNUNET_GenericReturnValue rv)
196{
197 struct TestState *ts = cls;
198 struct GNUNET_MessageHeader *reply;
199
200 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
201 "Local test exits with status %d\n",
202 rv);
203 reply = GNUNET_TESTING_send_local_test_finished_msg (rv);
204
205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
206 "message prepared\n");
207 ts->write_message (reply,
208 ntohs (reply->size));
209 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
210 "message send\n");
211 GNUNET_free (ts->testdir);
212 GNUNET_free (ts->cfgname);
213 GNUNET_TESTING_free_topology (ts->topology);
214 GNUNET_free (ts);
215}
216
217
218/**
219 * Callback from start peer cmd for signaling a peer got connected.
220 *
221 */
222static void *
223notify_connect (struct GNUNET_TESTING_Interpreter *is,
224 const struct GNUNET_PeerIdentity *peer)
225{
226 const struct ConnectPeersState *cps;
227 const struct GNUNET_TESTING_Command *cmd;
228 void *ret = NULL;
229
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "notify_connect peer %s\n",
232 GNUNET_i2s (peer));
233 cmd = GNUNET_TESTING_interpreter_lookup_command_all (is,
234 "connect-peers");
235 GNUNET_TRANSPORT_get_trait_connect_peer_state (cmd,
236 &cps);
237 cps->notify_connect (is,
238 peer);
239
240 return ret;
241}
242
243
244/**
245 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
246 */
247static void
248all_local_tests_prepared ()
249{
250 const struct LocalPreparedState *lfs;
251
252 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
253 &lfs);
254 GNUNET_assert (NULL != &lfs->ac);
255 if (NULL == lfs->ac.cont)
256 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
257 else
258 GNUNET_TESTING_async_finish ((struct
259 GNUNET_TESTING_AsyncContext *) &lfs->ac);
260}
261
262
263/**
264 * Function to start a local test case.
265 *
266 * @param write_message Callback to send a message to the master loop.
267 * @param router_ip Global address of the network namespace.
268 * @param node_ip Local address of a node i a network namespace.
269 * @param m The number of the node in a network namespace.
270 * @param n The number of the network namespace.
271 * @param local_m The number of nodes in a network namespace.
272 */
273static void
274start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
275 char *node_ip,
276 char *m,
277 char *n,
278 char *local_m,
279 char *topology_data,
280 unsigned int *read_file)
281{
282 unsigned int n_int;
283 unsigned int m_int;
284 unsigned int local_m_int;
285 unsigned int num;
286 struct TestState *ts = GNUNET_new (struct TestState);
287 struct GNUNET_TESTING_NetjailTopology *topology;
288 struct GNUNET_MQ_MessageHandler handlers[] = {
289 GNUNET_MQ_hd_var_size (test,
290 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
291 struct GNUNET_TRANSPORT_TESTING_TestMessage,
292 ts),
293 GNUNET_MQ_handler_end ()
294 };
295
296 if (GNUNET_YES == *read_file)
297 {
298 LOG (GNUNET_ERROR_TYPE_DEBUG,
299 "read from file\n");
300 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
301 }
302 else
303 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
304
305 ts->topology = topology;
306
307 sscanf (m, "%u", &m_int);
308 sscanf (n, "%u", &n_int);
309 sscanf (local_m, "%u", &local_m_int);
310
311 if (0 == n_int)
312 num = m_int;
313 else
314 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
315
316 block_send = GNUNET_TESTING_cmd_block_until_external_trigger ("block");
317 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
318 "block-receive");
319 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers (
320 "connect-peers",
321 "start-peer",
322 "system-create",
323 num,
324 topology,
325 topology->additional_connects);
326 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
327 "local-test-prepared",
328 write_message);
329
330
331 GNUNET_asprintf (&ts->cfgname,
332 "test_transport_api2_tcp_node1.conf");
333
334 LOG (GNUNET_ERROR_TYPE_DEBUG,
335 "plugin cfgname: %s\n",
336 ts->cfgname);
337
338 LOG (GNUNET_ERROR_TYPE_DEBUG,
339 "node ip: %s\n",
340 node_ip);
341
342 GNUNET_asprintf (&ts->testdir,
343 "%s%s%s",
344 BASE_DIR,
345 m,
346 n);
347
348 start_peer = GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
349 "system-create",
350 num,
351 node_ip,
352 handlers,
353 ts->cfgname,
354 notify_connect,
355 GNUNET_NO);
356 struct GNUNET_TESTING_Command commands[] = {
357 GNUNET_TESTING_cmd_system_create ("system-create",
358 ts->testdir),
359 start_peer,
360 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
361 write_message),
362 block_send,
363 connect_peers,
364 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
365 "start-peer",
366 "system-create",
367 num,
368 topology),
369 block_receive,
370 local_prepared,
371 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
372 "start-peer"),
373 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
374 "system-create"),
375 GNUNET_TESTING_cmd_end ()
376 };
377
378 ts->write_message = write_message;
379
380 GNUNET_TESTING_run (commands,
381 GNUNET_TIME_UNIT_FOREVER_REL,
382 &handle_result,
383 ts);
384
385}
386
387
388/**
389 * Entry point for the plugin.
390 *
391 * @param cls NULL
392 * @return the exported block API
393 */
394void *
395libgnunet_test_transport_plugin_cmd_simple_send_dv_init (void *cls)
396{
397 struct GNUNET_TESTING_PluginFunctions *api;
398
399 GNUNET_log_setup ("simple-send",
400 "DEBUG",
401 NULL);
402
403 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
404 api->start_testcase = &start_testcase;
405 api->all_peers_started = &all_peers_started;
406 api->all_local_tests_prepared = all_local_tests_prepared;
407 return api;
408}
409
410
411/**
412 * Exit point from the plugin.
413 *
414 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
415 * @return NULL
416 */
417void *
418libgnunet_test_transport_plugin_cmd_simple_send_dv_done (void *cls)
419{
420 struct GNUNET_TESTING_PluginFunctions *api = cls;
421
422 GNUNET_free (api);
423 return NULL;
424}
425
426
427/* end of plugin_cmd_simple_send_broadcast.c */
diff --git a/src/transport/test_transport_plugin_cmd_udp_backchannel.c b/src/transport/test_transport_plugin_cmd_udp_backchannel.c
deleted file mode 100644
index 537832e61..000000000
--- a/src/transport/test_transport_plugin_cmd_udp_backchannel.c
+++ /dev/null
@@ -1,356 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testbed/plugin_cmd_simple_send.c
23 * @brief a plugin to provide the API for running test cases.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "gnunet_util_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "transport-testing2.h"
32#include "transport-testing-cmds.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39#define BASE_DIR "testdir"
40
41#define TOPOLOGY_CONFIG "test_transport_udp_backchannel_topo.conf"
42
43struct TestState
44{
45 /**
46 * Callback to write messages to the master loop.
47 *
48 */
49 TESTING_CMD_HELPER_write_cb write_message;
50
51 /**
52 * The name for a specific test environment directory.
53 *
54 */
55 char *testdir;
56
57 /**
58 * The name for the configuration file of the specific node.
59 *
60 */
61 char *cfgname;
62
63 /**
64 * The complete topology information.
65 */
66 struct GNUNET_TESTING_NetjailTopology *topology;
67};
68
69static struct GNUNET_TESTING_Command block_send;
70
71static struct GNUNET_TESTING_Command connect_peers;
72
73static struct GNUNET_TESTING_Command local_prepared;
74
75
76/**
77 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
78 * received.
79 *
80 */
81static int
82check_test (void *cls,
83 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
84{
85 return GNUNET_OK;
86}
87
88
89/**
90 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
91 * being received.
92 *
93 */
94static void
95handle_test (void *cls,
96 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
97{
98 // struct GNUNET_TESTING_AsyncContext *ac;
99
100 /*GNUNET_TESTING_get_trait_async_context (&block_receive,
101 &ac);
102 if ((NULL == ac) || (NULL == ac->cont))
103 GNUNET_TESTING_async_fail (ac);
104 else
105 GNUNET_TESTING_async_finish (ac);*/
106}
107
108
109/**
110 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
111 *
112 */
113static void
114all_peers_started ()
115{
116 const struct GNUNET_TESTING_AsyncContext *ac;
117
118 GNUNET_TESTING_get_trait_async_context (&block_send,
119 &ac);
120 GNUNET_assert (NULL != ac);
121 if ((NULL == ac->cont))
122 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
123 else
124 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
125}
126
127
128/**
129* Function called with the final result of the test.
130*
131* @param cls the `struct MainParams`
132* @param rv #GNUNET_OK if the test passed
133*/
134static void
135handle_result (void *cls,
136 enum GNUNET_GenericReturnValue rv)
137{
138 struct TestState *ts = cls;
139 struct GNUNET_MessageHeader *reply;
140
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "Local test exits with status %d\n",
143 rv);
144 reply = GNUNET_TESTING_send_local_test_finished_msg (rv);
145
146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
147 "message prepared\n");
148 ts->write_message (reply,
149 ntohs (reply->size));
150
151 GNUNET_free (ts->testdir);
152 GNUNET_free (ts->cfgname);
153 GNUNET_TESTING_free_topology (ts->topology);
154 GNUNET_free (ts);
155}
156
157
158/**
159 * Callback from start peer cmd for signaling a peer got connected.
160 *
161 */
162static void *
163notify_connect (struct GNUNET_TESTING_Interpreter *is,
164 const struct GNUNET_PeerIdentity *peer)
165{
166 const struct ConnectPeersState *cps;
167
168 GNUNET_TRANSPORT_get_trait_connect_peer_state (&connect_peers,
169 &cps);
170 void *ret = NULL;
171
172 cps->notify_connect (is,
173 peer);
174 return ret;
175}
176
177/**
178 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
179 */
180static void
181all_local_tests_prepared ()
182{
183 const struct LocalPreparedState *lfs;
184
185 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
186 &lfs);
187 GNUNET_assert (NULL != &lfs->ac);
188 if (NULL == lfs->ac.cont)
189 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
190 else
191 GNUNET_TESTING_async_finish ((struct
192 GNUNET_TESTING_AsyncContext *) &lfs->ac);
193}
194
195/**
196 * Function to start a local test case.
197 *
198 * @param write_message Callback to send a message to the master loop.
199 * @param router_ip Global address of the network namespace.
200 * @param node_ip Local address of a node i a network namespace.
201 * @param m The number of the node in a network namespace.
202 * @param n The number of the network namespace.
203 * @param local_m The number of nodes in a network namespace.
204 */
205static void
206start_testcase (TESTING_CMD_HELPER_write_cb write_message, char *router_ip,
207 char *node_ip,
208 char *m,
209 char *n,
210 char *local_m,
211 char *topology_data,
212 unsigned int *read_file)
213{
214
215 unsigned int n_int;
216 unsigned int m_int;
217 unsigned int local_m_int;
218 unsigned int num;
219 struct TestState *ts = GNUNET_new (struct TestState);
220
221 struct GNUNET_TESTING_NetjailTopology *topology;
222
223 if (GNUNET_YES == *read_file)
224 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
225 else
226 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
227
228 ts->topology = topology;
229
230 sscanf (m, "%u", &m_int);
231 sscanf (n, "%u", &n_int);
232 sscanf (local_m, "%u", &local_m_int);
233
234
235 if (0 == n_int)
236 num = m_int;
237 else
238 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
239
240 block_send = GNUNET_TESTING_cmd_block_until_external_trigger (
241 "block");
242 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
243 "start-peer",
244 "system-create",
245 num,
246 topology,
247 0);
248 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
249 "local-test-prepared",
250 write_message);
251
252 GNUNET_asprintf (&ts->cfgname,
253 "test_transport_api2_tcp_node1.conf");
254
255 LOG (GNUNET_ERROR_TYPE_DEBUG,
256 "plugin cfgname: %s\n",
257 ts->cfgname);
258
259 LOG (GNUNET_ERROR_TYPE_DEBUG,
260 "node ip: %s\n",
261 node_ip);
262
263 GNUNET_asprintf (&ts->testdir,
264 "%s%s%s",
265 BASE_DIR,
266 m,
267 n);
268
269 struct GNUNET_MQ_MessageHandler handlers[] = {
270 GNUNET_MQ_hd_var_size (test,
271 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
272 struct GNUNET_TRANSPORT_TESTING_TestMessage,
273 NULL),
274 GNUNET_MQ_handler_end ()
275 };
276
277 struct GNUNET_TESTING_Command commands[] = {
278 GNUNET_TESTING_cmd_system_create ("system-create",
279 ts->testdir),
280 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
281 "system-create",
282 num,
283 node_ip,
284 handlers,
285 ts->cfgname,
286 notify_connect,
287 GNUNET_NO),
288 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
289 write_message),
290 block_send,
291 connect_peers,
292 GNUNET_TRANSPORT_cmd_backchannel_check ("backchannel-check",
293 "start-peer",
294 "system-create",
295 num,
296 m_int,
297 n_int,
298 topology),
299 local_prepared,
300 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
301 "start-peer"),
302 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
303 "system-create"),
304 GNUNET_TESTING_cmd_end ()
305 };
306
307 ts->write_message = write_message;
308
309 GNUNET_TESTING_run (commands,
310 GNUNET_TIME_UNIT_FOREVER_REL,
311 &handle_result,
312 ts);
313
314}
315
316
317/**
318 * Entry point for the plugin.
319 *
320 * @param cls NULL
321 * @return the exported block API
322 */
323void *
324libgnunet_test_transport_plugin_cmd_udp_backchannel_init (void *cls)
325{
326 struct GNUNET_TESTING_PluginFunctions *api;
327
328 GNUNET_log_setup ("udp-backchannel",
329 "DEBUG",
330 NULL);
331
332 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
333 api->start_testcase = &start_testcase;
334 api->all_peers_started = &all_peers_started;
335 api->all_local_tests_prepared = all_local_tests_prepared;
336 return api;
337}
338
339
340/**
341 * Exit point from the plugin.
342 *
343 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
344 * @return NULL
345 */
346void *
347libgnunet_test_transport_plugin_cmd_udp_backchannel_done (void *cls)
348{
349 struct GNUNET_TESTING_PluginFunctions *api = cls;
350
351 GNUNET_free (api);
352 return NULL;
353}
354
355
356/* end of plugin_cmd_simple_send.c */
diff --git a/src/transport/test_transport_simple_send.sh b/src/transport/test_transport_simple_send.sh
deleted file mode 100755
index 0250070be..000000000
--- a/src/transport/test_transport_simple_send.sh
+++ /dev/null
@@ -1,11 +0,0 @@
1#!/bin/bash
2if ! [ -d "/run/netns" ]; then
3 echo You have to create the directory /run/netns.
4fi
5if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
6 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
7 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
8 exit 78
9 fi
10fi
11exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config test_transport_simple_send_topo.conf"
diff --git a/src/transport/test_transport_simple_send_broadcast.sh b/src/transport/test_transport_simple_send_broadcast.sh
deleted file mode 100755
index a4801bf70..000000000
--- a/src/transport/test_transport_simple_send_broadcast.sh
+++ /dev/null
@@ -1,11 +0,0 @@
1#!/bin/bash
2if ! [ -d "/run/netns" ]; then
3 echo You have to create the directory /run/netns.
4fi
5if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
6 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
7 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
8 exit 78
9 fi
10fi
11exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config test_transport_simple_send_broadcast_topo.conf"
diff --git a/src/transport/test_transport_simple_send_broadcast_topo.conf b/src/transport/test_transport_simple_send_broadcast_topo.conf
deleted file mode 100644
index aa4964f81..000000000
--- a/src/transport/test_transport_simple_send_broadcast_topo.conf
+++ /dev/null
@@ -1,4 +0,0 @@
1M:2
2N:1
3X:0
4T:libgnunet_test_transport_plugin_cmd_simple_send_broadcast \ No newline at end of file
diff --git a/src/transport/test_transport_simple_send_dv.sh b/src/transport/test_transport_simple_send_dv.sh
deleted file mode 100755
index b57ee0629..000000000
--- a/src/transport/test_transport_simple_send_dv.sh
+++ /dev/null
@@ -1,11 +0,0 @@
1#!/bin/bash
2if ! [ -d "/run/netns" ]; then
3 echo You have to create the directory /run/netns.
4fi
5if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
6 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
7 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
8 exit 78
9 fi
10fi
11exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config test_transport_distance_vector_topo.conf"
diff --git a/src/transport/test_transport_simple_send_dv_circle.sh b/src/transport/test_transport_simple_send_dv_circle.sh
deleted file mode 100755
index bd5f00abe..000000000
--- a/src/transport/test_transport_simple_send_dv_circle.sh
+++ /dev/null
@@ -1,11 +0,0 @@
1#!/bin/bash
2if ! [ -d "/run/netns" ]; then
3 echo You have to create the directory /run/netns.
4fi
5if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
6 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
7 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
8 exit 78
9 fi
10fi
11exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config test_transport_distance_vector_circle_topo.conf"
diff --git a/src/transport/test_transport_simple_send_string.sh b/src/transport/test_transport_simple_send_string.sh
deleted file mode 100755
index 211abb494..000000000
--- a/src/transport/test_transport_simple_send_string.sh
+++ /dev/null
@@ -1,21 +0,0 @@
1#!/bin/bash
2string=$(cat << EOF
3M:2
4N:1
5X:0
6T:libgnunet_test_transport_plugin_cmd_simple_send
7P:1:1|{connect:{P:1:2:tcp}}
8P:1:2|{connect:{P:1:1:tcp}}
9EOF
10 )
11if ! [ -d "/run/netns" ]; then
12 echo You have to create the directory /run/netns.
13fi
14if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
15 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
16 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
17 exit 78
18 fi
19fi
20
21exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config -s '$string'"
diff --git a/src/transport/test_transport_simple_send_topo.conf b/src/transport/test_transport_simple_send_topo.conf
deleted file mode 100644
index 2c16201f5..000000000
--- a/src/transport/test_transport_simple_send_topo.conf
+++ /dev/null
@@ -1,6 +0,0 @@
1M:2
2N:1
3X:0
4T:libgnunet_test_transport_plugin_cmd_simple_send
5P:1:1|{connect:{P:1:2:tcp}}
6P:1:2|{connect:{P:1:1:tcp}} \ No newline at end of file
diff --git a/src/transport/test_transport_start_with_config.c b/src/transport/test_transport_start_with_config.c
deleted file mode 100644
index 0c3271436..000000000
--- a/src/transport/test_transport_start_with_config.c
+++ /dev/null
@@ -1,122 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/test_transport_start_with_config.c
23 * @brief Generic program to start testcases in an configurable topology.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "transport-testing-cmds.h"
30#include "gnunet_util_lib.h"
31
32#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
33
34
35int
36main (int argc,
37 char *const *argv)
38{
39 char *topology_data;
40 char *topology_data_script;
41 struct GNUNET_TESTING_NetjailTopology *topology;
42 unsigned int read_file = GNUNET_YES;
43 int ret;
44 char *rest = NULL;
45 char *token;
46 size_t single_line_len;
47 size_t data_len;
48
49 GNUNET_log_setup ("test-netjail",
50 "DEBUG",
51 NULL);
52
53 if (0 == strcmp ("-s", argv[1]))
54 {
55 data_len = strlen (argv[2]);
56 topology_data = GNUNET_malloc (data_len);
57 topology_data_script = GNUNET_malloc (data_len);
58 token = strtok_r (argv[2], "\n", &rest);
59 while (NULL != token)
60 {
61 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
62 "token1 %s\n",
63 token);
64 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
65 "token2 %s\n",
66 token);
67 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
68 "topology_data %s\n",
69 topology_data);
70 strcat (topology_data_script, token);
71 strcat (topology_data_script, " ");
72 strcat (topology_data, token);
73 strcat (topology_data, "\n");
74 token = strtok_r (NULL, "\n", &rest);
75 }
76 single_line_len = strlen (topology_data);
77 topology_data_script [single_line_len - 1] = '\0';
78 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
79 "read from string\n");
80 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
81 "topology_data %s\n",
82 topology_data);
83 read_file = GNUNET_NO;
84 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
85 }
86 else
87 {
88 topology_data = argv[1];
89 topology_data_script = argv[1];
90 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
91 }
92
93 struct GNUNET_TESTING_Command commands[] = {
94 GNUNET_TESTING_cmd_netjail_start ("netjail-start",
95 topology_data_script,
96 &read_file),
97 GNUNET_TESTING_cmd_netjail_start_testing_system ("netjail-start-testbed",
98 topology,
99 &read_file,
100 topology_data_script,
101 TIMEOUT),
102 GNUNET_TESTING_cmd_stop_testing_system ("stop-testbed",
103 "netjail-start-testbed",
104 topology),
105 GNUNET_TESTING_cmd_netjail_stop ("netjail-stop",
106 topology_data_script,
107 &read_file),
108 GNUNET_TESTING_cmd_end ()
109 };
110
111 ret = GNUNET_TESTING_main (commands,
112 TIMEOUT);
113
114 if (0 == strcmp ("-s", argv[1]))
115 {
116 GNUNET_free (topology_data_script);
117 GNUNET_free (topology_data);
118 }
119 GNUNET_TESTING_free_topology (topology);
120
121 return ret;
122}
diff --git a/src/transport/test_transport_test_transport_address_switch_tcp_peer1.conf b/src/transport/test_transport_test_transport_address_switch_tcp_peer1.conf
deleted file mode 100644
index 920e8d199..000000000
--- a/src/transport/test_transport_test_transport_address_switch_tcp_peer1.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer1.conf
2
3[ats]
4UNSPECIFIED_QUOTA_IN = 8 KiB
5UNSPECIFIED_QUOTA_OUT = 8 KiB
6# LOOPBACK
7LOOPBACK_QUOTA_IN = 8 KiB
8LOOPBACK_QUOTA_OUT = 8 KiB
9# LAN
10LAN_QUOTA_IN = 8 KiB
11LAN_QUOTA_OUT = 8 KiB
12# WAN
13WAN_QUOTA_IN = 8 KiB
14WAN_QUOTA_OUT = 8 KiB
15# WLAN
16WLAN_QUOTA_IN = 8 KiB
17WLAN_QUOTA_OUT = 8 KiB
18# BLUETOOTH
19BLUETOOTH_QUOTA_IN = 8 KiB
20BLUETOOTH_QUOTA_OUT = 8 KiB
21
22[PATHS]
23GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/quota-tcp-p1/
24
25[transport]
26PLUGINS = tcp
27
28
29
diff --git a/src/transport/test_transport_test_transport_address_switch_tcp_peer2.conf b/src/transport/test_transport_test_transport_address_switch_tcp_peer2.conf
deleted file mode 100644
index 6855cd00d..000000000
--- a/src/transport/test_transport_test_transport_address_switch_tcp_peer2.conf
+++ /dev/null
@@ -1,29 +0,0 @@
1@INLINE@ template_cfg_peer2.conf
2
3[ats]
4UNSPECIFIED_QUOTA_IN = 8 KiB
5UNSPECIFIED_QUOTA_OUT = 8 KiB
6# LOOPBACK
7LOOPBACK_QUOTA_IN = 8 KiB
8LOOPBACK_QUOTA_OUT = 8 KiB
9# LAN
10LAN_QUOTA_IN = 8 KiB
11LAN_QUOTA_OUT = 8 KiB
12# WAN
13WAN_QUOTA_IN = 8 KiB
14WAN_QUOTA_OUT = 8 KiB
15# WLAN
16WLAN_QUOTA_IN = 8 KiB
17WLAN_QUOTA_OUT = 8 KiB
18# BLUETOOTH
19BLUETOOTH_QUOTA_IN = 8 KiB
20BLUETOOTH_QUOTA_OUT = 8 KiB
21
22
23[PATHS]
24GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
25
26[transport]
27PLUGINS = tcp
28
29
diff --git a/src/transport/test_transport_testing_restart.c b/src/transport/test_transport_testing_restart.c
deleted file mode 100644
index f537af5fc..000000000
--- a/src/transport/test_transport_testing_restart.c
+++ /dev/null
@@ -1,163 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_testing_restart.c
22 * @brief test case for transport testing library:
23 * start the peer, get the HELLO message, restart and stop the peer
24 */
25#include "platform.h"
26#include "gnunet_transport_service.h"
27#include "transport-testing.h"
28
29#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
30
31
32static struct GNUNET_SCHEDULER_Task *timeout_task;
33
34static struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
35
36static struct GNUNET_TRANSPORT_TESTING_Handle *tth;
37
38static int ret;
39
40
41static void
42end ()
43{
44 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
45 "Stopping peers\n");
46 if (NULL != timeout_task)
47 GNUNET_SCHEDULER_cancel (timeout_task);
48 if (NULL != p)
49 GNUNET_TRANSPORT_TESTING_stop_peer (p);
50 if (NULL != tth)
51 GNUNET_TRANSPORT_TESTING_done (tth);
52}
53
54
55static void
56end_badly ()
57{
58 timeout_task = NULL;
59 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
60 "Timeout!\n");
61 end ();
62 ret = GNUNET_SYSERR;
63}
64
65
66static void
67restart_cb (void *cls)
68{
69 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
70 "Peer %u (`%s') successfully restarted\n",
71 p->no,
72 GNUNET_i2s (&p->id));
73 ret = 0;
74 GNUNET_SCHEDULER_add_now (&end,
75 NULL);
76}
77
78
79static void
80restart_task ()
81{
82 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
83 "Peer %u (`%s') restarting\n",
84 p->no,
85 GNUNET_i2s (&p->id));
86 GNUNET_TRANSPORT_TESTING_restart_peer (p,
87 &restart_cb,
88 p);
89}
90
91
92static void
93start_cb (void *cls)
94{
95 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
96 "Peer %u (`%s') successfully started\n",
97 p->no,
98 GNUNET_i2s (&p->id));
99 GNUNET_SCHEDULER_add_now (&restart_task,
100 NULL);
101}
102
103
104static void
105run (void *cls,
106 char *const *args,
107 const char *cfgfile,
108 const struct GNUNET_CONFIGURATION_Handle *cfg)
109{
110 ret = 1;
111 tth = GNUNET_TRANSPORT_TESTING_init ();
112 GNUNET_assert (NULL != tth);
113
114 timeout_task
115 = GNUNET_SCHEDULER_add_delayed (TIMEOUT,
116 &end_badly,
117 NULL);
118 p = GNUNET_TRANSPORT_TESTING_start_peer (tth,
119 cfgfile,
120 1,
121 NULL, /* receive cb */
122 NULL, /* connect cb */
123 NULL, /* disconnect cb */
124 NULL, /* nc/nd closure */
125 start_cb, /* startup cb */
126 NULL); /* closure */
127 if (NULL == p)
128 {
129 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
130 "Failed to start peer\n");
131 end ();
132 ret = 1;
133 }
134}
135
136
137int
138main (int argc,
139 char *argv[])
140{
141 char *const argv_1[] = { "test_transport_testing_restart",
142 "-c",
143 "test_transport_api_data.conf",
144 NULL };
145 struct GNUNET_GETOPT_CommandLineOption options[] = {
146 GNUNET_GETOPT_OPTION_END
147 };
148
149 GNUNET_log_setup ("test_transport_testing_restart",
150 "WARNING",
151 NULL);
152 GNUNET_PROGRAM_run ((sizeof(argv_1) / sizeof(char *)) - 1,
153 argv_1,
154 "test_transport_testing_restart",
155 "nohelp",
156 options,
157 &run,
158 NULL);
159 return ret;
160}
161
162
163/* end of test_transport_testing_restart.c */
diff --git a/src/transport/test_transport_testing_startstop.c b/src/transport/test_transport_testing_startstop.c
deleted file mode 100644
index 4783c1813..000000000
--- a/src/transport/test_transport_testing_startstop.c
+++ /dev/null
@@ -1,138 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009, 2010, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/test_transport_testing_startstop.c
22 * @brief test case for transport testing library:
23 * start the peer, get the HELLO message and stop the peer
24 */
25#include "platform.h"
26#include "gnunet_transport_service.h"
27#include "transport-testing.h"
28
29#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
30
31
32static struct GNUNET_SCHEDULER_Task *timeout_task;
33
34static struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
35
36static struct GNUNET_TRANSPORT_TESTING_Handle *tth;
37
38static int ret;
39
40
41static void
42end ()
43{
44 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
45 "Stopping peers\n");
46 if (NULL != timeout_task)
47 GNUNET_SCHEDULER_cancel (timeout_task);
48 if (NULL != p)
49 GNUNET_TRANSPORT_TESTING_stop_peer (p);
50 if (NULL != tth)
51 GNUNET_TRANSPORT_TESTING_done (tth);
52}
53
54
55static void
56end_badly ()
57{
58 timeout_task = NULL;
59 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
60 "Timeout!\n");
61 end ();
62 ret = GNUNET_SYSERR;
63}
64
65
66static void
67start_cb (void *cls)
68{
69 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
70 "Peer %u (`%s') successfully started\n",
71 p->no,
72 GNUNET_i2s (&p->id));
73 ret = 0;
74 GNUNET_SCHEDULER_add_now (&end,
75 NULL);
76}
77
78
79static void
80run (void *cls,
81 char *const *args,
82 const char *cfgfile,
83 const struct GNUNET_CONFIGURATION_Handle *cfg)
84{
85 ret = 1;
86 tth = GNUNET_TRANSPORT_TESTING_init ();
87 GNUNET_assert (NULL != tth);
88
89 timeout_task =
90 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
91 &end_badly,
92 NULL);
93
94 p = GNUNET_TRANSPORT_TESTING_start_peer (tth,
95 cfgfile,
96 1,
97 NULL, /* receive cb */
98 NULL, /* connect cb */
99 NULL, /* disconnect cb */
100 NULL, /* nc/nd closure */
101 &start_cb, /* startup cb */
102 NULL); /* closure */
103 if (NULL == p)
104 {
105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed to start peer\n");
106 if (timeout_task != NULL)
107 GNUNET_SCHEDULER_cancel (timeout_task);
108 timeout_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
109 }
110}
111
112
113int
114main (int argc, char *argv[])
115{
116 char *const argv_1[] = { "test_transport_testing",
117 "-c",
118 "test_transport_api_data.conf",
119 NULL };
120 struct GNUNET_GETOPT_CommandLineOption options[] = {
121 GNUNET_GETOPT_OPTION_END
122 };
123
124 GNUNET_log_setup ("test_transport_testing_startstop",
125 "WARNING",
126 NULL);
127 GNUNET_PROGRAM_run ((sizeof(argv_1) / sizeof(char *)) - 1,
128 argv_1,
129 "test_transport_testing_startstop", "nohelp",
130 options,
131 &run,
132 &ret);
133
134 return ret;
135}
136
137
138/* end of test_transport_testing_startstop.c */
diff --git a/src/transport/test_transport_udp_backchannel.sh b/src/transport/test_transport_udp_backchannel.sh
deleted file mode 100755
index 1a7c83385..000000000
--- a/src/transport/test_transport_udp_backchannel.sh
+++ /dev/null
@@ -1,14 +0,0 @@
1#!/bin/bash
2if [ -f "test.out" ]; then
3 rm test.out
4fi
5if ! [ -d "/run/netns" ]; then
6 echo You have to create the directory /run/netns.
7fi
8if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
9 if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
10 echo -e "Error during test setup: The kernel parameter kernel.unprivileged_userns_clone has to be set to 1! One has to execute\n\n sysctl kernel.unprivileged_userns_clone=1\n"
11 exit 78
12 fi
13fi
14exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; GNUNET_FORCE_LOG=';;;;DEBUG' GNUNET_FORCE_LOGFILE='test.out' ./test_transport_start_with_config test_transport_udp_backchannel_topo.conf"
diff --git a/src/transport/test_transport_udp_backchannel_topo.conf b/src/transport/test_transport_udp_backchannel_topo.conf
deleted file mode 100644
index ad35bde0a..000000000
--- a/src/transport/test_transport_udp_backchannel_topo.conf
+++ /dev/null
@@ -1,7 +0,0 @@
1M:1
2N:1
3X:1
4T:libgnunet_test_transport_plugin_cmd_udp_backchannel
5K:1|{connect:{P:1:1:tcp}}
6R:1|{tcp_port:1}|{udp_port:0}
7P:1:1|{connect:{K:1:udp}}
diff --git a/src/transport/transport-testing-cmds.h b/src/transport/transport-testing-cmds.h
deleted file mode 100644
index 5a3fb22d6..000000000
--- a/src/transport/transport-testing-cmds.h
+++ /dev/null
@@ -1,347 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport-testing.h
23 * @brief testing lib for transport service
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef TRANSPORT_TESTING_CMDS_H
28#define TRANSPORT_TESTING_CMDS_H
29#include "gnunet_testing_lib.h"
30
31
32typedef void *
33(*GNUNET_TRANSPORT_notify_connect_cb) (struct GNUNET_TESTING_Interpreter *is,
34 const struct GNUNET_PeerIdentity *peer);
35
36/**
37 * Struct to store information needed in callbacks.
38 *
39 */
40struct ConnectPeersState
41{
42 /**
43 * Context for our asynchronous completion.
44 */
45 struct GNUNET_TESTING_AsyncContext ac;
46
47 GNUNET_TRANSPORT_notify_connect_cb notify_connect;
48
49 /**
50 * The testing system of this node.
51 */
52 const struct GNUNET_TESTING_System *tl_system;
53
54 // Label of the cmd which started the test system.
55 const char *create_label;
56
57 /**
58 * Number globally identifying the node.
59 *
60 */
61 uint32_t num;
62
63 /**
64 * Label of the cmd to start a peer.
65 *
66 */
67 const char *start_peer_label;
68
69 /**
70 * The topology of the test setup.
71 */
72 struct GNUNET_TESTING_NetjailTopology *topology;
73
74 /**
75 * Connections to other peers.
76 */
77 struct GNUNET_TESTING_NodeConnection *node_connections_head;
78
79 struct GNUNET_TESTING_Interpreter *is;
80
81 /**
82 * Number of connections.
83 */
84 unsigned int con_num;
85
86 /**
87 * Number of additional connects this cmd will wait for not triggered by this cmd.
88 */
89 unsigned int additional_connects;
90
91 /**
92 * Number of connections we already have a notification for.
93 */
94 unsigned int con_num_notified;
95
96 /**
97 * Number of additional connects this cmd will wait for not triggered by this cmd we already have a notification for.
98 */
99 unsigned int additional_connects_notified;
100};
101
102struct StartPeerState
103{
104 /**
105 * Context for our asynchronous completion.
106 */
107 struct GNUNET_TESTING_AsyncContext ac;
108
109 /**
110 * The ip of a node.
111 */
112 char *node_ip;
113
114 /**
115 * Receive callback
116 */
117 struct GNUNET_MQ_MessageHandler *handlers;
118
119 const char *cfgname;
120
121 /**
122 * Peer's configuration
123 */
124 struct GNUNET_CONFIGURATION_Handle *cfg;
125
126 struct GNUNET_TESTING_Peer *peer;
127
128 /**
129 * Peer identity
130 */
131 struct GNUNET_PeerIdentity id;
132
133 /**
134 * Peer's transport service handle
135 */
136 struct GNUNET_TRANSPORT_CoreHandle *th;
137
138 /**
139 * Application handle
140 */
141 struct GNUNET_TRANSPORT_ApplicationHandle *ah;
142
143 /**
144 * Peer's PEERSTORE Handle
145 */
146 struct GNUNET_PEERSTORE_Handle *ph;
147
148 /**
149 * Hello get task
150 */
151 struct GNUNET_SCHEDULER_Task *rh_task;
152
153 /**
154 * Peer's transport get hello handle to retrieve peer's HELLO message
155 */
156 struct GNUNET_PEERSTORE_IterateContext *pic;
157
158 /**
159 * Hello
160 */
161 char *hello;
162
163 /**
164 * Hello size
165 */
166 size_t hello_size;
167
168 char *m;
169
170 char *n;
171
172 char *local_m;
173
174 const char *system_label;
175
176 /**
177 * An unique number to identify the peer
178 */
179 unsigned int no;
180
181 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
182
183 const struct GNUNET_TESTING_System *tl_system;
184
185 GNUNET_TRANSPORT_notify_connect_cb notify_connect;
186
187 /**
188 * Flag indicating, if udp broadcast should be switched on.
189 */
190 enum GNUNET_GenericReturnValue broadcast;
191};
192
193
194/**
195 * Create command.
196 *
197 * @param label name for command.
198 * @param system_label Label of the cmd to setup a test environment.
199 * @param m The number of the local node of the actual network namespace.
200 * @param n The number of the actual namespace.
201 * @param local_m Number of local nodes in each namespace.
202 * @param handlers Handler for messages received by this peer.
203 * @param cfgname Configuration file name for this peer.
204 * @param notify_connect Method which will be called, when a peer connects.
205 * @param broadcast Flag indicating, if broadcast should be switched on.
206 * @return command.
207 */
208struct GNUNET_TESTING_Command
209GNUNET_TRANSPORT_cmd_start_peer (const char *label,
210 const char *system_label,
211 uint32_t no,
212 char *node_ip,
213 struct GNUNET_MQ_MessageHandler *handlers,
214 const char *cfgname,
215 GNUNET_TRANSPORT_notify_connect_cb
216 notify_connect,
217 unsigned int broadcast);
218
219
220struct GNUNET_TESTING_Command
221GNUNET_TRANSPORT_cmd_stop_peer (const char *label,
222 const char *start_label);
223
224
225/**
226 * Create command
227 *
228 * @param label name for command
229 * @param start_peer_label Label of the cmd to start a peer.
230 * @param create_peer_label Label of the cmd which started the test system.
231 * @param num Number globally identifying the node.
232 * @param The topology for the test setup.
233 * @param additional_connects Number of additional connects this cmd will wait for not triggered by this cmd.
234 * @return command.
235 */
236struct GNUNET_TESTING_Command
237GNUNET_TRANSPORT_cmd_connect_peers (
238 const char *label,
239 const char *start_peer_label,
240 const char *create_label,
241 uint32_t num,
242 struct GNUNET_TESTING_NetjailTopology *topology,
243 unsigned int additional_connects);
244
245
246/**
247 * Create command.
248 *
249 * @param label name for command.
250 * @param start_peer_label Label of the cmd to start a peer.
251 * @param create_peer_label Label of the cmd which started the test system.
252 * @param num Number globally identifying the node.
253 * @param The topology for the test setup.
254 * @return command.
255 */
256struct GNUNET_TESTING_Command
257GNUNET_TRANSPORT_cmd_send_simple (const char *label,
258 const char *start_peer_label,
259 const char *create_label,
260 uint32_t num,
261 struct GNUNET_TESTING_NetjailTopology *
262 topology);
263
264
265/**
266 * Create command.
267 *
268 * @param label name for command.
269 * @param start_peer_label Label of the cmd to start a peer.
270 * @param create_label Label of the cmd to create the testing system.
271 * @param num Number globally identifying the node.
272 * @param node_n The number of the node in a network namespace.
273 * @param namespace_n The number of the network namespace.
274 * @param The topology for the test setup.
275 * @return command.
276 */
277struct GNUNET_TESTING_Command
278GNUNET_TRANSPORT_cmd_backchannel_check (const char *label,
279 const char *start_peer_label,
280 const char *create_label,
281 uint32_t num,
282 unsigned int node_n,
283 unsigned int namespace_n,
284 struct GNUNET_TESTING_NetjailTopology *
285 topology);
286
287
288/**
289 * Create headers for a trait with name @a name for
290 * statically allocated data of type @a type.
291 */
292#define GNUNET_TRANSPORT_MAKE_DECL_SIMPLE_TRAIT(name,type) \
293 enum GNUNET_GenericReturnValue \
294 GNUNET_TRANSPORT_get_trait_ ## name ( \
295 const struct GNUNET_TESTING_Command *cmd, \
296 type **ret); \
297 struct GNUNET_TESTING_Trait \
298 GNUNET_TRANSPORT_make_trait_ ## name ( \
299 type * value);
300
301
302/**
303 * Create C implementation for a trait with name @a name for statically
304 * allocated data of type @a type.
305 */
306#define GNUNET_TRANSPORT_MAKE_IMPL_SIMPLE_TRAIT(name,type) \
307 enum GNUNET_GenericReturnValue \
308 GNUNET_TRANSPORT_get_trait_ ## name ( \
309 const struct GNUNET_TESTING_Command *cmd, \
310 type **ret) \
311 { \
312 if (NULL == cmd->traits) return GNUNET_SYSERR; \
313 return cmd->traits (cmd->cls, \
314 (const void **) ret, \
315 GNUNET_S (name), \
316 0); \
317 } \
318 struct GNUNET_TESTING_Trait \
319 GNUNET_TRANSPORT_make_trait_ ## name ( \
320 type * value) \
321 { \
322 struct GNUNET_TESTING_Trait ret = { \
323 .trait_name = GNUNET_S (name), \
324 .ptr = (const void *) value \
325 }; \
326 return ret; \
327 }
328
329
330/**
331 * Call #op on all simple traits.
332 */
333#define GNUNET_TRANSPORT_SIMPLE_TRAITS(op) \
334 op (peer_id, const struct GNUNET_PeerIdentity) \
335 op (connected_peers_map, const struct GNUNET_CONTAINER_MultiShortmap) \
336 op (hello_size, const size_t) \
337 op (hello, const char) \
338 op (application_handle, const struct GNUNET_TRANSPORT_ApplicationHandle) \
339 op (connect_peer_state, const struct ConnectPeersState) \
340 op (state, const struct StartPeerState) \
341 op (broadcast, const enum GNUNET_GenericReturnValue)
342
343GNUNET_TRANSPORT_SIMPLE_TRAITS (GNUNET_TRANSPORT_MAKE_DECL_SIMPLE_TRAIT)
344
345
346#endif
347/* end of transport_testing.h */
diff --git a/src/transport/transport-testing-communicator.c b/src/transport/transport-testing-communicator.c
deleted file mode 100644
index ce4af01f2..000000000
--- a/src/transport/transport-testing-communicator.c
+++ /dev/null
@@ -1,1227 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport-testing-communicator.c
23 * @brief functions related to testing-tng
24 * @author Christian Grothoff
25 * @author Julius Bünger
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_constants.h"
31#include "transport-testing-communicator.h"
32#include "gnunet_ats_transport_service.h"
33#include "gnunet_hello_lib.h"
34#include "gnunet_signatures.h"
35#include "transport.h"
36#include <inttypes.h>
37
38#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing2", __VA_ARGS__)
39
40struct MyClient
41{
42 struct MyClient *prev;
43 struct MyClient *next;
44 /**
45 * @brief Handle to the client
46 */
47 struct GNUNET_SERVICE_Client *client;
48
49 /**
50 * @brief Handle to the client
51 */
52 struct GNUNET_MQ_Handle *c_mq;
53
54 /**
55 * The TCH
56 */
57 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc;
58
59};
60
61/**
62 * @brief Queue of a communicator and some context
63 */
64struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue
65{
66 /**
67 * @brief Handle to the TransportCommunicator
68 */
69 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h;
70
71 /**
72 * @brief Envelope to a message that requests the opening of the queue.
73 *
74 * If the client already requests queue(s), but the communicator is not yet
75 * connected, we cannot send the request to open the queue. Save it until the
76 * communicator becomes available and send it then.
77 */
78 struct GNUNET_MQ_Envelope *open_queue_env;
79
80 /**
81 * @brief Peer ID of the peer on the other side of the queue
82 */
83 struct GNUNET_PeerIdentity peer_id;
84
85 /**
86 * @brief Queue ID
87 */
88 uint32_t qid;
89
90 /**
91 * @brief Current message id
92 */
93 uint64_t mid;
94
95 /**
96 * An `enum GNUNET_NetworkType` in NBO.
97 */
98 uint32_t nt;
99
100 /**
101 * Maximum transmission unit. UINT32_MAX for unlimited.
102 */
103 uint32_t mtu;
104
105 /**
106 * Queue length. UINT64_MAX for unlimited.
107 */
108 uint64_t q_len;
109
110 /**
111 * Queue prio
112 */
113 uint32_t priority;
114
115 /**
116 * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO.
117 */
118 uint32_t cs;
119
120 /**
121 * @brief Next element inside a DLL
122 */
123 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *next;
124
125 /**
126 * @brief Previous element inside a DLL
127 */
128 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *prev;
129};
130
131
132/**
133 * @brief Handle/Context to a single transmission
134 */
135struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission
136{
137};
138
139
140/**
141 * @brief Check whether incoming msg indicating available communicator is
142 * correct
143 *
144 * @param cls Closure
145 * @param msg Message struct
146 *
147 * @return GNUNET_YES in case message is correct
148 */
149static int
150check_communicator_available (
151 void *cls,
152 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg)
153{
154 uint16_t size;
155
156 size = ntohs (msg->header.size) - sizeof(*msg);
157 if (0 == size)
158 return GNUNET_OK; /* receive-only communicator */
159 GNUNET_MQ_check_zero_termination (msg);
160 return GNUNET_OK;
161}
162
163
164/**
165 * @brief Handle new communicator
166 *
167 * Store characteristics of communicator, call respective client callback.
168 *
169 * @param cls Closure - communicator handle
170 * @param msg Message struct
171 */
172static void
173handle_communicator_available (
174 void *cls,
175 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg)
176{
177 struct MyClient *client = cls;
178 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
179 client->tc;
180 uint16_t size;
181 tc_h->c_mq = client->c_mq;
182
183 size = ntohs (msg->header.size) - sizeof(*msg);
184 if (0 == size)
185 {
186 GNUNET_SERVICE_client_continue (client->client);
187 return; /* receive-only communicator */
188 }
189 tc_h->c_characteristics = ntohl (msg->cc);
190 tc_h->c_addr_prefix = GNUNET_strdup ((const char *) &msg[1]);
191 if (NULL != tc_h->communicator_available_cb)
192 {
193 LOG (GNUNET_ERROR_TYPE_DEBUG, "calling communicator_available_cb()\n");
194 tc_h->communicator_available_cb (tc_h->cb_cls,
195 tc_h,
196 tc_h->c_characteristics,
197 tc_h->c_addr_prefix);
198 }
199 GNUNET_SERVICE_client_continue (client->client);
200 LOG (GNUNET_ERROR_TYPE_DEBUG, "finished communicator_available_cb()\n");
201
202}
203
204
205/**
206 * Incoming message. Test message is well-formed.
207 *
208 * @param cls the client
209 * @param msg the send message that was sent
210 * @return #GNUNET_OK if message is well-formed
211 */
212static int
213check_communicator_backchannel (void *cls,
214 const struct
215 GNUNET_TRANSPORT_CommunicatorBackchannel *msg)
216{
217 // struct TransportClient *tc = cls;
218
219 // if (CT_COMMUNICATOR != tc->type)
220 // {
221 // GNUNET_break (0);
222 // return GNUNET_SYSERR;
223 // }
224 // GNUNET_MQ_check_boxed_message (msg);
225 return GNUNET_OK;
226}
227
228
229/**
230 * @brief Receive an incoming message.
231 *
232 * Pass the message to the client.
233 *
234 * @param cls Closure - communicator handle
235 * @param msg Message
236 */
237static void
238handle_communicator_backchannel (void *cls,
239 const struct
240 GNUNET_TRANSPORT_CommunicatorBackchannel *
241 bc_msg)
242{
243 struct MyClient *client = cls;
244 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
245 client->tc;
246 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *other_tc_h;
247 struct GNUNET_MessageHeader *msg;
248 msg = (struct GNUNET_MessageHeader *) &bc_msg[1];
249 uint16_t isize = ntohs (msg->size);
250 const char *target_communicator = ((const char *) msg) + isize;
251 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
252 struct GNUNET_MQ_Envelope *env;
253
254 LOG (GNUNET_ERROR_TYPE_DEBUG,
255 "Received backchannel message\n");
256 if (tc_h->bc_enabled != GNUNET_YES)
257 {
258 GNUNET_SERVICE_client_continue (client->client);
259 return;
260 }
261 /* Find client providing this communicator */
262 /* Finally, deliver backchannel message to communicator */
263 LOG (GNUNET_ERROR_TYPE_DEBUG,
264 "Delivering backchannel message of type %u to %s\n",
265 ntohs (msg->type),
266 target_communicator);
267 other_tc_h = tc_h->bc_cb (tc_h, msg, (struct
268 GNUNET_PeerIdentity*) &bc_msg->pid);
269 env = GNUNET_MQ_msg_extra (
270 cbi,
271 isize,
272 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
273 cbi->pid = tc_h->peer_id;
274 memcpy (&cbi[1], msg, isize);
275
276
277 GNUNET_MQ_send (other_tc_h->c_mq, env);
278 GNUNET_SERVICE_client_continue (client->client);
279}
280
281
282/**
283 * Address of our peer added. Test message is well-formed.
284 *
285 * @param cls the client
286 * @param aam the send message that was sent
287 * @return #GNUNET_OK if message is well-formed
288 */
289static int
290check_add_address (void *cls,
291 const struct GNUNET_TRANSPORT_AddAddressMessage *msg)
292{
293 // if (CT_COMMUNICATOR != tc->type)
294 // {
295 // GNUNET_break (0);
296 // return GNUNET_SYSERR;
297 // }
298 GNUNET_MQ_check_zero_termination (msg);
299 return GNUNET_OK;
300}
301
302
303/**
304 * @brief The communicator informs about an address.
305 *
306 * Store address and call client callback.
307 *
308 * @param cls Closure - communicator handle
309 * @param msg Message
310 */
311static void
312handle_add_address (void *cls,
313 const struct GNUNET_TRANSPORT_AddAddressMessage *msg)
314{
315 struct MyClient *client = cls;
316 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
317 client->tc;
318 uint16_t size;
319 size = ntohs (msg->header.size) - sizeof(*msg);
320 LOG (GNUNET_ERROR_TYPE_DEBUG, "received add address cb %u\n", size);
321 if (0 == size)
322 return; /* receive-only communicator */
323 LOG (GNUNET_ERROR_TYPE_DEBUG, "received add address cb %u\n", size);
324 tc_h->c_address = GNUNET_strdup ((const char *) &msg[1]);
325 if (NULL != tc_h->add_address_cb)
326 {
327 LOG (GNUNET_ERROR_TYPE_DEBUG, "calling add_address_cb()\n");
328 tc_h->add_address_cb (tc_h->cb_cls,
329 tc_h,
330 tc_h->c_address,
331 GNUNET_TIME_relative_ntoh (msg->expiration),
332 msg->aid,
333 ntohl (msg->nt));
334 }
335 GNUNET_SERVICE_client_continue (client->client);
336}
337
338
339/**
340 * Incoming message. Test message is well-formed.
341 *
342 * @param cls the client
343 * @param msg the send message that was sent
344 * @return #GNUNET_OK if message is well-formed
345 */
346static int
347check_incoming_msg (void *cls,
348 const struct GNUNET_TRANSPORT_IncomingMessage *msg)
349{
350 // struct TransportClient *tc = cls;
351
352 // if (CT_COMMUNICATOR != tc->type)
353 // {
354 // GNUNET_break (0);
355 // return GNUNET_SYSERR;
356 // }
357 GNUNET_MQ_check_boxed_message (msg);
358 return GNUNET_OK;
359}
360
361
362/**
363 * @brief Receive an incoming message.
364 *
365 * Pass the message to the client.
366 *
367 * @param cls Closure - communicator handle
368 * @param msg Message
369 */
370static void
371handle_incoming_msg (void *cls,
372 const struct GNUNET_TRANSPORT_IncomingMessage *inc_msg)
373{
374 struct MyClient *client = cls;
375 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
376 client->tc;
377 struct GNUNET_MessageHeader *msg;
378 msg = (struct GNUNET_MessageHeader *) &inc_msg[1];
379 size_t payload_len = ntohs (msg->size) - sizeof (struct
380 GNUNET_MessageHeader);
381 if (NULL != tc_h->incoming_msg_cb)
382 {
383 tc_h->incoming_msg_cb (tc_h->cb_cls,
384 tc_h,
385 (char*) &msg[1],
386 payload_len);
387 }
388 else
389 {
390 LOG (GNUNET_ERROR_TYPE_WARNING,
391 "Incoming message from communicator but no handler!\n");
392 }
393 if (GNUNET_YES == ntohl (inc_msg->fc_on))
394 {
395 /* send ACK when done to communicator for flow control! */
396 struct GNUNET_MQ_Envelope *env;
397 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
398
399 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
400 GNUNET_assert (NULL != env);
401 ack->reserved = htonl (0);
402 ack->fc_id = inc_msg->fc_id;
403 ack->sender = inc_msg->sender;
404 GNUNET_MQ_send (tc_h->c_mq, env);
405 }
406
407 GNUNET_SERVICE_client_continue (client->client);
408}
409
410
411/**
412 * @brief Communicator informs that it tries to establish requested queue
413 *
414 * @param cls Closure - communicator handle
415 * @param msg Message
416 */
417static void
418handle_queue_create_ok (void *cls,
419 const struct GNUNET_TRANSPORT_CreateQueueResponse *msg)
420{
421 struct MyClient *client = cls;
422 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
423 client->tc;
424
425 if (NULL != tc_h->queue_create_reply_cb)
426 {
427 tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_YES);
428 }
429 GNUNET_SERVICE_client_continue (client->client);
430}
431
432
433/**
434 * @brief Communicator informs that it won't try establishing requested queue.
435 *
436 * It will not do so probably because the address is bougus (see comment to
437 * #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL)
438 *
439 * @param cls Closure - communicator handle
440 * @param msg Message
441 */
442static void
443handle_queue_create_fail (
444 void *cls,
445 const struct GNUNET_TRANSPORT_CreateQueueResponse *msg)
446{
447 struct MyClient *client = cls;
448 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
449 client->tc;
450
451 if (NULL != tc_h->queue_create_reply_cb)
452 {
453 tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_NO);
454 }
455 GNUNET_SERVICE_client_continue (client->client);
456}
457
458
459/**
460 * New queue became available. Check message.
461 *
462 * @param cls the client
463 * @param aqm the send message that was sent
464 */
465static int
466check_add_queue_message (void *cls,
467 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
468{
469 GNUNET_MQ_check_zero_termination (aqm);
470 return GNUNET_OK;
471}
472
473
474/**
475 * @brief Handle new queue
476 *
477 * Store context and call client callback.
478 *
479 * @param cls Closure - communicator handle
480 * @param msg Message struct
481 */
482static void
483handle_add_queue_message (void *cls,
484 const struct GNUNET_TRANSPORT_AddQueueMessage *msg)
485{
486 struct MyClient *client = cls;
487 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
488 client->tc;
489 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
490
491 LOG (GNUNET_ERROR_TYPE_DEBUG,
492 "Got queue with ID %u\n", msg->qid);
493 for (tc_queue = tc_h->queue_head; NULL != tc_queue; tc_queue = tc_queue->next)
494 {
495 if (tc_queue->qid == msg->qid)
496 break;
497 }
498 if (NULL == tc_queue)
499 {
500 tc_queue =
501 GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue);
502 tc_queue->tc_h = tc_h;
503 tc_queue->qid = msg->qid;
504 tc_queue->peer_id = msg->receiver;
505 GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue);
506 }
507 GNUNET_assert (tc_queue->qid == msg->qid);
508 GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver));
509 tc_queue->nt = msg->nt;
510 tc_queue->mtu = ntohl (msg->mtu);
511 tc_queue->cs = msg->cs;
512 tc_queue->priority = ntohl (msg->priority);
513 tc_queue->q_len = GNUNET_ntohll (msg->q_len);
514 if (NULL != tc_h->add_queue_cb)
515 {
516 tc_h->add_queue_cb (tc_h->cb_cls, tc_h, tc_queue, tc_queue->mtu);
517 }
518 GNUNET_SERVICE_client_continue (client->client);
519}
520
521
522/**
523 * @brief Handle new queue
524 *
525 * Store context and call client callback.
526 *
527 * @param cls Closure - communicator handle
528 * @param msg Message struct
529 */
530static void
531handle_update_queue_message (void *cls,
532 const struct
533 GNUNET_TRANSPORT_UpdateQueueMessage *msg)
534{
535 struct MyClient *client = cls;
536 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
537 client->tc;
538 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
539
540 LOG (GNUNET_ERROR_TYPE_DEBUG,
541 "Received queue update message for %u with q_len %" PRIu64 "\n",
542 msg->qid, GNUNET_ntohll (msg->q_len));
543 tc_queue = tc_h->queue_head;
544 if (NULL != tc_queue)
545 {
546 while (tc_queue->qid != msg->qid)
547 {
548 tc_queue = tc_queue->next;
549 }
550 }
551 if (NULL == tc_queue)
552 {
553 GNUNET_SERVICE_client_continue (client->client);
554 return;
555 }
556 GNUNET_assert (tc_queue->qid == msg->qid);
557 GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver));
558 tc_queue->nt = msg->nt;
559 tc_queue->mtu = ntohl (msg->mtu);
560 tc_queue->cs = msg->cs;
561 tc_queue->priority = ntohl (msg->priority);
562 // Uncomment this for alternativ 1 of backchannel functionality
563 tc_queue->q_len += GNUNET_ntohll (msg->q_len);
564 // Until here for alternativ 1
565 // Uncomment this for alternativ 2 of backchannel functionality
566 // tc_queue->q_len = GNUNET_ntohll (msg->q_len);
567 // Until here for alternativ 2
568 GNUNET_SERVICE_client_continue (client->client);
569}
570
571
572/**
573 * @brief Shut down the service
574 *
575 * @param cls Closure - Handle to the service
576 */
577static void
578shutdown_service (void *cls)
579{
580 struct GNUNET_SERVICE_Handle *h = cls;
581
582 LOG (GNUNET_ERROR_TYPE_DEBUG,
583 "Shutting down service!\n");
584
585 GNUNET_SERVICE_stop (h);
586}
587
588
589/**
590 * @brief Callback called when new Client (Communicator) connects
591 *
592 * @param cls Closure - TransporCommmunicator Handle
593 * @param client Client
594 * @param mq Messagequeue
595 *
596 * @return TransportCommunicator Handle
597 */
598static void *
599connect_cb (void *cls,
600 struct GNUNET_SERVICE_Client *client,
601 struct GNUNET_MQ_Handle *mq)
602{
603 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
604 struct MyClient *new_c;
605
606 LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected to %p.\n",
607 client, tc_h);
608 new_c = GNUNET_new (struct MyClient);
609 new_c->client = client;
610 new_c->c_mq = mq;
611 new_c->tc = tc_h;
612 GNUNET_CONTAINER_DLL_insert (tc_h->client_head,
613 tc_h->client_tail,
614 new_c);
615
616 if (NULL == tc_h->queue_head)
617 return new_c;
618 /* Iterate over queues. They are yet to be opened. Request opening. */
619 for (struct
620 GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_iter =
621 tc_h->queue_head;
622 NULL != tc_queue_iter;
623 tc_queue_iter = tc_queue_iter->next)
624 {
625 if (NULL == tc_queue_iter->open_queue_env)
626 continue;
627 /* Send the previously created mq envelope to request the creation of the
628 * queue. */
629 GNUNET_MQ_send (tc_h->c_mq,
630 tc_queue_iter->open_queue_env);
631 tc_queue_iter->open_queue_env = NULL;
632 }
633 return new_c;
634}
635
636
637/**
638 * @brief Callback called when Client disconnects
639 *
640 * @param cls Closure - TransportCommunicator Handle
641 * @param client Client
642 * @param internal_cls TransporCommmunicator Handle
643 */
644static void
645disconnect_cb (void *cls,
646 struct GNUNET_SERVICE_Client *client,
647 void *internal_cls)
648{
649 struct MyClient *cl = cls;
650 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
651
652 for (cl = tc_h->client_head; NULL != cl; cl = cl->next)
653 {
654 if (cl->client != client)
655 continue;
656 GNUNET_CONTAINER_DLL_remove (tc_h->client_head,
657 tc_h->client_tail,
658 cl);
659 if (cl->c_mq == tc_h->c_mq)
660 tc_h->c_mq = NULL;
661 GNUNET_free (cl);
662 break;
663 }
664 LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected.\n");
665}
666
667
668/**
669 * Message was transmitted. Process the request.
670 *
671 * @param cls the client
672 * @param sma the send message that was sent
673 */
674static void
675handle_send_message_ack (void *cls,
676 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
677{
678 struct MyClient *client = cls;
679 GNUNET_SERVICE_client_continue (client->client);
680 // NOP
681}
682
683
684/**
685 * @brief Start the communicator part of the transport service
686 *
687 * @param communicator_available Callback to be called when a new communicator
688 * becomes available
689 * @param cfg Configuration
690 */
691static void
692transport_communicator_start (
693 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
694{
695 struct GNUNET_MQ_MessageHandler mh[] = {
696 GNUNET_MQ_hd_var_size (communicator_available,
697 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
698 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
699 tc_h),
700 GNUNET_MQ_hd_var_size (communicator_backchannel,
701 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
702 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
703 tc_h),
704 GNUNET_MQ_hd_var_size (add_address,
705 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
706 struct GNUNET_TRANSPORT_AddAddressMessage,
707 tc_h),
708 // GNUNET_MQ_hd_fixed_size (del_address,
709 // GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
710 // struct GNUNET_TRANSPORT_DelAddressMessage,
711 // NULL),
712 GNUNET_MQ_hd_var_size (incoming_msg,
713 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
714 struct GNUNET_TRANSPORT_IncomingMessage,
715 tc_h),
716 GNUNET_MQ_hd_fixed_size (queue_create_ok,
717 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
718 struct GNUNET_TRANSPORT_CreateQueueResponse,
719 tc_h),
720 GNUNET_MQ_hd_fixed_size (queue_create_fail,
721 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
722 struct GNUNET_TRANSPORT_CreateQueueResponse,
723 tc_h),
724 GNUNET_MQ_hd_var_size (add_queue_message,
725 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
726 struct GNUNET_TRANSPORT_AddQueueMessage,
727 tc_h),
728 GNUNET_MQ_hd_fixed_size (update_queue_message,
729 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE,
730 struct GNUNET_TRANSPORT_UpdateQueueMessage,
731 tc_h),
732 // GNUNET_MQ_hd_fixed_size (del_queue_message,
733 // GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
734 // struct GNUNET_TRANSPORT_DelQueueMessage,
735 // NULL),
736 GNUNET_MQ_hd_fixed_size (send_message_ack,
737 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
738 struct GNUNET_TRANSPORT_SendMessageToAck,
739 tc_h),
740 GNUNET_MQ_handler_end ()
741 };
742
743
744 tc_h->sh = GNUNET_SERVICE_start ("transport",
745 tc_h->cfg,
746 &connect_cb,
747 &disconnect_cb,
748 tc_h,
749 mh);
750 GNUNET_assert (NULL != tc_h->sh);
751}
752
753
754/**
755 * @brief Task run at shutdown to kill communicator and clean up
756 *
757 * @param cls Closure - Process of communicator
758 */
759static void
760shutdown_process (struct GNUNET_OS_Process *proc)
761{
762 if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
763 {
764 LOG (GNUNET_ERROR_TYPE_WARNING,
765 "Error shutting down process with SIGERM, trying SIGKILL\n");
766 if (0 != GNUNET_OS_process_kill (proc, SIGKILL))
767 {
768 LOG (GNUNET_ERROR_TYPE_ERROR,
769 "Error shutting down process with SIGERM and SIGKILL\n");
770 }
771 }
772 GNUNET_OS_process_destroy (proc);
773}
774
775/**
776 * @brief Task run at shutdown to kill the statistics process
777 *
778 * @param cls Closure - Process of communicator
779 */
780static void
781shutdown_statistics (void *cls)
782{
783 struct GNUNET_OS_Process *proc = cls;
784 shutdown_process (proc);
785}
786
787/**
788 * @brief Task run at shutdown to kill the peerstore process
789 *
790 * @param cls Closure - Process of communicator
791 */
792static void
793shutdown_peerstore (void *cls)
794{
795 struct GNUNET_OS_Process *proc = cls;
796 shutdown_process (proc);
797}
798
799/**
800 * @brief Task run at shutdown to kill a communicator process
801 *
802 * @param cls Closure - Process of communicator
803 */
804static void
805shutdown_communicator (void *cls)
806{
807 struct GNUNET_OS_Process *proc = cls;
808 shutdown_process (proc);
809}
810
811
812/**
813 * @brief Start the communicator
814 *
815 * @param cfgname Name of the communicator
816 */
817static void
818communicator_start (
819 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
820 const char *binary_name)
821{
822 char *binary;
823 char *loprefix;
824 char *section_name;
825
826 LOG (GNUNET_ERROR_TYPE_DEBUG, "communicator_start\n");
827
828 section_name = strchr (binary_name, '-');
829 section_name++;
830
831 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (tc_h->cfg,
832 section_name,
833 "PREFIX",
834 &loprefix))
835 loprefix = GNUNET_strdup ("");
836
837
838 binary = GNUNET_OS_get_libexec_binary_path (binary_name);
839 tc_h->c_proc = GNUNET_OS_start_process_s (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
840 NULL,
841 loprefix,
842 binary,
843 binary_name,
844 "-c",
845 tc_h->cfg_filename,
846 NULL);
847 if (NULL == tc_h->c_proc)
848 {
849 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start communicator!");
850 return;
851 }
852 LOG (GNUNET_ERROR_TYPE_INFO, "started communicator\n");
853 GNUNET_free (binary);
854}
855
856
857/**
858 * @brief Task run at shutdown to kill communicator and clean up
859 *
860 * @param cls Closure - Process of communicator
861 */
862static void
863shutdown_nat (void *cls)
864{
865 struct GNUNET_OS_Process *proc = cls;
866 shutdown_process (proc);
867}
868
869
870/**
871 * @brief Task run at shutdown to kill the resolver process
872 *
873 * @param cls Closure - Process of communicator
874 */
875static void
876shutdown_resolver (void *cls)
877{
878 struct GNUNET_OS_Process *proc = cls;
879 shutdown_process (proc);
880}
881
882
883/**
884 * @brief Start Resolver
885 *
886 */
887static void
888resolver_start (struct
889 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
890{
891 char *binary;
892
893 LOG (GNUNET_ERROR_TYPE_DEBUG, "resolver_start\n");
894 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
895 tc_h->resolver_proc = GNUNET_OS_start_process (
896 GNUNET_OS_INHERIT_STD_OUT_AND_ERR
897 | GNUNET_OS_USE_PIPE_CONTROL,
898 NULL,
899 NULL,
900 NULL,
901 binary,
902 "gnunet-service-resolver",
903 "-c",
904 tc_h->cfg_filename,
905 NULL);
906 if (NULL == tc_h->resolver_proc)
907 {
908 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start resolver service!");
909 return;
910 }
911 LOG (GNUNET_ERROR_TYPE_INFO, "started resolver service\n");
912 GNUNET_free (binary);
913
914}
915
916/**
917 * @brief Start Statistics
918 *
919 */
920static void
921statistics_start (
922 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
923{
924 char *binary;
925
926 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-statistics");
927 tc_h->stat_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
928 NULL,
929 NULL,
930 NULL,
931 binary,
932 "gnunet-service-statistics",
933 "-c",
934 tc_h->cfg_filename,
935 NULL);
936 if (NULL == tc_h->stat_proc)
937 {
938 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start Statistics!");
939 return;
940 }
941 LOG (GNUNET_ERROR_TYPE_INFO, "started Statistics\n");
942 GNUNET_free (binary);
943}
944
945/**
946 * @brief Start Peerstore
947 *
948 */
949static void
950peerstore_start (
951 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
952{
953 char *binary;
954
955 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-peerstore");
956 tc_h->ps_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
957 NULL,
958 NULL,
959 NULL,
960 binary,
961 "gnunet-service-peerstore",
962 "-c",
963 tc_h->cfg_filename,
964 NULL);
965 if (NULL == tc_h->ps_proc)
966 {
967 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start Peerstore!");
968 return;
969 }
970 LOG (GNUNET_ERROR_TYPE_INFO, "started Peerstore\n");
971 GNUNET_free (binary);
972}
973
974/**
975 * @brief Start NAT
976 *
977 */
978static void
979nat_start (
980 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
981{
982 char *binary;
983
984 LOG (GNUNET_ERROR_TYPE_DEBUG, "nat_start\n");
985 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-nat");
986 tc_h->nat_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR
987 | GNUNET_OS_USE_PIPE_CONTROL,
988 NULL,
989 NULL,
990 NULL,
991 binary,
992 "gnunet-service-nat",
993 "-c",
994 tc_h->cfg_filename,
995 NULL);
996 if (NULL == tc_h->nat_proc)
997 {
998 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start NAT!");
999 return;
1000 }
1001 LOG (GNUNET_ERROR_TYPE_INFO, "started NAT\n");
1002 GNUNET_free (binary);
1003}
1004
1005
1006/**
1007 * @brief Start communicator part of transport service and communicator
1008 *
1009 * @param service_name Name of the service
1010 * @param cfg Configuration handle
1011 * @param communicator_available_cb Callback that is called when a new
1012 * @param add_address_cb Callback that is called when a new
1013 * communicator becomes available
1014 * @param cb_cls Closure to @a communicator_available_cb and @a
1015 *
1016 * @return Handle to the communicator duo
1017 */
1018struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
1019GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
1020 const char *service_name,
1021 const char *binary_name,
1022 const char *cfg_filename,
1023 const struct GNUNET_PeerIdentity *peer_id,
1024 GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback
1025 communicator_available_cb,
1026 GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb,
1027 GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb,
1028 GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb,
1029 GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb,
1030 GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb,
1031 void *cb_cls)
1032{
1033 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h;
1034
1035 LOG (GNUNET_ERROR_TYPE_DEBUG,
1036 "Starting new transport/communicator combo with config %s\n",
1037 cfg_filename);
1038 tc_h =
1039 GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle);
1040 tc_h->cfg_filename = GNUNET_strdup (cfg_filename);
1041 tc_h->cfg = GNUNET_CONFIGURATION_create ();
1042 if ((GNUNET_SYSERR == GNUNET_CONFIGURATION_load (tc_h->cfg, cfg_filename)))
1043 {
1044 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1045 _ ("Malformed configuration file `%s', exit ...\n"),
1046 cfg_filename);
1047 GNUNET_free (tc_h->cfg_filename);
1048 GNUNET_CONFIGURATION_destroy (tc_h->cfg);
1049 GNUNET_free (tc_h);
1050 return NULL;
1051 }
1052 tc_h->bc_enabled = GNUNET_CONFIGURATION_get_value_yesno (tc_h->cfg,
1053 "communicator-test",
1054 "BACKCHANNEL_ENABLED");
1055 tc_h->communicator_available_cb = communicator_available_cb;
1056 tc_h->add_address_cb = add_address_cb;
1057 tc_h->queue_create_reply_cb = queue_create_reply_cb;
1058 tc_h->add_queue_cb = add_queue_cb;
1059 tc_h->incoming_msg_cb = incoming_message_cb;
1060 tc_h->bc_cb = bc_cb;
1061 tc_h->peer_id = *peer_id;
1062 tc_h->cb_cls = cb_cls;
1063
1064 /* Start communicator part of service */
1065 transport_communicator_start (tc_h);
1066 /* Start NAT */
1067 nat_start (tc_h);
1068 /* Start resolver service */
1069 resolver_start (tc_h);
1070 /* Start peerstore service */
1071 peerstore_start (tc_h);
1072 /* Start statistic service */
1073 statistics_start (tc_h);
1074 /* Schedule start communicator */
1075 communicator_start (tc_h,
1076 binary_name);
1077 return tc_h;
1078}
1079
1080
1081void
1082GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (
1083 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
1084{
1085 shutdown_communicator (tc_h->c_proc);
1086 shutdown_service (tc_h->sh);
1087 shutdown_nat (tc_h->nat_proc);
1088 shutdown_resolver (tc_h->resolver_proc);
1089 shutdown_peerstore (tc_h->ps_proc);
1090 shutdown_statistics (tc_h->stat_proc);
1091 GNUNET_CONFIGURATION_destroy (tc_h->cfg);
1092 GNUNET_free (tc_h);
1093}
1094
1095
1096/**
1097 * @brief Instruct communicator to open a queue
1098 *
1099 * @param tc_h Handle to communicator which shall open queue
1100 * @param peer_id Towards which peer
1101 * @param address For which address
1102 */
1103void
1104GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (
1105 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
1106 const struct GNUNET_PeerIdentity *peer_id,
1107 const char *address)
1108{
1109 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
1110 static uint32_t idgen;
1111 char *prefix;
1112 struct GNUNET_TRANSPORT_CreateQueue *msg;
1113 struct GNUNET_MQ_Envelope *env;
1114 size_t alen;
1115
1116 tc_queue =
1117 GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue);
1118 tc_queue->tc_h = tc_h;
1119 prefix = GNUNET_HELLO_address_to_prefix (address);
1120 if (NULL == prefix)
1121 {
1122 GNUNET_break (0); /* We got an invalid address!? */
1123 GNUNET_free (tc_queue);
1124 return;
1125 }
1126 GNUNET_free (prefix);
1127 alen = strlen (address) + 1;
1128 env =
1129 GNUNET_MQ_msg_extra (msg, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
1130 msg->request_id = htonl (idgen++);
1131 tc_queue->qid = msg->request_id;
1132 msg->receiver = *peer_id;
1133 tc_queue->peer_id = *peer_id;
1134 memcpy (&msg[1], address, alen);
1135 if (NULL != tc_h->c_mq)
1136 {
1137 LOG (GNUNET_ERROR_TYPE_DEBUG,
1138 "Sending queue create immediately\n");
1139 GNUNET_MQ_send (tc_h->c_mq, env);
1140 }
1141 else
1142 {
1143 tc_queue->open_queue_env = env;
1144 }
1145 GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue);
1146}
1147
1148
1149/**
1150 * @brief Instruct communicator to send data
1151 *
1152 * @param tc_queue The queue to use for sending
1153 * @param cont function to call when done sending
1154 * @param cont_cls closure for @a cont
1155 * @param payload Data to send
1156 * @param payload_size Size of the @a payload
1157 */
1158void
1159GNUNET_TRANSPORT_TESTING_transport_communicator_send
1160 (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
1161 GNUNET_SCHEDULER_TaskCallback cont,
1162 void *cont_cls,
1163 const void *payload,
1164 size_t payload_size)
1165{
1166 struct GNUNET_MessageHeader *mh;
1167 struct GNUNET_TRANSPORT_SendMessageTo *msg;
1168 struct GNUNET_MQ_Envelope *env;
1169 size_t inbox_size;
1170 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
1171 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_tmp;
1172
1173 tc_queue = NULL;
1174 for (tc_queue_tmp = tc_h->queue_head;
1175 NULL != tc_queue_tmp;
1176 tc_queue_tmp = tc_queue_tmp->next)
1177 {
1178 if (tc_queue_tmp->q_len <= 0)
1179 continue;
1180 if (NULL == tc_queue)
1181 {
1182 LOG (GNUNET_ERROR_TYPE_DEBUG,
1183 "Selecting queue with prio %u, len %" PRIu64 " and MTU %u\n",
1184 tc_queue_tmp->priority,
1185 tc_queue_tmp->q_len,
1186 tc_queue_tmp->mtu);
1187 tc_queue = tc_queue_tmp;
1188 continue;
1189 }
1190 if (tc_queue->priority < tc_queue_tmp->priority)
1191 {
1192 LOG (GNUNET_ERROR_TYPE_DEBUG,
1193 "Selecting queue with prio %u, len %" PRIu64 " and MTU %u\n",
1194 tc_queue_tmp->priority,
1195 tc_queue_tmp->q_len,
1196 tc_queue_tmp->mtu);
1197 tc_queue = tc_queue_tmp;
1198 }
1199 }
1200 GNUNET_assert (NULL != tc_queue);
1201 // Uncomment this for alternativ 1 of backchannel functionality
1202 if (tc_queue->q_len != GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED)
1203 tc_queue->q_len--;
1204 // Until here for alternativ 1
1205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1206 "Sending message\n");
1207 inbox_size = sizeof (struct GNUNET_MessageHeader) + payload_size;
1208 env = GNUNET_MQ_msg_extra (msg,
1209 inbox_size,
1210 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
1211 GNUNET_assert (NULL != env);
1212 msg->qid = htonl (tc_queue->qid);
1213 msg->mid = tc_queue->mid++;
1214 msg->receiver = tc_queue->peer_id;
1215 mh = (struct GNUNET_MessageHeader *) &msg[1];
1216 mh->size = htons (inbox_size);
1217 mh->type = GNUNET_MESSAGE_TYPE_DUMMY;
1218 memcpy (&mh[1],
1219 payload,
1220 payload_size);
1221 if (NULL != cont)
1222 GNUNET_MQ_notify_sent (env,
1223 cont,
1224 cont_cls);
1225 GNUNET_MQ_send (tc_queue->tc_h->c_mq,
1226 env);
1227}
diff --git a/src/transport/transport-testing-communicator.h b/src/transport/transport-testing-communicator.h
deleted file mode 100644
index 1875258b4..000000000
--- a/src/transport/transport-testing-communicator.h
+++ /dev/null
@@ -1,360 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport-testing-communicator.h
23 * @brief functions and structures related to testing-tng
24 * @author Christian Grothoff
25 * @author Julius Bünger
26 */
27#include "platform.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_ats_transport_service.h"
30#include "transport.h"
31
32/**
33 * @brief Queue of a communicator and some context
34 */
35struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue;
36
37
38/**
39 * @brief Handle/Context to a single transmission
40 */
41struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission;
42
43/**
44 * @brief Function signature for callbacks that are called when new
45 * backchannel message arrived
46 *
47 * @param cls Closure
48 * @param msg Backchannel message
49 * @param pid Target peer
50 */
51typedef struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
52(*GNUNET_TRANSPORT_TESTING_BackchannelCallback)(void *cls,
53 struct GNUNET_MessageHeader *msg,
54 struct GNUNET_PeerIdentity *pid);
55
56
57/**
58 * @brief Function signature for callbacks that are called when new
59 * communicators become available
60 *
61 * @param cls Closure
62 * @param tc_h Communicator handle
63 * @param cc Characteristics of communicator
64 * @param address_prefix Prefix of the address
65 */
66typedef void
67(*GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback)(void *cls,
68 struct
69 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
70 *tc_h,
71 enum
72 GNUNET_TRANSPORT_CommunicatorCharacteristics
73 cc,
74 char *address_prefix);
75
76
77/**
78 * @brief Receive information about the address of a communicator.
79 *
80 * @param cls Closure
81 * @param tc_h Communicator handle
82 * @param address Address represented as string
83 * @param expiration Expiration
84 * @param aid Aid
85 * @param nt Network Type
86 */
87typedef void
88(*GNUNET_TRANSPORT_TESTING_AddAddressCallback)(void *cls,
89 struct
90 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
91 *tc_h,
92 const char *address,
93 struct GNUNET_TIME_Relative
94 expiration,
95 uint32_t aid,
96 enum GNUNET_NetworkType nt);
97
98
99/**
100 * @brief Get informed about the success of a queue request.
101 *
102 * @param cls Closure
103 * @param tc_h Communicator handle
104 * @param will_try #GNUNET_YES if communicator will try to create queue
105 */
106typedef void
107(*GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback)(void *cls,
108 struct
109 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
110 *tc_h,
111 int will_try);
112
113
114/**
115 * @brief Handle opening of queue
116 *
117 * @param cls Closure
118 * @param tc_h Communicator handle
119 * @param tc_queue Handle to newly opened queue
120 */
121typedef void
122(*GNUNET_TRANSPORT_TESTING_AddQueueCallback)(void *cls,
123 struct
124 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
125 *tc_h,
126 struct
127 GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue
128 *tc_queue,
129 size_t mtu);
130
131
132/**
133 * @brief Handle an incoming message
134 *
135 * @param cls Closure
136 * @param tc_h Handle to the receiving communicator
137 * @param msg Received message
138 */
139typedef void
140(*GNUNET_TRANSPORT_TESTING_IncomingMessageCallback)(void *cls,
141 struct
142 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
143 *tc_h,
144 const char*payload,
145 size_t payload_len);
146
147/**
148 * @brief Handle to a transport communicator
149 */
150struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
151{
152 /**
153 * Clients
154 */
155 struct MyClient *client_head;
156 struct MyClient *client_tail;
157
158 /**
159 * @brief Handle to the client
160 */
161 struct GNUNET_MQ_Handle *c_mq;
162
163 /**
164 * @brief Handle to the configuration
165 */
166 struct GNUNET_CONFIGURATION_Handle *cfg;
167
168 /**
169 * @brief File name of configuration file
170 */
171 char *cfg_filename;
172
173 struct GNUNET_PeerIdentity peer_id;
174
175 /**
176 * @brief Handle to the transport service
177 */
178 struct GNUNET_SERVICE_Handle *tsh;
179
180 /**
181 * @brief Task that will be run on shutdown to stop and clean transport
182 * service
183 */
184 struct GNUNET_SCHEDULER_Task *ts_shutdown_task;
185
186
187 /**
188 * @brief Process of the communicator
189 */
190 struct GNUNET_OS_Process *c_proc;
191
192 /**
193 * NAT process
194 */
195 struct GNUNET_OS_Process *nat_proc;
196
197 /**
198 * resolver service process
199 */
200 struct GNUNET_OS_Process *resolver_proc;
201
202 /**
203 * statistics service process
204 */
205 struct GNUNET_OS_Process *stat_proc;
206
207 /**
208 * peerstore service process
209 */
210 struct GNUNET_OS_Process *ps_proc;
211
212 /**
213 * @brief Task that will be run on shutdown to stop and clean communicator
214 */
215 struct GNUNET_SCHEDULER_Task *c_shutdown_task;
216
217 /**
218 * @brief Characteristics of the communicator
219 */
220 enum GNUNET_TRANSPORT_CommunicatorCharacteristics c_characteristics;
221
222 /**
223 * @brief Specifies supported addresses
224 */
225 char *c_addr_prefix;
226
227 /**
228 * @brief Specifies supported addresses
229 */
230 char *c_address;
231
232 /**
233 * @brief Head of the DLL of queues associated with this communicator
234 */
235 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue_head;
236
237 /**
238 * @brief Tail of the DLL of queues associated with this communicator
239 */
240 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue_tail;
241
242 /* Callbacks + Closures */
243 /**
244 * @brief Callback called when a new communicator connects
245 */
246 GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback
247 communicator_available_cb;
248
249 /**
250 * @brief Callback called when a new communicator connects
251 */
252 GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb;
253
254 /**
255 * @brief Callback called when a new communicator connects
256 */
257 GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb;
258
259 /**
260 * @brief Callback called when a new communicator connects
261 */
262 GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb;
263
264 /**
265 * @brief Callback called when a new communicator connects
266 */
267 GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_msg_cb;
268
269 /**
270 * @brief Backchannel callback
271 */
272 GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb;
273
274 /**
275 * Our service handle
276 */
277 struct GNUNET_SERVICE_Handle *sh;
278
279 /**
280 * @brief Closure to the callback
281 */
282 void *cb_cls;
283
284 /**
285 * Backchannel supported
286 */
287 int bc_enabled;
288};
289
290/**
291 * @brief Start communicator part of transport service and communicator
292 *
293 * @param service_name Name of the service
294 * @param cfg Configuration handle
295 * @param communicator_available Callback that is called when a new
296 * communicator becomes available
297 * @param add_address_cb Callback handling new addresses
298 * @param queue_create_reply_cb Callback handling success of queue requests
299 * @param add_queue_cb Callback handling freshly created queues
300 * @param incoming_message_cb Callback handling incoming messages
301 * @param cb_cls Closure to @p communicator_available
302 *
303 * @return Handle to the communicator duo
304 */
305struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
306GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
307 const char *service_name,
308 const char *binary_name,
309 const char *cfg_filename,
310 const struct GNUNET_PeerIdentity *peer_id,
311 GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback
312 communicator_available_cb,
313 GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb,
314 GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb,
315 GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb,
316 GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb,
317 GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb,
318 void *cb_cls);
319
320
321void
322GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (
323 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h);
324
325
326/**
327 * @brief Instruct communicator to open a queue
328 *
329 * @param tc_h Handle to communicator which shall open queue
330 * @param peer_id Towards which peer
331 * @param address For which address
332 */
333void
334GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (struct
335 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
336 *tc_h,
337 const struct
338 GNUNET_PeerIdentity
339 *peer_id,
340 const char *address);
341
342
343/**
344 * @brief Instruct communicator to send data
345 *
346 * @param tc_queue The queue to use for sending
347 * @param cont function to call when done sending
348 * @param cont_cls closure for @a cont
349 * @param payload Data to send
350 * @param payload_size Size of the @a payload
351 */
352void
353GNUNET_TRANSPORT_TESTING_transport_communicator_send (struct
354 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
355 *tc_h,
356 GNUNET_SCHEDULER_TaskCallback
357 cont,
358 void *cont_cls,
359 const void *payload,
360 size_t payload_size);
diff --git a/src/transport/transport-testing-filenames.c b/src/transport/transport-testing-filenames.c
deleted file mode 100644
index 7c136b690..000000000
--- a/src/transport/transport-testing-filenames.c
+++ /dev/null
@@ -1,202 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-filenames.c
22 * @brief convenience string manipulation functions for tests
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "transport-testing.h"
27
28
29/**
30 * Removes all directory separators from absolute filename
31 *
32 * @param file the absolute file name, e.g. as found in argv[0]
33 * @return extracted file name, has to be freed by caller
34 */
35static char *
36extract_filename (const char *file)
37{
38 char *pch = GNUNET_strdup (file);
39 char *backup = pch;
40 char *filename = NULL;
41 char *res;
42
43 if (NULL != strstr (pch, "/"))
44 {
45 pch = strtok (pch, "/");
46 while (pch != NULL)
47 {
48 pch = strtok (NULL, "/");
49 if (pch != NULL)
50 {
51 filename = pch;
52 }
53 }
54 }
55 else
56 filename = pch;
57
58 res = GNUNET_strdup (filename);
59 GNUNET_free (backup);
60 return res;
61}
62
63
64/**
65 * Extracts the test filename from an absolute file name and removes
66 * the extension
67 *
68 * @param file absolute file name
69 * @return the result
70 */
71char *
72GNUNET_TRANSPORT_TESTING_get_test_name (const char *file)
73{
74 char *backup = extract_filename (file);
75 char *filename = backup;
76 char *dotexe;
77 char *ret;
78
79 if (NULL == filename)
80 return NULL;
81
82 /* remove "lt-" */
83 filename = strstr (filename, "test");
84 if (NULL == filename)
85 {
86 GNUNET_free (backup);
87 return NULL;
88 }
89
90 /* remove ".exe" */
91 if (NULL != (dotexe = strstr (filename, ".exe")))
92 dotexe[0] = '\0';
93 ret = GNUNET_strdup (filename);
94 GNUNET_free (backup);
95 return ret;
96}
97
98
99/**
100 * Extracts the filename from an absolute file name and removes the extension
101 *
102 * @param file absolute file name
103 * @return the result
104 */
105char *
106GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file)
107{
108 char *src = extract_filename (file);
109 char *split;
110
111 split = strstr (src, ".");
112 if (NULL != split)
113 split[0] = '\0';
114 return src;
115}
116
117
118/**
119 * Extracts the plugin name from an absolute file name and the test name
120 *
121 * @param file absolute file name
122 * @param test test name
123 * @return the result
124 */
125char *
126GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
127 const char *test)
128{
129 char *filename;
130 char *dotexe;
131 char *e = extract_filename (file);
132 char *t = extract_filename (test);
133 char *ret;
134
135 if (NULL == e)
136 goto fail;
137 /* remove "lt-" */
138 filename = strstr (e, "tes");
139 if (NULL == filename)
140 goto fail;
141 /* remove ".exe" */
142 if (NULL != (dotexe = strstr (filename, ".exe")))
143 dotexe[0] = '\0';
144
145 /* find last _ */
146 filename = strstr (filename, t);
147 if (NULL == filename)
148 goto fail;
149 /* copy plugin */
150 filename += strlen (t);
151 if ('\0' != *filename)
152 filename++;
153 ret = GNUNET_strdup (filename);
154 goto suc;
155fail:
156 ret = NULL;
157suc:
158 GNUNET_free (t);
159 GNUNET_free (e);
160 return ret;
161}
162
163
164/**
165 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
166 * if existing ".exe"-prefix and adds the peer-number
167 *
168 * @param file filename of the test, e.g. argv[0]
169 * @param count peer number
170 * @return the result
171 */
172char *
173GNUNET_TRANSPORT_TESTING_get_config_name (const char *file,
174 int count)
175{
176 char *filename = extract_filename (file);
177 char *backup = filename;
178 char *dotexe;
179 char *ret;
180
181 if (NULL == filename)
182 return NULL;
183 /* remove "lt-" */
184 filename = strstr (filename, "test");
185 if (NULL == filename)
186 goto fail;
187 /* remove ".exe" */
188 if (NULL != (dotexe = strstr (filename, ".exe")))
189 dotexe[0] = '\0';
190 GNUNET_asprintf (&ret,
191 "%s_peer%u.conf",
192 filename,
193 count);
194 GNUNET_free (backup);
195 return ret;
196fail:
197 GNUNET_free (backup);
198 return NULL;
199}
200
201
202/* end of transport-testing-filenames.c */
diff --git a/src/transport/transport-testing-filenames2.c b/src/transport/transport-testing-filenames2.c
deleted file mode 100644
index 7d6fd529d..000000000
--- a/src/transport/transport-testing-filenames2.c
+++ /dev/null
@@ -1,202 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-filenames.c
22 * @brief convenience string manipulation functions for tests
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "transport-testing2.h"
27
28
29/**
30 * Removes all directory separators from absolute filename
31 *
32 * @param file the absolute file name, e.g. as found in argv[0]
33 * @return extracted file name, has to be freed by caller
34 */
35static char *
36extract_filename (const char *file)
37{
38 char *pch = GNUNET_strdup (file);
39 char *backup = pch;
40 char *filename = NULL;
41 char *res;
42
43 if (NULL != strstr (pch, "/"))
44 {
45 pch = strtok (pch, "/");
46 while (pch != NULL)
47 {
48 pch = strtok (NULL, "/");
49 if (pch != NULL)
50 {
51 filename = pch;
52 }
53 }
54 }
55 else
56 filename = pch;
57
58 res = GNUNET_strdup (filename);
59 GNUNET_free (backup);
60 return res;
61}
62
63
64/**
65 * Extracts the test filename from an absolute file name and removes
66 * the extension
67 *
68 * @param file absolute file name
69 * @return the result
70 */
71char *
72GNUNET_TRANSPORT_TESTING_get_test_name (const char *file)
73{
74 char *backup = extract_filename (file);
75 char *filename = backup;
76 char *dotexe;
77 char *ret;
78
79 if (NULL == filename)
80 return NULL;
81
82 /* remove "lt-" */
83 filename = strstr (filename, "test");
84 if (NULL == filename)
85 {
86 GNUNET_free (backup);
87 return NULL;
88 }
89
90 /* remove ".exe" */
91 if (NULL != (dotexe = strstr (filename, ".exe")))
92 dotexe[0] = '\0';
93 ret = GNUNET_strdup (filename);
94 GNUNET_free (backup);
95 return ret;
96}
97
98
99/**
100 * Extracts the filename from an absolute file name and removes the extension
101 *
102 * @param file absolute file name
103 * @return the result
104 */
105char *
106GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file)
107{
108 char *src = extract_filename (file);
109 char *split;
110
111 split = strstr (src, ".");
112 if (NULL != split)
113 split[0] = '\0';
114 return src;
115}
116
117
118/**
119 * Extracts the plugin name from an absolute file name and the test name
120 *
121 * @param file absolute file name
122 * @param test test name
123 * @return the result
124 */
125char *
126GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
127 const char *test)
128{
129 char *filename;
130 char *dotexe;
131 char *e = extract_filename (file);
132 char *t = extract_filename (test);
133 char *ret;
134
135 if (NULL == e)
136 goto fail;
137 /* remove "lt-" */
138 filename = strstr (e, "tes");
139 if (NULL == filename)
140 goto fail;
141 /* remove ".exe" */
142 if (NULL != (dotexe = strstr (filename, ".exe")))
143 dotexe[0] = '\0';
144
145 /* find last _ */
146 filename = strstr (filename, t);
147 if (NULL == filename)
148 goto fail;
149 /* copy plugin */
150 filename += strlen (t);
151 if ('\0' != *filename)
152 filename++;
153 ret = GNUNET_strdup (filename);
154 goto suc;
155fail:
156 ret = NULL;
157suc:
158 GNUNET_free (t);
159 GNUNET_free (e);
160 return ret;
161}
162
163
164/**
165 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
166 * if existing ".exe"-prefix and adds the peer-number
167 *
168 * @param file filename of the test, e.g. argv[0]
169 * @param count peer number
170 * @return the result
171 */
172char *
173GNUNET_TRANSPORT_TESTING_get_config_name (const char *file,
174 int count)
175{
176 char *filename = extract_filename (file);
177 char *backup = filename;
178 char *dotexe;
179 char *ret;
180
181 if (NULL == filename)
182 return NULL;
183 /* remove "lt-" */
184 filename = strstr (filename, "test");
185 if (NULL == filename)
186 goto fail;
187 /* remove ".exe" */
188 if (NULL != (dotexe = strstr (filename, ".exe")))
189 dotexe[0] = '\0';
190 GNUNET_asprintf (&ret,
191 "%s_peer%u.conf",
192 filename,
193 count);
194 GNUNET_free (backup);
195 return ret;
196fail:
197 GNUNET_free (backup);
198 return NULL;
199}
200
201
202/* end of transport-testing-filenames.c */
diff --git a/src/transport/transport-testing-loggers.c b/src/transport/transport-testing-loggers.c
deleted file mode 100644
index 330a392c6..000000000
--- a/src/transport/transport-testing-loggers.c
+++ /dev/null
@@ -1,80 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-loggers.c
22 * @brief convenience functions for logging common events in tests
23 * @author Christian Grothoff
24 */
25#include "transport-testing.h"
26
27
28/**
29 * Log a connect event.
30 *
31 * @param cls NULL
32 * @param me peer that had the event
33 * @param other peer that connected.
34 */
35void
36GNUNET_TRANSPORT_TESTING_log_connect (void *cls,
37 struct
38 GNUNET_TRANSPORT_TESTING_PeerContext *me,
39 const struct GNUNET_PeerIdentity *other)
40{
41 char *ps;
42
43 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
44 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
45 "Peer %s connected to %u (%s)!\n",
46 GNUNET_i2s (other),
47 me->no,
48 ps);
49 GNUNET_free (ps);
50}
51
52
53/**
54 * Log a disconnect event.
55 *
56 * @param cls NULL
57 * @param me peer that had the event
58 * @param other peer that disconnected.
59 */
60void
61GNUNET_TRANSPORT_TESTING_log_disconnect (void *cls,
62 struct
63 GNUNET_TRANSPORT_TESTING_PeerContext *
64 me,
65 const struct
66 GNUNET_PeerIdentity *other)
67{
68 char *ps;
69
70 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
71 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
72 "Peer `%s' disconnected from %u (%s)!\n",
73 GNUNET_i2s (other),
74 me->no,
75 ps);
76 GNUNET_free (ps);
77}
78
79
80/* end of transport-testing-loggers.c */
diff --git a/src/transport/transport-testing-loggers2.c b/src/transport/transport-testing-loggers2.c
deleted file mode 100644
index ead4fa365..000000000
--- a/src/transport/transport-testing-loggers2.c
+++ /dev/null
@@ -1,80 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-loggers.c
22 * @brief convenience functions for logging common events in tests
23 * @author Christian Grothoff
24 */
25#include "transport-testing2.h"
26
27
28/**
29 * Log a connect event.
30 *
31 * @param cls NULL
32 * @param me peer that had the event
33 * @param other peer that connected.
34 */
35void
36GNUNET_TRANSPORT_TESTING_log_connect (void *cls,
37 struct
38 GNUNET_TRANSPORT_TESTING_PeerContext *me,
39 const struct GNUNET_PeerIdentity *other)
40{
41 char *ps;
42
43 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
44 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
45 "Peer %s connected to %u (%s)!\n",
46 GNUNET_i2s (other),
47 me->no,
48 ps);
49 GNUNET_free (ps);
50}
51
52
53/**
54 * Log a disconnect event.
55 *
56 * @param cls NULL
57 * @param me peer that had the event
58 * @param other peer that disconnected.
59 */
60void
61GNUNET_TRANSPORT_TESTING_log_disconnect (void *cls,
62 struct
63 GNUNET_TRANSPORT_TESTING_PeerContext *
64 me,
65 const struct
66 GNUNET_PeerIdentity *other)
67{
68 char *ps;
69
70 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
71 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
72 "Peer `%s' disconnected from %u (%s)!\n",
73 GNUNET_i2s (other),
74 me->no,
75 ps);
76 GNUNET_free (ps);
77}
78
79
80/* end of transport-testing-loggers.c */
diff --git a/src/transport/transport-testing-main.c b/src/transport/transport-testing-main.c
deleted file mode 100644
index 20c58eeee..000000000
--- a/src/transport/transport-testing-main.c
+++ /dev/null
@@ -1,613 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-main.c
22 * @brief convenience main function for tests
23 * @author Christian Grothoff
24 */
25#include "transport-testing.h"
26
27
28/**
29 * Closure for #connect_cb.
30 */
31struct GNUNET_TRANSPORT_TESTING_ConnectRequestList
32{
33 /**
34 * Stored in a DLL.
35 */
36 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *next;
37
38 /**
39 * Stored in a DLL.
40 */
41 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *prev;
42
43 /**
44 * Overall context we are in.
45 */
46 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
47
48 /**
49 * Connect request this is about.
50 */
51 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
52
53 /**
54 * Peer being connected.
55 */
56 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
57
58 /**
59 * Peer being connected.
60 */
61 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
62};
63
64
65/**
66 * Shutdown function for the test. Stops all peers.
67 *
68 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
69 */
70static void
71do_shutdown (void *cls)
72{
73 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
74 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
75
76 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
77 "Testcase shutting down\n");
78 if (NULL != ccc->shutdown_task)
79 ccc->shutdown_task (ccc->shutdown_task_cls);
80 if (NULL != ccc->timeout_task)
81 {
82 GNUNET_SCHEDULER_cancel (ccc->timeout_task);
83 ccc->timeout_task = NULL;
84 }
85 if (NULL != ccc->connect_task)
86 {
87 GNUNET_SCHEDULER_cancel (ccc->connect_task);
88 ccc->connect_task = NULL;
89 }
90 while (NULL != (crl = ccc->crl_head))
91 {
92 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
93 ccc->crl_tail,
94 crl);
95 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (crl->cr);
96 GNUNET_free (crl);
97 }
98 for (unsigned int i = 0; i < ccc->num_peers; i++)
99 {
100 if (NULL != ccc->p[i])
101 {
102 GNUNET_TRANSPORT_TESTING_stop_peer (ccc->p[i]);
103 ccc->p[i] = NULL;
104 }
105 }
106}
107
108
109/**
110 * Testcase hit timeout, shut it down with error.
111 *
112 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
113 */
114static void
115do_timeout (void *cls)
116{
117 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
118
119 ccc->timeout_task = NULL;
120 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
121 "Testcase timed out\n");
122 ccc->global_ret = GNUNET_SYSERR;
123 GNUNET_SCHEDULER_shutdown ();
124}
125
126
127/**
128 * Internal data structure. Closure for
129 * #connect_cb, #disconnect_cb, #my_nc and #start_cb.
130 * Allows us to identify which peer this is about.
131 */
132struct GNUNET_TRANSPORT_TESTING_InternalPeerContext
133{
134 /**
135 * Overall context of the callback.
136 */
137 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
138
139 /**
140 * Offset of the peer this is about.
141 */
142 unsigned int off;
143};
144
145
146/**
147 * Information tracked per connected peer.
148 */
149struct ConnectPairInfo
150{
151 /**
152 * Peer this is about.
153 */
154 const struct GNUNET_PeerIdentity *sender;
155
156 /**
157 * Information about the receiving peer.
158 */
159 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi;
160};
161
162
163/**
164 * Function called when we connected two peers. Once we have gotten
165 * to the clique, launch test-specific logic.
166 *
167 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *`
168 */
169static void
170connect_cb (void *cls)
171{
172 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl = cls;
173 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = crl->ccc;
174
175 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
176 ccc->crl_tail,
177 crl);
178 {
179 char *p1_c = GNUNET_strdup (GNUNET_i2s (&crl->p1->id));
180
181 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
182 "Peers connected: %u (%s) <-> %u (%s)\n",
183 crl->p1->no,
184 p1_c,
185 crl->p2->no,
186 GNUNET_i2s (&crl->p2->id));
187 GNUNET_free (p1_c);
188 GNUNET_free (crl);
189 }
190 if (NULL == ccc->crl_head)
191 {
192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
193 "All connections UP, launching custom test logic.\n");
194 GNUNET_SCHEDULER_add_now (ccc->connect_continuation,
195 ccc->connect_continuation_cls);
196 }
197}
198
199
200/**
201 * Find peer by peer ID.
202 *
203 * @param ccc context to search
204 * @param peer peer to look for
205 * @return NULL if @a peer was not found
206 */
207struct GNUNET_TRANSPORT_TESTING_PeerContext *
208GNUNET_TRANSPORT_TESTING_find_peer (struct
209 GNUNET_TRANSPORT_TESTING_ConnectCheckContext
210 *ccc,
211 const struct GNUNET_PeerIdentity *peer)
212{
213 for (unsigned int i = 0; i < ccc->num_peers; i++)
214 if ((NULL != ccc->p[i]) &&
215 (0 == memcmp (peer,
216 &ccc->p[i]->id,
217 sizeof(*peer))))
218 return ccc->p[i];
219 return NULL;
220}
221
222
223/**
224 * Wrapper around peers connecting. Calls client's nc function.
225 *
226 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
227 * @param peer peer we got connected to
228 * @param mq message queue for transmissions to @a peer
229 * @return closure for message handlers
230 */
231static void *
232my_nc (void *cls,
233 const struct GNUNET_PeerIdentity *peer,
234 struct GNUNET_MQ_Handle *mq)
235{
236 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
237 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
238 struct ConnectPairInfo *cpi;
239
240 if (NULL != ccc->nc)
241 ccc->nc (ccc->cls,
242 ccc->p[ipi->off],
243 peer);
244 cpi = GNUNET_new (struct ConnectPairInfo);
245 cpi->ipi = ipi;
246 cpi->sender = peer; /* valid until disconnect */
247 return cpi;
248}
249
250
251/**
252 * Wrapper around peers disconnecting. Calls client's nd function.
253 *
254 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
255 * @param peer peer we got disconnected from
256 * @param custom_cls return value from @my_nc
257 */
258static void
259my_nd (void *cls,
260 const struct GNUNET_PeerIdentity *peer,
261 void *custom_cls)
262{
263 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
264 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
265 struct ConnectPairInfo *cpi = custom_cls;
266
267 if (NULL != ccc->nd)
268 ccc->nd (ccc->cls,
269 ccc->p[ipi->off],
270 peer);
271 GNUNET_free (cpi);
272}
273
274
275/**
276 * Wrapper around receiving data. Calls client's rec function.
277 *
278 * @param cls our `struct ConnectPairInfo *`
279 * @param message message we received
280 * @return #GNUNET_OK (all messages are fine)
281 */
282static int
283check_test (void *cls,
284 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
285{
286 return GNUNET_OK;
287}
288
289
290/**
291 * Wrapper around receiving data. Calls client's rec function.
292 *
293 * @param cls our `struct ConnectPairInfo *`
294 * @param message message we received
295 */
296static void
297handle_test (void *cls,
298 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
299{
300 struct ConnectPairInfo *cpi = cls;
301 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
302 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
303
304 if (NULL != ccc->rec)
305 ccc->rec (ccc->cls,
306 ccc->p[ipi->off],
307 cpi->sender,
308 message);
309}
310
311
312/**
313 * Wrapper around receiving data. Calls client's rec function.
314 *
315 * @param cls our `struct ConnectPairInfo *`
316 * @param message message we received
317 * @return #GNUNET_OK (all messages are fine)
318 */
319static int
320check_test2 (void *cls,
321 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
322{
323 return GNUNET_OK;
324}
325
326
327/**
328 * Wrapper around receiving data. Calls client's rec function.
329 *
330 * @param cls our `struct ConnectPairInfo *`
331 * @param message message we received
332 */
333static void
334handle_test2 (void *cls,
335 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
336{
337 struct ConnectPairInfo *cpi = cls;
338 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
339 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
340
341 if (NULL != ccc->rec)
342 ccc->rec (ccc->cls,
343 ccc->p[ipi->off],
344 cpi->sender,
345 message);
346}
347
348
349/**
350 * Connect the peers as a clique.
351 *
352 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
353 */
354static void
355do_connect (void *cls)
356{
357 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
358
359 ccc->connect_task = NULL;
360 for (unsigned int i = 0; i < ccc->num_peers; i++)
361 for (unsigned int j = (ccc->bi_directional ? 0 : i + 1); j < ccc->num_peers;
362 j++)
363 {
364 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
365
366 if (i == j)
367 continue;
368 crl = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequestList);
369 GNUNET_CONTAINER_DLL_insert (ccc->crl_head,
370 ccc->crl_tail,
371 crl);
372 crl->ccc = ccc;
373 crl->p1 = ccc->p[i];
374 crl->p2 = ccc->p[j];
375 {
376 char *sender_c = GNUNET_strdup (GNUNET_i2s (&ccc->p[0]->id));
377
378 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
379 "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
380 ccc->p[0]->no,
381 sender_c,
382 ccc->p[1]->no,
383 GNUNET_i2s (&ccc->p[1]->id));
384 GNUNET_free (sender_c);
385 }
386 crl->cr = GNUNET_TRANSPORT_TESTING_connect_peers (ccc->p[i],
387 ccc->p[j],
388 &connect_cb,
389 crl);
390 }
391}
392
393
394/**
395 * Function called once we have successfully launched a peer.
396 * Once all peers have been launched, we connect all of them
397 * in a clique.
398 *
399 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
400 */
401static void
402start_cb (void *cls)
403{
404 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
405 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
406 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = ccc->p[ipi->off];
407
408 ccc->started++;
409 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
410 "Peer %u (`%s') started\n",
411 p->no,
412 GNUNET_i2s (&p->id));
413 if (ccc->started != ccc->num_peers)
414 return;
415 if (NULL != ccc->pre_connect_task)
416 {
417 /* Run the custom per-connect job, then give it a second to
418 go into effect before we continue connecting peers. */
419 ccc->pre_connect_task (ccc->pre_connect_task_cls);
420 ccc->connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
421 &do_connect,
422 ccc);
423 }
424 else
425 {
426 do_connect (ccc);
427 }
428}
429
430
431/**
432 * Function run from #GNUNET_TRANSPORT_TESTING_connect_check
433 * once the scheduler is up. Should launch the peers and
434 * then in the continuations try to connect them.
435 *
436 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
437 * @param args ignored
438 * @param cfgfile ignored
439 * @param cfg configuration
440 */
441static void
442connect_check_run (void *cls,
443 char *const *args,
444 const char *cfgfile,
445 const struct GNUNET_CONFIGURATION_Handle *cfg)
446{
447 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
448 int ok;
449
450 ccc->cfg = cfg;
451 ccc->timeout_task = GNUNET_SCHEDULER_add_delayed (ccc->timeout,
452 &do_timeout,
453 ccc);
454 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
455 ccc);
456 ok = GNUNET_OK;
457 for (unsigned int i = 0; i < ccc->num_peers; i++)
458 {
459 struct GNUNET_MQ_MessageHandler handlers[] = {
460 GNUNET_MQ_hd_var_size (test,
461 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
462 struct GNUNET_TRANSPORT_TESTING_TestMessage,
463 NULL),
464 GNUNET_MQ_hd_var_size (test2,
465 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2,
466 struct GNUNET_TRANSPORT_TESTING_TestMessage,
467 NULL),
468 GNUNET_MQ_handler_end ()
469 };
470 ccc->p[i] = GNUNET_TRANSPORT_TESTING_start_peer (ccc->tth,
471 ccc->cfg_files[i],
472 i + 1,
473 handlers,
474 &my_nc,
475 &my_nd,
476 &ccc->ip[i],
477 &start_cb,
478 &ccc->ip[i]);
479 if (NULL == ccc->p[i])
480 ok = GNUNET_SYSERR;
481 }
482 if (GNUNET_OK != ok)
483 {
484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
485 "Fail! Could not start peers!\n");
486 GNUNET_SCHEDULER_shutdown ();
487 }
488}
489
490
491/**
492 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
493 * Starts and connects the two peers, then invokes the
494 * `connect_continuation` from @a cls. Sets up a timeout to
495 * abort the test, and a shutdown handler to clean up properly
496 * on exit.
497 *
498 * @param cls closure of type `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
499 * @param tth_ initialized testing handle
500 * @param test_plugin_ name of the plugin
501 * @param test_name_ name of the test
502 * @param num_peers number of entries in the @a cfg_file array
503 * @param cfg_files array of names of configuration files for the peers
504 * @return #GNUNET_SYSERR on error
505 */
506int
507GNUNET_TRANSPORT_TESTING_connect_check (void *cls,
508 struct GNUNET_TRANSPORT_TESTING_Handle *
509 tth_,
510 const char *test_plugin_,
511 const char *test_name_,
512 unsigned int num_peers,
513 char *cfg_files[])
514{
515 static struct GNUNET_GETOPT_CommandLineOption options[] = {
516 GNUNET_GETOPT_OPTION_END
517 };
518 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
519 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[num_peers];
520 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext ip[num_peers];
521 char *argv[] = {
522 (char *) test_name_,
523 "-c",
524 (char *) ccc->config_file,
525 NULL
526 };
527
528 ccc->num_peers = num_peers;
529 ccc->cfg_files = cfg_files;
530 ccc->test_plugin = test_plugin_;
531 ccc->test_name = test_name_;
532 ccc->tth = tth_;
533 ccc->global_ret = GNUNET_OK;
534 ccc->p = p;
535 ccc->ip = ip;
536 for (unsigned int i = 0; i < num_peers; i++)
537 {
538 ip[i].off = i;
539 ip[i].ccc = ccc;
540 }
541 if (GNUNET_OK !=
542 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
543 argv,
544 test_name_,
545 "nohelp",
546 options,
547 &connect_check_run,
548 ccc))
549 return GNUNET_SYSERR;
550 return ccc->global_ret;
551}
552
553
554/**
555 * Setup testcase. Calls @a check with the data the test needs.
556 *
557 * @param argv0 binary name (argv[0])
558 * @param filename source file name (__FILE__)
559 * @param num_peers number of peers to start
560 * @param check main function to run
561 * @param check_cls closure for @a check
562 * @return #GNUNET_OK on success
563 */
564int
565GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
566 const char *filename,
567 unsigned int num_peers,
568 GNUNET_TRANSPORT_TESTING_CheckCallback check,
569 void *check_cls)
570{
571 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
572 char *test_name;
573 char *test_source;
574 char *test_plugin;
575 char *cfg_names[num_peers];
576 int ret;
577
578 ret = GNUNET_OK;
579 test_name = GNUNET_TRANSPORT_TESTING_get_test_name (argv0);
580 GNUNET_log_setup (test_name,
581 "WARNING",
582 NULL);
583 test_source = GNUNET_TRANSPORT_TESTING_get_test_source_name (filename);
584 test_plugin = GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv0,
585 test_source);
586 for (unsigned int i = 0; i < num_peers; i++)
587 cfg_names[i] = GNUNET_TRANSPORT_TESTING_get_config_name (argv0,
588 i + 1);
589 tth = GNUNET_TRANSPORT_TESTING_init ();
590 if (NULL == tth)
591 {
592 ret = GNUNET_SYSERR;
593 }
594 else
595 {
596 ret = check (check_cls,
597 tth,
598 test_plugin,
599 test_name,
600 num_peers,
601 cfg_names);
602 GNUNET_TRANSPORT_TESTING_done (tth);
603 }
604 for (unsigned int i = 0; i < num_peers; i++)
605 GNUNET_free (cfg_names[i]);
606 GNUNET_free (test_source);
607 GNUNET_free (test_plugin);
608 GNUNET_free (test_name);
609 return ret;
610}
611
612
613/* end of transport-testing-main.c */
diff --git a/src/transport/transport-testing-main2.c b/src/transport/transport-testing-main2.c
deleted file mode 100644
index 62aa3ceb7..000000000
--- a/src/transport/transport-testing-main2.c
+++ /dev/null
@@ -1,613 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-main.c
22 * @brief convenience main function for tests
23 * @author Christian Grothoff
24 */
25#include "transport-testing2.h"
26
27
28/**
29 * Closure for #connect_cb.
30 */
31struct GNUNET_TRANSPORT_TESTING_ConnectRequestList
32{
33 /**
34 * Stored in a DLL.
35 */
36 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *next;
37
38 /**
39 * Stored in a DLL.
40 */
41 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *prev;
42
43 /**
44 * Overall context we are in.
45 */
46 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
47
48 /**
49 * Connect request this is about.
50 */
51 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
52
53 /**
54 * Peer being connected.
55 */
56 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
57
58 /**
59 * Peer being connected.
60 */
61 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
62};
63
64
65/**
66 * Shutdown function for the test. Stops all peers.
67 *
68 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
69 */
70static void
71do_shutdown (void *cls)
72{
73 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
74 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
75
76 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
77 "Testcase shutting down\n");
78 if (NULL != ccc->shutdown_task)
79 ccc->shutdown_task (ccc->shutdown_task_cls);
80 if (NULL != ccc->timeout_task)
81 {
82 GNUNET_SCHEDULER_cancel (ccc->timeout_task);
83 ccc->timeout_task = NULL;
84 }
85 if (NULL != ccc->connect_task)
86 {
87 GNUNET_SCHEDULER_cancel (ccc->connect_task);
88 ccc->connect_task = NULL;
89 }
90 while (NULL != (crl = ccc->crl_head))
91 {
92 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
93 ccc->crl_tail,
94 crl);
95 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (crl->cr);
96 GNUNET_free (crl);
97 }
98 for (unsigned int i = 0; i < ccc->num_peers; i++)
99 {
100 if (NULL != ccc->p[i])
101 {
102 GNUNET_TRANSPORT_TESTING_stop_peer (ccc->p[i]);
103 ccc->p[i] = NULL;
104 }
105 }
106}
107
108
109/**
110 * Testcase hit timeout, shut it down with error.
111 *
112 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
113 */
114static void
115do_timeout (void *cls)
116{
117 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
118
119 ccc->timeout_task = NULL;
120 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
121 "Testcase timed out\n");
122 ccc->global_ret = GNUNET_SYSERR;
123 GNUNET_SCHEDULER_shutdown ();
124}
125
126
127/**
128 * Internal data structure. Closure for
129 * #connect_cb, #disconnect_cb, #my_nc and #start_cb.
130 * Allows us to identify which peer this is about.
131 */
132struct GNUNET_TRANSPORT_TESTING_InternalPeerContext
133{
134 /**
135 * Overall context of the callback.
136 */
137 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
138
139 /**
140 * Offset of the peer this is about.
141 */
142 unsigned int off;
143};
144
145
146/**
147 * Information tracked per connected peer.
148 */
149struct ConnectPairInfo
150{
151 /**
152 * Peer this is about.
153 */
154 const struct GNUNET_PeerIdentity *sender;
155
156 /**
157 * Information about the receiving peer.
158 */
159 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi;
160};
161
162
163/**
164 * Function called when we connected two peers. Once we have gotten
165 * to the clique, launch test-specific logic.
166 *
167 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *`
168 */
169static void
170connect_cb (void *cls)
171{
172 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl = cls;
173 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = crl->ccc;
174
175 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
176 ccc->crl_tail,
177 crl);
178 {
179 char *p1_c = GNUNET_strdup (GNUNET_i2s (&crl->p1->id));
180
181 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
182 "Peers connected: %u (%s) <-> %u (%s)\n",
183 crl->p1->no,
184 p1_c,
185 crl->p2->no,
186 GNUNET_i2s (&crl->p2->id));
187 GNUNET_free (p1_c);
188 GNUNET_free (crl);
189 }
190 if (NULL == ccc->crl_head)
191 {
192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
193 "All connections UP, launching custom test logic.\n");
194 GNUNET_SCHEDULER_add_now (ccc->connect_continuation,
195 ccc->connect_continuation_cls);
196 }
197}
198
199
200/**
201 * Find peer by peer ID.
202 *
203 * @param ccc context to search
204 * @param peer peer to look for
205 * @return NULL if @a peer was not found
206 */
207struct GNUNET_TRANSPORT_TESTING_PeerContext *
208GNUNET_TRANSPORT_TESTING_find_peer (struct
209 GNUNET_TRANSPORT_TESTING_ConnectCheckContext
210 *ccc,
211 const struct GNUNET_PeerIdentity *peer)
212{
213 for (unsigned int i = 0; i < ccc->num_peers; i++)
214 if ((NULL != ccc->p[i]) &&
215 (0 == memcmp (peer,
216 &ccc->p[i]->id,
217 sizeof(*peer))))
218 return ccc->p[i];
219 return NULL;
220}
221
222
223/**
224 * Wrapper around peers connecting. Calls client's nc function.
225 *
226 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
227 * @param peer peer we got connected to
228 * @param mq message queue for transmissions to @a peer
229 * @return closure for message handlers
230 */
231static void *
232my_nc (void *cls,
233 const struct GNUNET_PeerIdentity *peer,
234 struct GNUNET_MQ_Handle *mq)
235{
236 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
237 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
238 struct ConnectPairInfo *cpi;
239
240 if (NULL != ccc->nc)
241 ccc->nc (ccc->cls,
242 ccc->p[ipi->off],
243 peer);
244 cpi = GNUNET_new (struct ConnectPairInfo);
245 cpi->ipi = ipi;
246 cpi->sender = peer; /* valid until disconnect */
247 return cpi;
248}
249
250
251/**
252 * Wrapper around peers disconnecting. Calls client's nd function.
253 *
254 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
255 * @param peer peer we got disconnected from
256 * @param custom_cls return value from @my_nc
257 */
258static void
259my_nd (void *cls,
260 const struct GNUNET_PeerIdentity *peer,
261 void *custom_cls)
262{
263 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
264 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
265 struct ConnectPairInfo *cpi = custom_cls;
266
267 if (NULL != ccc->nd)
268 ccc->nd (ccc->cls,
269 ccc->p[ipi->off],
270 peer);
271 GNUNET_free (cpi);
272}
273
274
275/**
276 * Wrapper around receiving data. Calls client's rec function.
277 *
278 * @param cls our `struct ConnectPairInfo *`
279 * @param message message we received
280 * @return #GNUNET_OK (all messages are fine)
281 */
282static int
283check_test (void *cls,
284 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
285{
286 return GNUNET_OK;
287}
288
289
290/**
291 * Wrapper around receiving data. Calls client's rec function.
292 *
293 * @param cls our `struct ConnectPairInfo *`
294 * @param message message we received
295 */
296static void
297handle_test (void *cls,
298 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
299{
300 struct ConnectPairInfo *cpi = cls;
301 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
302 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
303
304 if (NULL != ccc->rec)
305 ccc->rec (ccc->cls,
306 ccc->p[ipi->off],
307 cpi->sender,
308 message);
309}
310
311
312/**
313 * Wrapper around receiving data. Calls client's rec function.
314 *
315 * @param cls our `struct ConnectPairInfo *`
316 * @param message message we received
317 * @return #GNUNET_OK (all messages are fine)
318 */
319static int
320check_test2 (void *cls,
321 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
322{
323 return GNUNET_OK;
324}
325
326
327/**
328 * Wrapper around receiving data. Calls client's rec function.
329 *
330 * @param cls our `struct ConnectPairInfo *`
331 * @param message message we received
332 */
333static void
334handle_test2 (void *cls,
335 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
336{
337 struct ConnectPairInfo *cpi = cls;
338 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
339 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
340
341 if (NULL != ccc->rec)
342 ccc->rec (ccc->cls,
343 ccc->p[ipi->off],
344 cpi->sender,
345 message);
346}
347
348
349/**
350 * Connect the peers as a clique.
351 *
352 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
353 */
354static void
355do_connect (void *cls)
356{
357 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
358
359 ccc->connect_task = NULL;
360 for (unsigned int i = 0; i < ccc->num_peers; i++)
361 for (unsigned int j = (ccc->bi_directional ? 0 : i + 1); j < ccc->num_peers;
362 j++)
363 {
364 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
365
366 if (i == j)
367 continue;
368 crl = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequestList);
369 GNUNET_CONTAINER_DLL_insert (ccc->crl_head,
370 ccc->crl_tail,
371 crl);
372 crl->ccc = ccc;
373 crl->p1 = ccc->p[i];
374 crl->p2 = ccc->p[j];
375 {
376 char *sender_c = GNUNET_strdup (GNUNET_i2s (&ccc->p[0]->id));
377
378 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
379 "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
380 ccc->p[0]->no,
381 sender_c,
382 ccc->p[1]->no,
383 GNUNET_i2s (&ccc->p[1]->id));
384 GNUNET_free (sender_c);
385 }
386 crl->cr = GNUNET_TRANSPORT_TESTING_connect_peers (ccc->p[i],
387 ccc->p[j],
388 &connect_cb,
389 crl);
390 }
391}
392
393
394/**
395 * Function called once we have successfully launched a peer.
396 * Once all peers have been launched, we connect all of them
397 * in a clique.
398 *
399 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
400 */
401static void
402start_cb (void *cls)
403{
404 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
405 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
406 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = ccc->p[ipi->off];
407
408 ccc->started++;
409 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
410 "Peer %u (`%s') started\n",
411 p->no,
412 GNUNET_i2s (&p->id));
413 if (ccc->started != ccc->num_peers)
414 return;
415 if (NULL != ccc->pre_connect_task)
416 {
417 /* Run the custom per-connect job, then give it a second to
418 go into effect before we continue connecting peers. */
419 ccc->pre_connect_task (ccc->pre_connect_task_cls);
420 ccc->connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
421 &do_connect,
422 ccc);
423 }
424 else
425 {
426 do_connect (ccc);
427 }
428}
429
430
431/**
432 * Function run from #GNUNET_TRANSPORT_TESTING_connect_check
433 * once the scheduler is up. Should launch the peers and
434 * then in the continuations try to connect them.
435 *
436 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
437 * @param args ignored
438 * @param cfgfile ignored
439 * @param cfg configuration
440 */
441static void
442connect_check_run (void *cls,
443 char *const *args,
444 const char *cfgfile,
445 const struct GNUNET_CONFIGURATION_Handle *cfg)
446{
447 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
448 int ok;
449
450 ccc->cfg = cfg;
451 ccc->timeout_task = GNUNET_SCHEDULER_add_delayed (ccc->timeout,
452 &do_timeout,
453 ccc);
454 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
455 ccc);
456 ok = GNUNET_OK;
457 for (unsigned int i = 0; i < ccc->num_peers; i++)
458 {
459 struct GNUNET_MQ_MessageHandler handlers[] = {
460 GNUNET_MQ_hd_var_size (test,
461 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
462 struct GNUNET_TRANSPORT_TESTING_TestMessage,
463 NULL),
464 GNUNET_MQ_hd_var_size (test2,
465 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2,
466 struct GNUNET_TRANSPORT_TESTING_TestMessage,
467 NULL),
468 GNUNET_MQ_handler_end ()
469 };
470 ccc->p[i] = GNUNET_TRANSPORT_TESTING_start_peer (ccc->tth,
471 ccc->cfg_files[i],
472 i + 1,
473 handlers,
474 &my_nc,
475 &my_nd,
476 &ccc->ip[i],
477 &start_cb,
478 &ccc->ip[i]);
479 if (NULL == ccc->p[i])
480 ok = GNUNET_SYSERR;
481 }
482 if (GNUNET_OK != ok)
483 {
484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
485 "Fail! Could not start peers!\n");
486 GNUNET_SCHEDULER_shutdown ();
487 }
488}
489
490
491/**
492 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
493 * Starts and connects the two peers, then invokes the
494 * `connect_continuation` from @a cls. Sets up a timeout to
495 * abort the test, and a shutdown handler to clean up properly
496 * on exit.
497 *
498 * @param cls closure of type `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
499 * @param tth_ initialized testing handle
500 * @param test_plugin_ name of the plugin
501 * @param test_name_ name of the test
502 * @param num_peers number of entries in the @a cfg_file array
503 * @param cfg_files array of names of configuration files for the peers
504 * @return #GNUNET_SYSERR on error
505 */
506int
507GNUNET_TRANSPORT_TESTING_connect_check (void *cls,
508 struct GNUNET_TRANSPORT_TESTING_Handle *
509 tth_,
510 const char *test_plugin_,
511 const char *test_name_,
512 unsigned int num_peers,
513 char *cfg_files[])
514{
515 static struct GNUNET_GETOPT_CommandLineOption options[] = {
516 GNUNET_GETOPT_OPTION_END
517 };
518 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
519 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[num_peers];
520 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext ip[num_peers];
521 char *argv[] = {
522 (char *) test_name_,
523 "-c",
524 (char *) ccc->config_file,
525 NULL
526 };
527
528 ccc->num_peers = num_peers;
529 ccc->cfg_files = cfg_files;
530 ccc->test_plugin = test_plugin_;
531 ccc->test_name = test_name_;
532 ccc->tth = tth_;
533 ccc->global_ret = GNUNET_OK;
534 ccc->p = p;
535 ccc->ip = ip;
536 for (unsigned int i = 0; i < num_peers; i++)
537 {
538 ip[i].off = i;
539 ip[i].ccc = ccc;
540 }
541 if (GNUNET_OK !=
542 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
543 argv,
544 test_name_,
545 "nohelp",
546 options,
547 &connect_check_run,
548 ccc))
549 return GNUNET_SYSERR;
550 return ccc->global_ret;
551}
552
553
554/**
555 * Setup testcase. Calls @a check with the data the test needs.
556 *
557 * @param argv0 binary name (argv[0])
558 * @param filename source file name (__FILE__)
559 * @param num_peers number of peers to start
560 * @param check main function to run
561 * @param check_cls closure for @a check
562 * @return #GNUNET_OK on success
563 */
564int
565GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
566 const char *filename,
567 unsigned int num_peers,
568 GNUNET_TRANSPORT_TESTING_CheckCallback check,
569 void *check_cls)
570{
571 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
572 char *test_name;
573 char *test_source;
574 char *test_plugin;
575 char *cfg_names[num_peers];
576 int ret;
577
578 ret = GNUNET_OK;
579 test_name = GNUNET_TRANSPORT_TESTING_get_test_name (argv0);
580 GNUNET_log_setup (test_name,
581 "WARNING",
582 NULL);
583 test_source = GNUNET_TRANSPORT_TESTING_get_test_source_name (filename);
584 test_plugin = GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv0,
585 test_source);
586 for (unsigned int i = 0; i < num_peers; i++)
587 cfg_names[i] = GNUNET_TRANSPORT_TESTING_get_config_name (argv0,
588 i + 1);
589 tth = GNUNET_TRANSPORT_TESTING_init ();
590 if (NULL == tth)
591 {
592 ret = GNUNET_SYSERR;
593 }
594 else
595 {
596 ret = check (check_cls,
597 tth,
598 test_plugin,
599 test_name,
600 num_peers,
601 cfg_names);
602 GNUNET_TRANSPORT_TESTING_done (tth);
603 }
604 for (unsigned int i = 0; i < num_peers; i++)
605 GNUNET_free (cfg_names[i]);
606 GNUNET_free (test_source);
607 GNUNET_free (test_plugin);
608 GNUNET_free (test_name);
609 return ret;
610}
611
612
613/* end of transport-testing-main.c */
diff --git a/src/transport/transport-testing-send.c b/src/transport/transport-testing-send.c
deleted file mode 100644
index 38018c172..000000000
--- a/src/transport/transport-testing-send.c
+++ /dev/null
@@ -1,240 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-send.c
22 * @brief convenience transmission function for tests
23 * @author Christian Grothoff
24 */
25#include "transport-testing.h"
26
27/**
28 * Acceptable transmission delay.
29 */
30#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply ( \
31 GNUNET_TIME_UNIT_SECONDS, 30)
32
33
34/**
35 * Return @a cx in @a cls.
36 */
37static void
38find_cr (void *cls,
39 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
40{
41 struct GNUNET_TRANSPORT_TESTING_ConnectRequest **cr = cls;
42
43 if (GNUNET_NO == cx->connected)
44 return;
45 *cr = cx;
46}
47
48
49/**
50 * Send a test message of type @a mtype and size @a msize from
51 * peer @a sender to peer @a receiver. The peers should be
52 * connected when this function is called.
53 *
54 * @param sender the sending peer
55 * @param receiver the receiving peer
56 * @param mtype message type to use
57 * @param msize size of the message, at least `sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage)`
58 * @param num unique message number
59 * @param cont continuation to call after transmission
60 * @param cont_cls closure for @a cont
61 * @return #GNUNET_OK if message was queued,
62 * #GNUNET_NO if peers are not connected
63 * #GNUNET_SYSERR if @a msize is illegal
64 */
65int
66GNUNET_TRANSPORT_TESTING_send (struct
67 GNUNET_TRANSPORT_TESTING_PeerContext *sender,
68 struct GNUNET_TRANSPORT_TESTING_PeerContext *
69 receiver,
70 uint16_t mtype,
71 uint16_t msize,
72 uint32_t num,
73 GNUNET_SCHEDULER_TaskCallback cont,
74 void *cont_cls)
75{
76 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
77 struct GNUNET_MQ_Envelope *env;
78 struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
79
80 if (msize < sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage))
81 {
82 GNUNET_break (0);
83 return GNUNET_SYSERR;
84 }
85 cr = NULL;
86 GNUNET_TRANSPORT_TESTING_find_connecting_context (sender,
87 receiver,
88 &find_cr,
89 &cr);
90 if (NULL == cr)
91 GNUNET_TRANSPORT_TESTING_find_connecting_context (receiver,
92 sender,
93 &find_cr,
94 &cr);
95 if (NULL == cr)
96 {
97 GNUNET_break (0);
98 return GNUNET_NO;
99 }
100 if (NULL == cr->mq)
101 {
102 GNUNET_break (0);
103 return GNUNET_NO;
104 }
105 {
106 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
107
108 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
109 "Sending message from peer %u (`%s') -> peer %u (`%s') !\n",
110 sender->no,
111 GNUNET_i2s (&sender->id),
112 receiver->no,
113 receiver_s);
114 GNUNET_free (receiver_s);
115 }
116 env = GNUNET_MQ_msg_extra (test,
117 msize - sizeof(*test),
118 mtype);
119 test->num = htonl (num);
120 memset (&test[1],
121 num,
122 msize - sizeof(*test));
123 GNUNET_MQ_notify_sent (env,
124 cont,
125 cont_cls);
126 GNUNET_MQ_send (cr->mq,
127 env);
128 return GNUNET_OK;
129}
130
131
132/**
133 * Task that sends a test message from the
134 * first peer to the second peer.
135 *
136 * @param ccc context which should contain at least two peers, the
137 * first two of which should be currently connected
138 * @param size desired message size
139 * @param cont continuation to call after transmission
140 * @param cont_cls closure for @a cont
141 */
142static void
143do_send (struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
144 uint16_t size,
145 GNUNET_SCHEDULER_TaskCallback cont,
146 void *cont_cls)
147{
148 int ret;
149
150 ccc->global_ret = GNUNET_SYSERR;
151 ret = GNUNET_TRANSPORT_TESTING_send (ccc->p[0],
152 ccc->p[1],
153 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
154 size,
155 ccc->send_num_gen++,
156 cont,
157 cont_cls);
158 GNUNET_assert (GNUNET_SYSERR != ret);
159 if (GNUNET_NO == ret)
160 {
161 GNUNET_break (0);
162 ccc->global_ret = GNUNET_SYSERR;
163 GNUNET_SCHEDULER_shutdown ();
164 }
165}
166
167
168/**
169 * Task that sends a minimalistic test message from the
170 * first peer to the second peer.
171 *
172 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
173 * which should contain at least two peers, the first two
174 * of which should be currently connected
175 */
176void
177GNUNET_TRANSPORT_TESTING_simple_send (void *cls)
178{
179 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
180 int done;
181 size_t msize;
182
183 if (0 < sc->num_messages)
184 {
185 sc->num_messages--;
186 done = (0 == sc->num_messages);
187 }
188 else
189 {
190 done = 0; /* infinite loop */
191 }
192 msize = sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage);
193 if (NULL != sc->get_size_cb)
194 msize = sc->get_size_cb (sc->num_messages);
195 /* if this was the last message, call the continuation,
196 otherwise call this function again */
197 do_send (sc->ccc,
198 msize,
199 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_simple_send,
200 done ? sc->cont_cls : sc);
201}
202
203
204/**
205 * Task that sends a large test message from the
206 * first peer to the second peer.
207 *
208 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
209 * which should contain at least two peers, the first two
210 * of which should be currently connected
211 */
212void
213GNUNET_TRANSPORT_TESTING_large_send (void *cls)
214{
215 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
216 int done;
217 size_t msize;
218
219 if (0 < sc->num_messages)
220 {
221 sc->num_messages--;
222 done = (0 == sc->num_messages);
223 }
224 else
225 {
226 done = 0; /* infinite loop */
227 }
228 msize = 2600;
229 if (NULL != sc->get_size_cb)
230 msize = sc->get_size_cb (sc->num_messages);
231 /* if this was the last message, call the continuation,
232 otherwise call this function again */
233 do_send (sc->ccc,
234 msize,
235 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_large_send,
236 done ? sc->cont_cls : sc);
237}
238
239
240/* end of transport-testing-send.c */
diff --git a/src/transport/transport-testing-send2.c b/src/transport/transport-testing-send2.c
deleted file mode 100644
index bd2afb9b0..000000000
--- a/src/transport/transport-testing-send2.c
+++ /dev/null
@@ -1,240 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-send.c
22 * @brief convenience transmission function for tests
23 * @author Christian Grothoff
24 */
25#include "transport-testing2.h"
26
27/**
28 * Acceptable transmission delay.
29 */
30#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply ( \
31 GNUNET_TIME_UNIT_SECONDS, 30)
32
33
34/**
35 * Return @a cx in @a cls.
36 */
37static void
38find_cr (void *cls,
39 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
40{
41 struct GNUNET_TRANSPORT_TESTING_ConnectRequest **cr = cls;
42
43 if (GNUNET_NO == cx->connected)
44 return;
45 *cr = cx;
46}
47
48
49/**
50 * Send a test message of type @a mtype and size @a msize from
51 * peer @a sender to peer @a receiver. The peers should be
52 * connected when this function is called.
53 *
54 * @param sender the sending peer
55 * @param receiver the receiving peer
56 * @param mtype message type to use
57 * @param msize size of the message, at least `sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage)`
58 * @param num unique message number
59 * @param cont continuation to call after transmission
60 * @param cont_cls closure for @a cont
61 * @return #GNUNET_OK if message was queued,
62 * #GNUNET_NO if peers are not connected
63 * #GNUNET_SYSERR if @a msize is illegal
64 */
65int
66GNUNET_TRANSPORT_TESTING_send (struct
67 GNUNET_TRANSPORT_TESTING_PeerContext *sender,
68 struct GNUNET_TRANSPORT_TESTING_PeerContext *
69 receiver,
70 uint16_t mtype,
71 uint16_t msize,
72 uint32_t num,
73 GNUNET_SCHEDULER_TaskCallback cont,
74 void *cont_cls)
75{
76 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
77 struct GNUNET_MQ_Envelope *env;
78 struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
79
80 if (msize < sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage))
81 {
82 GNUNET_break (0);
83 return GNUNET_SYSERR;
84 }
85 cr = NULL;
86 GNUNET_TRANSPORT_TESTING_find_connecting_context (sender,
87 receiver,
88 &find_cr,
89 &cr);
90 if (NULL == cr)
91 GNUNET_TRANSPORT_TESTING_find_connecting_context (receiver,
92 sender,
93 &find_cr,
94 &cr);
95 if (NULL == cr)
96 {
97 GNUNET_break (0);
98 return GNUNET_NO;
99 }
100 if (NULL == cr->mq)
101 {
102 GNUNET_break (0);
103 return GNUNET_NO;
104 }
105 {
106 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
107
108 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
109 "Sending message from peer %u (`%s') -> peer %u (`%s') !\n",
110 sender->no,
111 GNUNET_i2s (&sender->id),
112 receiver->no,
113 receiver_s);
114 GNUNET_free (receiver_s);
115 }
116 env = GNUNET_MQ_msg_extra (test,
117 msize - sizeof(*test),
118 mtype);
119 test->num = htonl (num);
120 memset (&test[1],
121 num,
122 msize - sizeof(*test));
123 GNUNET_MQ_notify_sent (env,
124 cont,
125 cont_cls);
126 GNUNET_MQ_send (cr->mq,
127 env);
128 return GNUNET_OK;
129}
130
131
132/**
133 * Task that sends a test message from the
134 * first peer to the second peer.
135 *
136 * @param ccc context which should contain at least two peers, the
137 * first two of which should be currently connected
138 * @param size desired message size
139 * @param cont continuation to call after transmission
140 * @param cont_cls closure for @a cont
141 */
142static void
143do_send (struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
144 uint16_t size,
145 GNUNET_SCHEDULER_TaskCallback cont,
146 void *cont_cls)
147{
148 int ret;
149
150 ccc->global_ret = GNUNET_SYSERR;
151 ret = GNUNET_TRANSPORT_TESTING_send (ccc->p[0],
152 ccc->p[1],
153 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
154 size,
155 ccc->send_num_gen++,
156 cont,
157 cont_cls);
158 GNUNET_assert (GNUNET_SYSERR != ret);
159 if (GNUNET_NO == ret)
160 {
161 GNUNET_break (0);
162 ccc->global_ret = GNUNET_SYSERR;
163 GNUNET_SCHEDULER_shutdown ();
164 }
165}
166
167
168/**
169 * Task that sends a minimalistic test message from the
170 * first peer to the second peer.
171 *
172 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
173 * which should contain at least two peers, the first two
174 * of which should be currently connected
175 */
176void
177GNUNET_TRANSPORT_TESTING_simple_send (void *cls)
178{
179 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
180 int done;
181 size_t msize;
182
183 if (0 < sc->num_messages)
184 {
185 sc->num_messages--;
186 done = (0 == sc->num_messages);
187 }
188 else
189 {
190 done = 0; /* infinite loop */
191 }
192 msize = sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage);
193 if (NULL != sc->get_size_cb)
194 msize = sc->get_size_cb (sc->num_messages);
195 /* if this was the last message, call the continuation,
196 otherwise call this function again */
197 do_send (sc->ccc,
198 msize,
199 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_simple_send,
200 done ? sc->cont_cls : sc);
201}
202
203
204/**
205 * Task that sends a large test message from the
206 * first peer to the second peer.
207 *
208 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
209 * which should contain at least two peers, the first two
210 * of which should be currently connected
211 */
212void
213GNUNET_TRANSPORT_TESTING_large_send (void *cls)
214{
215 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
216 int done;
217 size_t msize;
218
219 if (0 < sc->num_messages)
220 {
221 sc->num_messages--;
222 done = (0 == sc->num_messages);
223 }
224 else
225 {
226 done = 0; /* infinite loop */
227 }
228 msize = 2600;
229 if (NULL != sc->get_size_cb)
230 msize = sc->get_size_cb (sc->num_messages);
231 /* if this was the last message, call the continuation,
232 otherwise call this function again */
233 do_send (sc->ccc,
234 msize,
235 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_large_send,
236 done ? sc->cont_cls : sc);
237}
238
239
240/* end of transport-testing-send.c */
diff --git a/src/transport/transport-testing.c b/src/transport/transport-testing.c
deleted file mode 100644
index 00c4a08dd..000000000
--- a/src/transport/transport-testing.c
+++ /dev/null
@@ -1,931 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing.c
22 * @brief testing lib for transport service
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "transport-testing.h"
27
28
29#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing", __VA_ARGS__)
30
31
32static struct GNUNET_TRANSPORT_TESTING_PeerContext *
33find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
34 const struct GNUNET_PeerIdentity *peer)
35{
36 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
37
38 for (t = tth->p_head; NULL != t; t = t->next)
39 if (0 == memcmp (&t->id,
40 peer,
41 sizeof(struct GNUNET_PeerIdentity)))
42 return t;
43 return NULL;
44}
45
46
47/**
48 * Find any connecting context matching the given pair of peers.
49 *
50 * @param p1 first peer
51 * @param p2 second peer
52 * @param cb function to call
53 * @param cb_cls closure for @a cb
54 */
55void
56GNUNET_TRANSPORT_TESTING_find_connecting_context (struct
57 GNUNET_TRANSPORT_TESTING_PeerContext
58 *p1,
59 struct
60 GNUNET_TRANSPORT_TESTING_PeerContext
61 *p2,
62 GNUNET_TRANSPORT_TESTING_ConnectContextCallback
63 cb,
64 void *cb_cls)
65{
66 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
67 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
68 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
69
70 for (cc = tth->cc_head; NULL != cc; cc = ccn)
71 {
72 ccn = cc->next;
73 if ((cc->p1 == p1) &&
74 (cc->p2 == p2))
75 cb (cb_cls,
76 cc);
77 }
78}
79
80
81static void
82set_p1c (void *cls,
83 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
84{
85 int *found = cls;
86
87 if (NULL != found)
88 *found = GNUNET_YES;
89 cx->p1_c = GNUNET_YES;
90}
91
92
93static void
94set_mq (void *cls,
95 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
96{
97 struct GNUNET_MQ_Handle *mq = cls;
98
99 cx->mq = mq;
100}
101
102
103static void
104set_p2c (void *cls,
105 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
106{
107 int *found = cls;
108
109 if (NULL != found)
110 *found = GNUNET_YES;
111 cx->p2_c = GNUNET_YES;
112}
113
114
115static void
116clear_p1c (void *cls,
117 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
118{
119 int *found = cls;
120
121 if (NULL != found)
122 *found = GNUNET_YES;
123 cx->p1_c = GNUNET_NO;
124}
125
126
127static void
128clear_p2c (void *cls,
129 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
130{
131 int *found = cls;
132
133 if (NULL != found)
134 *found = GNUNET_YES;
135 cx->p2_c = GNUNET_NO;
136}
137
138
139static void *
140notify_connect (void *cls,
141 const struct GNUNET_PeerIdentity *peer,
142 struct GNUNET_MQ_Handle *mq)
143{
144 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
145 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
146 char *p2_s;
147 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
148 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
149 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
150 int found;
151 void *ret;
152
153 p2 = find_peer_context (p->tth,
154 peer);
155 if (NULL != p->nc)
156 ret = p->nc (p->cb_cls,
157 peer,
158 mq);
159 else
160 ret = NULL;
161
162 if (NULL != p2)
163 GNUNET_asprintf (&p2_s,
164 "%u (`%s')",
165 p2->no,
166 GNUNET_i2s (&p2->id));
167 else
168 GNUNET_asprintf (&p2_s,
169 "`%s'",
170 GNUNET_i2s (peer));
171 LOG (GNUNET_ERROR_TYPE_DEBUG,
172 "Peers %s connected to peer %u (`%s')\n",
173 p2_s,
174 p->no,
175 GNUNET_i2s (&p->id));
176 GNUNET_free (p2_s);
177 /* update flags in connecting contexts */
178 found = GNUNET_NO;
179 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
180 p2,
181 &set_p1c,
182 &found);
183 if (GNUNET_NO == found)
184 {
185 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
186 cc->p1 = p;
187 cc->p2 = p2;
188 cc->p1_c = GNUNET_YES;
189 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
190 tth->cc_tail,
191 cc);
192 }
193 found = GNUNET_NO;
194 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
195 p,
196 &set_p2c,
197 &found);
198 if (GNUNET_NO == found)
199 {
200 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
201 cc->p1 = p2;
202 cc->p2 = p;
203 cc->p1_c = GNUNET_YES;
204 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
205 tth->cc_tail,
206 cc);
207 }
208 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
209 p2,
210 &set_mq,
211 mq);
212 /* update set connected flag for all requests */
213 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
214 {
215 if (GNUNET_YES == cc->connected)
216 continue;
217 if ((GNUNET_YES == cc->p1_c) &&
218 (GNUNET_YES == cc->p2_c))
219 {
220 cc->connected = GNUNET_YES;
221 /* stop trying to connect */
222 if (NULL != cc->tct)
223 {
224 GNUNET_SCHEDULER_cancel (cc->tct);
225 cc->tct = NULL;
226 }
227 if (NULL != cc->oh)
228 {
229 GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
230 cc->oh = NULL;
231 }
232 if (NULL != cc->ats_sh)
233 {
234 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
235 cc->ats_sh = NULL;
236 }
237 }
238 }
239 /* then notify application */
240 for (cc = tth->cc_head; NULL != cc; cc = ccn)
241 {
242 ccn = cc->next;
243 if ((GNUNET_YES == cc->connected) &&
244 (NULL != cc->cb))
245 {
246 cc->cb (cc->cb_cls);
247 cc->cb = NULL; /* only notify once! */
248 }
249 }
250 return ret;
251}
252
253
254/**
255 * Offer the current HELLO of P2 to P1.
256 *
257 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
258 */
259static void
260offer_hello (void *cls);
261
262
263static void
264notify_disconnect (void *cls,
265 const struct GNUNET_PeerIdentity *peer,
266 void *handler_cls)
267{
268 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
269 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
270 char *p2_s;
271 /* Find PeerContext */
272 int no = 0;
273 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
274 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
275
276 p2 = find_peer_context (p->tth,
277 peer);
278 no = p->no;
279 if (NULL != p2)
280 GNUNET_asprintf (&p2_s,
281 "%u (`%s')",
282 p2->no,
283 GNUNET_i2s (&p2->id));
284 else
285 GNUNET_asprintf (&p2_s,
286 "`%s'",
287 GNUNET_i2s (peer));
288 LOG (GNUNET_ERROR_TYPE_DEBUG,
289 "Peers %s disconnected from peer %u (`%s')\n",
290 p2_s,
291 no,
292 GNUNET_i2s (&p->id));
293 GNUNET_free (p2_s);
294 /* notify about disconnect */
295 if (NULL != p->nd)
296 p->nd (p->cb_cls,
297 peer,
298 handler_cls);
299 if (NULL == p2)
300 return;
301 /* clear MQ, it is now invalid */
302 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
303 p2,
304 &set_mq,
305 NULL);
306 /* update set connected flags for all requests */
307 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
308 p2,
309 &clear_p1c,
310 NULL);
311 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
312 p,
313 &clear_p2c,
314 NULL);
315 /* resume connectivity requests as necessary */
316 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
317 {
318 if (GNUNET_NO == cc->connected)
319 continue;
320 if ((GNUNET_YES != cc->p1_c) ||
321 (GNUNET_YES != cc->p2_c))
322 {
323 cc->connected = GNUNET_NO;
324 /* start trying to connect */
325 if ((NULL == cc->tct) &&
326 (NULL == cc->oh))
327 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
328 cc);
329 if (NULL == cc->ats_sh)
330 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
331 &p2->id,
332 1);
333 }
334 }
335}
336
337
338static void
339get_hello (void *cb_cls,
340 const struct GNUNET_MessageHeader *message)
341{
342 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cb_cls;
343 struct GNUNET_PeerIdentity hello_id;
344
345 GNUNET_assert (GNUNET_OK ==
346 GNUNET_HELLO_get_id ((const struct
347 GNUNET_HELLO_Message *) message,
348 &hello_id));
349 GNUNET_assert (0 == memcmp (&hello_id,
350 &p->id,
351 sizeof(hello_id)));
352 GNUNET_free (p->hello);
353 p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message);
354
355 if (NULL != p->start_cb)
356 {
357 LOG (GNUNET_ERROR_TYPE_DEBUG,
358 "Peer %u (`%s') successfully started\n",
359 p->no,
360 GNUNET_i2s (&p->id));
361 p->start_cb (p->start_cb_cls);
362 p->start_cb = NULL;
363 }
364}
365
366
367/**
368 * Start a peer with the given configuration
369 * @param tth the testing handle
370 * @param cfgname configuration file
371 * @param peer_id a unique number to identify the peer
372 * @param handlers functions for receiving messages
373 * @param nc connect callback
374 * @param nd disconnect callback
375 * @param cb_cls closure for callback
376 * @param start_cb start callback
377 * @param start_cb_cls closure for callback
378 * @return the peer context
379 */
380struct GNUNET_TRANSPORT_TESTING_PeerContext *
381GNUNET_TRANSPORT_TESTING_start_peer (struct
382 GNUNET_TRANSPORT_TESTING_Handle *tth,
383 const char *cfgname,
384 int peer_id,
385 const struct
386 GNUNET_MQ_MessageHandler *handlers,
387 GNUNET_TRANSPORT_NotifyConnect nc,
388 GNUNET_TRANSPORT_NotifyDisconnect nd,
389 void *cb_cls,
390 GNUNET_SCHEDULER_TaskCallback start_cb,
391 void *start_cb_cls)
392{
393 char *emsg = NULL;
394 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
395 struct GNUNET_PeerIdentity dummy;
396 unsigned int i;
397
398 if (GNUNET_NO == GNUNET_DISK_file_test (cfgname))
399 {
400 LOG (GNUNET_ERROR_TYPE_ERROR,
401 "File not found: `%s'\n",
402 cfgname);
403 return NULL;
404 }
405
406 p = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_PeerContext);
407 p->tth = tth;
408 p->nc = nc;
409 p->nd = nd;
410 if (NULL != handlers)
411 {
412 for (i = 0; NULL != handlers[i].cb; i++)
413 ;
414 p->handlers = GNUNET_new_array (i + 1,
415 struct GNUNET_MQ_MessageHandler);
416 GNUNET_memcpy (p->handlers,
417 handlers,
418 i * sizeof(struct GNUNET_MQ_MessageHandler));
419 }
420 if (NULL != cb_cls)
421 p->cb_cls = cb_cls;
422 else
423 p->cb_cls = p;
424 p->start_cb = start_cb;
425 if (NULL != start_cb_cls)
426 p->start_cb_cls = start_cb_cls;
427 else
428 p->start_cb_cls = p;
429 GNUNET_CONTAINER_DLL_insert (tth->p_head,
430 tth->p_tail,
431 p);
432
433 /* Create configuration and call testing lib to modify it */
434 p->cfg = GNUNET_CONFIGURATION_create ();
435 GNUNET_assert (GNUNET_OK ==
436 GNUNET_CONFIGURATION_load (p->cfg, cfgname));
437 if (GNUNET_SYSERR ==
438 GNUNET_TESTING_configuration_create (tth->tl_system,
439 p->cfg))
440 {
441 LOG (GNUNET_ERROR_TYPE_ERROR,
442 "Testing library failed to create unique configuration based on `%s'\n",
443 cfgname);
444 GNUNET_CONFIGURATION_destroy (p->cfg);
445 GNUNET_free (p);
446 return NULL;
447 }
448
449 p->no = peer_id;
450 /* Configure peer with configuration */
451 p->peer = GNUNET_TESTING_peer_configure (tth->tl_system,
452 p->cfg,
453 p->no,
454 NULL,
455 &emsg);
456 if (NULL == p->peer)
457 {
458 LOG (GNUNET_ERROR_TYPE_ERROR,
459 "Testing library failed to create unique configuration based on `%s': `%s'\n",
460 cfgname,
461 emsg);
462 GNUNET_TRANSPORT_TESTING_stop_peer (p);
463 GNUNET_free (emsg);
464 return NULL;
465 }
466
467 if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
468 {
469 LOG (GNUNET_ERROR_TYPE_ERROR,
470 "Testing library failed to create unique configuration based on `%s'\n",
471 cfgname);
472 GNUNET_TRANSPORT_TESTING_stop_peer (p);
473 return NULL;
474 }
475
476 memset (&dummy,
477 '\0',
478 sizeof(dummy));
479 GNUNET_TESTING_peer_get_identity (p->peer,
480 &p->id);
481 if (0 == memcmp (&dummy,
482 &p->id,
483 sizeof(struct GNUNET_PeerIdentity)))
484 {
485 LOG (GNUNET_ERROR_TYPE_ERROR,
486 "Testing library failed to obtain peer identity for peer %u\n",
487 p->no);
488 GNUNET_TRANSPORT_TESTING_stop_peer (p);
489 return NULL;
490 }
491 LOG (GNUNET_ERROR_TYPE_DEBUG,
492 "Peer %u configured with identity `%s'\n",
493 p->no,
494 GNUNET_i2s_full (&p->id));
495 p->tmh = GNUNET_TRANSPORT_manipulation_connect (p->cfg);
496 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
497 NULL,
498 handlers,
499 p,
500 &notify_connect,
501 &notify_disconnect,
502 NULL);
503 if ((NULL == p->th) ||
504 (NULL == p->tmh))
505 {
506 LOG (GNUNET_ERROR_TYPE_ERROR,
507 "Failed to connect to transport service for peer `%s': `%s'\n",
508 cfgname,
509 emsg);
510 GNUNET_TRANSPORT_TESTING_stop_peer (p);
511 GNUNET_free (emsg);
512 return NULL;
513 }
514 p->ats = GNUNET_ATS_connectivity_init (p->cfg);
515 if (NULL == p->ats)
516 {
517 LOG (GNUNET_ERROR_TYPE_ERROR,
518 "Failed to connect to ATS service for peer `%s': `%s'\n",
519 cfgname,
520 emsg);
521 GNUNET_TRANSPORT_TESTING_stop_peer (p);
522 GNUNET_free (emsg);
523 return NULL;
524 }
525 p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
526 GNUNET_TRANSPORT_AC_ANY,
527 &get_hello,
528 p);
529 GNUNET_assert (NULL != p->ghh);
530 return p;
531}
532
533
534/**
535 * Stops and restarts the given peer, sleeping (!) for 5s in between.
536 *
537 * @param p the peer
538 * @param restart_cb callback to call when restarted
539 * @param restart_cb_cls callback closure
540 * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
541 */
542int
543GNUNET_TRANSPORT_TESTING_restart_peer (struct
544 GNUNET_TRANSPORT_TESTING_PeerContext *p,
545 GNUNET_SCHEDULER_TaskCallback restart_cb,
546 void *restart_cb_cls)
547{
548 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
549 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
550
551 /* shutdown */
552 LOG (GNUNET_ERROR_TYPE_DEBUG,
553 "Stopping peer %u (`%s')\n",
554 p->no,
555 GNUNET_i2s (&p->id));
556 if (NULL != p->ghh)
557 {
558 GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
559 p->ghh = NULL;
560 }
561 if (NULL != p->th)
562 {
563 GNUNET_TRANSPORT_core_disconnect (p->th);
564 p->th = NULL;
565 }
566 if (NULL != p->tmh)
567 {
568 GNUNET_TRANSPORT_manipulation_disconnect (p->tmh);
569 p->tmh = NULL;
570 }
571 for (cc = p->tth->cc_head; NULL != cc; cc = ccn)
572 {
573 ccn = cc->next;
574 if ((cc->p1 == p) ||
575 (cc->p2 == p))
576 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
577 }
578 if (NULL != p->ats)
579 {
580 GNUNET_ATS_connectivity_done (p->ats);
581 p->ats = NULL;
582 }
583 if (GNUNET_SYSERR ==
584 GNUNET_TESTING_peer_stop (p->peer))
585 {
586 LOG (GNUNET_ERROR_TYPE_ERROR,
587 "Failed to stop peer %u (`%s')\n",
588 p->no,
589 GNUNET_i2s (&p->id));
590 return GNUNET_SYSERR;
591 }
592
593 sleep (5); // YUCK!
594
595 LOG (GNUNET_ERROR_TYPE_DEBUG,
596 "Restarting peer %u (`%s')\n",
597 p->no,
598 GNUNET_i2s (&p->id));
599 /* restart */
600 if (GNUNET_SYSERR == GNUNET_TESTING_peer_start (p->peer))
601 {
602 LOG (GNUNET_ERROR_TYPE_ERROR,
603 "Failed to restart peer %u (`%s')\n",
604 p->no,
605 GNUNET_i2s (&p->id));
606 return GNUNET_SYSERR;
607 }
608
609 GNUNET_assert (NULL == p->start_cb);
610 p->start_cb = restart_cb;
611 p->start_cb_cls = restart_cb_cls;
612
613 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
614 NULL,
615 p->handlers,
616 p,
617 &notify_connect,
618 &notify_disconnect,
619 NULL);
620 GNUNET_assert (NULL != p->th);
621 p->ats = GNUNET_ATS_connectivity_init (p->cfg);
622 p->ghh = GNUNET_TRANSPORT_hello_get (p->cfg,
623 GNUNET_TRANSPORT_AC_ANY,
624 &get_hello,
625 p);
626 GNUNET_assert (NULL != p->ghh);
627 return GNUNET_OK;
628}
629
630
631/**
632 * Shutdown the given peer
633 *
634 * @param p the peer
635 */
636void
637GNUNET_TRANSPORT_TESTING_stop_peer (struct
638 GNUNET_TRANSPORT_TESTING_PeerContext *p)
639{
640 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
641 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
642 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
643
644 for (cc = tth->cc_head; NULL != cc; cc = ccn)
645 {
646 ccn = cc->next;
647 if ((cc->p1 == p) ||
648 (cc->p2 == p))
649 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
650 }
651 if (NULL != p->ghh)
652 {
653 GNUNET_TRANSPORT_hello_get_cancel (p->ghh);
654 p->ghh = NULL;
655 }
656 if (NULL != p->tmh)
657 {
658 GNUNET_TRANSPORT_manipulation_disconnect (p->tmh);
659 p->tmh = NULL;
660 }
661 if (NULL != p->th)
662 {
663 GNUNET_TRANSPORT_core_disconnect (p->th);
664 p->th = NULL;
665 }
666 if (NULL != p->peer)
667 {
668 if (GNUNET_OK !=
669 GNUNET_TESTING_peer_stop (p->peer))
670 {
671 LOG (GNUNET_ERROR_TYPE_DEBUG,
672 "Testing lib failed to stop peer %u (`%s')\n",
673 p->no,
674 GNUNET_i2s (&p->id));
675 }
676 GNUNET_TESTING_peer_destroy (p->peer);
677 p->peer = NULL;
678 }
679 if (NULL != p->ats)
680 {
681 GNUNET_ATS_connectivity_done (p->ats);
682 p->ats = NULL;
683 }
684 if (NULL != p->hello)
685 {
686 GNUNET_free (p->hello);
687 p->hello = NULL;
688 }
689 if (NULL != p->cfg)
690 {
691 GNUNET_CONFIGURATION_destroy (p->cfg);
692 p->cfg = NULL;
693 }
694 if (NULL != p->handlers)
695 {
696 GNUNET_free (p->handlers);
697 p->handlers = NULL;
698 }
699 GNUNET_CONTAINER_DLL_remove (tth->p_head,
700 tth->p_tail,
701 p);
702 LOG (GNUNET_ERROR_TYPE_DEBUG,
703 "Peer %u (`%s') stopped\n",
704 p->no,
705 GNUNET_i2s (&p->id));
706 GNUNET_free (p);
707}
708
709
710/**
711 * Function called after the HELLO was passed to the
712 * transport service.
713 */
714static void
715hello_offered (void *cls)
716{
717 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
718
719 cc->oh = NULL;
720 cc->tct = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
721 &offer_hello,
722 cc);
723}
724
725
726/**
727 * Offer the current HELLO of P2 to P1.
728 *
729 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
730 */
731static void
732offer_hello (void *cls)
733{
734 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
735 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1 = cc->p1;
736 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = cc->p2;
737
738 cc->tct = NULL;
739 {
740 char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));
741
742 LOG (GNUNET_ERROR_TYPE_DEBUG,
743 "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n",
744 p1->no,
745 GNUNET_i2s (&p1->id),
746 p2->no,
747 p2_s,
748 GNUNET_HELLO_size (cc->p2->hello));
749 GNUNET_free (p2_s);
750 }
751
752 if (NULL != cc->oh)
753 GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
754 cc->oh =
755 GNUNET_TRANSPORT_offer_hello (cc->p1->cfg,
756 (const struct
757 GNUNET_MessageHeader *) cc->p2->hello,
758 &hello_offered,
759 cc);
760}
761
762
763/**
764 * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
765 *
766 * Remarks: start_peer's notify_connect callback can be called before.
767 *
768 * @param tth transport testing handle
769 * @param p1 peer 1
770 * @param p2 peer 2
771 * @param cb the callback to call when both peers notified that they are connected
772 * @param cls callback cls
773 * @return a connect request handle
774 */
775struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
776GNUNET_TRANSPORT_TESTING_connect_peers (struct
777 GNUNET_TRANSPORT_TESTING_PeerContext *p1,
778 struct
779 GNUNET_TRANSPORT_TESTING_PeerContext *p2,
780 GNUNET_SCHEDULER_TaskCallback cb,
781 void *cls)
782{
783 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
784 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
785 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
786
787 ccn = NULL;
788 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
789 {
790 if ((cc->p1 == p1) &&
791 (cc->p2 == p2))
792 {
793 ccn = cc;
794 break;
795 }
796 }
797
798 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
799 cc->p1 = p1;
800 cc->p2 = p2;
801 cc->cb = cb;
802 if (NULL != cls)
803 cc->cb_cls = cls;
804 else
805 cc->cb_cls = cc;
806 if (NULL != ccn)
807 {
808 cc->p1_c = ccn->p1_c;
809 cc->p2_c = ccn->p2_c;
810 cc->connected = ccn->connected;
811 }
812 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
813 tth->cc_tail,
814 cc);
815 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
816 cc);
817 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
818 &p2->id,
819 1);
820 LOG (GNUNET_ERROR_TYPE_DEBUG,
821 "New connect request %p\n",
822 cc);
823 return cc;
824}
825
826
827/**
828 * Cancel the request to connect two peers
829 * Tou MUST cancel the request if you stop the peers before the peers connected successfully
830 *
831 * @param tth transport testing handle
832 * @param cc a connect request handle
833 */
834void
835GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
836 GNUNET_TRANSPORT_TESTING_ConnectRequest
837 *cc)
838{
839 struct GNUNET_TRANSPORT_TESTING_Handle *tth = cc->p1->tth;
840
841 LOG (GNUNET_ERROR_TYPE_DEBUG,
842 "Canceling connect request!\n");
843 if (NULL != cc->tct)
844 {
845 GNUNET_SCHEDULER_cancel (cc->tct);
846 cc->tct = NULL;
847 }
848 if (NULL != cc->oh)
849 {
850 GNUNET_TRANSPORT_offer_hello_cancel (cc->oh);
851 cc->oh = NULL;
852 }
853 if (NULL != cc->ats_sh)
854 {
855 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
856 cc->ats_sh = NULL;
857 }
858 GNUNET_CONTAINER_DLL_remove (tth->cc_head,
859 tth->cc_tail,
860 cc);
861 GNUNET_free (cc);
862}
863
864
865/**
866 * Clean up the transport testing
867 *
868 * @param tth transport testing handle
869 */
870void
871GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth)
872{
873 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
874 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ct;
875 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
876 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
877
878 if (NULL == tth)
879 return;
880 cc = tth->cc_head;
881 while (NULL != cc)
882 {
883 ct = cc->next;
884 LOG (GNUNET_ERROR_TYPE_ERROR,
885 "Developer forgot to cancel connect request!\n");
886 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
887 cc = ct;
888 }
889 p = tth->p_head;
890 while (NULL != p)
891 {
892 t = p->next;
893 LOG (GNUNET_ERROR_TYPE_ERROR,
894 "Developer forgot to stop peer!\n");
895 GNUNET_TRANSPORT_TESTING_stop_peer (p);
896 p = t;
897 }
898 GNUNET_TESTING_system_destroy (tth->tl_system,
899 GNUNET_YES);
900
901 GNUNET_free (tth);
902}
903
904
905/**
906 * Initialize the transport testing
907 *
908 * @return transport testing handle
909 */
910struct GNUNET_TRANSPORT_TESTING_Handle *
911GNUNET_TRANSPORT_TESTING_init ()
912{
913 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
914
915 tth = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_Handle);
916 tth->tl_system = GNUNET_TESTING_system_create ("transport-testing",
917 NULL,
918 NULL,
919 NULL);
920 if (NULL == tth->tl_system)
921 {
922 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
923 "Failed to initialize testing library!\n");
924 GNUNET_free (tth);
925 return NULL;
926 }
927 return tth;
928}
929
930
931/* end of transport-testing.c */
diff --git a/src/transport/transport-testing.h b/src/transport/transport-testing.h
deleted file mode 100644
index c548e59c1..000000000
--- a/src/transport/transport-testing.h
+++ /dev/null
@@ -1,914 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport-testing.h
23 * @brief testing lib for transport service
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef TRANSPORT_TESTING_H
28#define TRANSPORT_TESTING_H
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_transport_service.h"
33#include "gnunet_transport_hello_service.h"
34#include "gnunet_transport_manipulation_service.h"
35#include "gnunet_testing_lib.h"
36
37
38/* ************* Basic functions for starting/stopping/connecting *********** */
39
40/**
41 * Context for a single peer
42 */
43struct GNUNET_TRANSPORT_TESTING_PeerContext;
44
45/**
46 * Definition for a transport testing handle
47 */
48struct GNUNET_TRANSPORT_TESTING_Handle;
49
50
51/**
52 * Context for a single peer
53 */
54struct GNUNET_TRANSPORT_TESTING_PeerContext
55{
56 /**
57 * Next element in the DLL
58 */
59 struct GNUNET_TRANSPORT_TESTING_PeerContext *next;
60
61 /**
62 * Previous element in the DLL
63 */
64 struct GNUNET_TRANSPORT_TESTING_PeerContext *prev;
65
66 /**
67 * Transport testing handle this peer belongs to
68 */
69 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
70
71 /**
72 * Peer's configuration
73 */
74 struct GNUNET_CONFIGURATION_Handle *cfg;
75
76 /**
77 * Peer's transport service handle
78 */
79 struct GNUNET_TRANSPORT_CoreHandle *th;
80
81 /**
82 * Peer's transport service manipulation handle
83 */
84 struct GNUNET_TRANSPORT_ManipulationHandle *tmh;
85
86 /**
87 * Peer's ATS handle.
88 */
89 struct GNUNET_ATS_ConnectivityHandle *ats;
90
91 /**
92 * Peer's transport get hello handle to retrieve peer's HELLO message
93 */
94 struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
95
96 /**
97 * Peer's testing handle
98 */
99 struct GNUNET_TESTING_Peer *peer;
100
101 /**
102 * Peer identity
103 */
104 struct GNUNET_PeerIdentity id;
105
106 /**
107 * Handle for the peer's ARM process
108 */
109 struct GNUNET_OS_Process *arm_proc;
110
111 /**
112 * Receive callback
113 */
114 struct GNUNET_MQ_MessageHandler *handlers;
115
116 /**
117 * Notify connect callback
118 */
119 GNUNET_TRANSPORT_NotifyConnect nc;
120
121 /**
122 * Notify disconnect callback
123 */
124 GNUNET_TRANSPORT_NotifyDisconnect nd;
125
126 /**
127 * Startup completed callback
128 */
129 GNUNET_SCHEDULER_TaskCallback start_cb;
130
131 /**
132 * Peers HELLO Message
133 */
134 struct GNUNET_HELLO_Message *hello;
135
136 /**
137 * Closure for the @a nc and @a nd callbacks
138 */
139 void *cb_cls;
140
141 /**
142 * Closure for @e start_cb.
143 */
144 void *start_cb_cls;
145
146 /**
147 * An unique number to identify the peer
148 */
149 unsigned int no;
150};
151
152
153/**
154 * Handle for a request to connect two peers.
155 */
156struct GNUNET_TRANSPORT_TESTING_ConnectRequest
157{
158 /**
159 * Kept in a DLL.
160 */
161 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *next;
162
163 /**
164 * Kept in a DLL.
165 */
166 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *prev;
167
168 /**
169 * Peer we want to connect.
170 */
171 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
172
173 /**
174 * Peer we want to connect.
175 */
176 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
177
178 /**
179 * Task by which we accomplish the connection.
180 */
181 struct GNUNET_SCHEDULER_Task *tct;
182
183 /**
184 * Handle by which we ask ATS to facilitate the connection.
185 */
186 struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
187
188 /**
189 * Handle by which we inform the peer about the HELLO of
190 * the other peer.
191 */
192 struct GNUNET_TRANSPORT_OfferHelloHandle *oh;
193
194 /**
195 * Function to call upon completion.
196 */
197 GNUNET_SCHEDULER_TaskCallback cb;
198
199 /**
200 * Closure for @e cb.
201 */
202 void *cb_cls;
203
204 /**
205 * Message queue for sending from @a p1 to @a p2.
206 */
207 struct GNUNET_MQ_Handle *mq;
208
209 /**
210 * Set if peer1 says the connection is up to peer2.
211 */
212 int p1_c;
213
214 /**
215 * Set if peer2 says the connection is up to peer1.
216 */
217 int p2_c;
218
219 /**
220 * #GNUNET_YES if both @e p1_c and @e p2_c are #GNUNET_YES.
221 */
222 int connected;
223};
224
225
226/**
227 * Handle for a test run.
228 */
229struct GNUNET_TRANSPORT_TESTING_Handle
230{
231 /**
232 * Testing library system handle
233 */
234 struct GNUNET_TESTING_System *tl_system;
235
236 /**
237 * head DLL of connect contexts
238 */
239 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_head;
240
241 /**
242 * head DLL of connect contexts
243 */
244 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_tail;
245
246 /**
247 * head DLL of peers
248 */
249 struct GNUNET_TRANSPORT_TESTING_PeerContext *p_head;
250
251 /**
252 * tail DLL of peers
253 */
254 struct GNUNET_TRANSPORT_TESTING_PeerContext *p_tail;
255};
256
257
258/**
259 * Initialize the transport testing
260 *
261 * @return transport testing handle
262 */
263struct GNUNET_TRANSPORT_TESTING_Handle *
264GNUNET_TRANSPORT_TESTING_init (void);
265
266
267/**
268 * Clean up the transport testing
269 *
270 * @param tth transport testing handle
271 */
272void
273GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth);
274
275
276/**
277 * Start a peer with the given configuration
278 *
279 * @param tth the testing handle
280 * @param cfgname configuration file
281 * @param peer_id the peer_id
282 * @param handlers functions for receiving messages
283 * @param nc connect callback
284 * @param nd disconnect callback
285 * @param cb_cls closure for @a nc and @a nd callback
286 * @param start_cb start callback
287 * @param start_cb_cls closure for @a start_cb
288 * @return the peer context
289 */
290struct GNUNET_TRANSPORT_TESTING_PeerContext *
291GNUNET_TRANSPORT_TESTING_start_peer (
292 struct GNUNET_TRANSPORT_TESTING_Handle *tth,
293 const char *cfgname,
294 int peer_id,
295 const struct GNUNET_MQ_MessageHandler *handlers,
296 GNUNET_TRANSPORT_NotifyConnect nc,
297 GNUNET_TRANSPORT_NotifyDisconnect nd,
298 void *cb_cls,
299 GNUNET_SCHEDULER_TaskCallback start_cb,
300 void *start_cb_cls);
301
302
303/**
304 * Shutdown the given peer
305 *
306 * @param p the peer
307 */
308void
309GNUNET_TRANSPORT_TESTING_stop_peer (
310 struct GNUNET_TRANSPORT_TESTING_PeerContext *pc);
311
312
313/**
314 * Stops and restarts the given peer, sleeping (!) for 5s in between.
315 *
316 * @param p the peer
317 * @param restart_cb restart callback
318 * @param restart_cb_cls callback closure
319 * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
320 */
321int
322GNUNET_TRANSPORT_TESTING_restart_peer (
323 struct GNUNET_TRANSPORT_TESTING_PeerContext *p,
324 GNUNET_SCHEDULER_TaskCallback restart_cb,
325 void *restart_cb_cls);
326
327
328/**
329 * Connect the given peers and call the callback when both peers
330 * report the inbound connection. Remarks: start_peer's notify_connect
331 * callback can be called before.
332 *
333 * @param p1 peer 1
334 * @param p2 peer 2
335 * @param cb the callback to call when both peers notified that they are
336 * connected
337 * @param cls callback cls
338 * @return a connect request handle
339 */
340struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
341GNUNET_TRANSPORT_TESTING_connect_peers (
342 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
343 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
344 GNUNET_SCHEDULER_TaskCallback cb,
345 void *cls);
346
347
348/**
349 * Cancel the request to connect two peers. You MUST cancel the
350 * request if you stop the peers before the peers connected
351 * successfully.
352 *
353 * @param cc a connect request handle
354 */
355void
356GNUNET_TRANSPORT_TESTING_connect_peers_cancel (
357 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc);
358
359
360/**
361 * Function called on matching connect requests.
362 *
363 * @param cls closure
364 * @param cc request matching the query
365 */
366typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContextCallback) (
367 void *cls,
368 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc);
369
370
371/**
372 * Find any connecting context matching the given pair of peers.
373 *
374 * @param p1 first peer
375 * @param p2 second peer
376 * @param cb function to call
377 * @param cb_cls closure for @a cb
378 */
379void
380GNUNET_TRANSPORT_TESTING_find_connecting_context (
381 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
382 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
383 GNUNET_TRANSPORT_TESTING_ConnectContextCallback cb,
384 void *cb_cls);
385
386
387/* ********************** high-level process functions *************** */
388
389
390/**
391 * Function called once the peers have been launched and
392 * connected by #GNUNET_TRANSPORT_TESTING_connect_check().
393 *
394 * @param cls closure
395 * @param num_peers size of the @a p array
396 * @param p the peers that were launched
397 */
398typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContinuation) (
399 void *cls,
400 unsigned int num_peers,
401 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[]);
402
403
404/**
405 * Internal data structure.
406 */
407struct GNUNET_TRANSPORT_TESTING_ConnectRequestList;
408
409/**
410 * Internal data structure.
411 */
412struct GNUNET_TRANSPORT_TESTING_InternalPeerContext;
413
414
415GNUNET_NETWORK_STRUCT_BEGIN
416struct GNUNET_TRANSPORT_TESTING_TestMessage
417{
418 /**
419 * Type is (usually) #GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE.
420 */
421 struct GNUNET_MessageHeader header;
422
423 /**
424 * Monotonically increasing counter throughout the test.
425 */
426 uint32_t num GNUNET_PACKED;
427};
428GNUNET_NETWORK_STRUCT_END
429
430
431/**
432 * Function called by the transport for each received message.
433 *
434 * @param cls closure
435 * @param receiver receiver of the message
436 * @param sender sender of the message
437 * @param message the message
438 */
439typedef void (*GNUNET_TRANSPORT_TESTING_ReceiveCallback) (
440 void *cls,
441 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
442 const struct GNUNET_PeerIdentity *sender,
443 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message);
444
445
446/**
447 * Function called to notify transport users that another
448 * peer connected to us.
449 *
450 * @param cls closure
451 * @param me peer experiencing the event
452 * @param other peer that connected to @a me
453 */
454typedef void (*GNUNET_TRANSPORT_TESTING_NotifyConnect) (
455 void *cls,
456 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
457 const struct GNUNET_PeerIdentity *other);
458
459
460/**
461 * Function called to notify transport users that another
462 * peer disconnected from us.
463 *
464 * @param cls closure
465 * @param me peer experiencing the event
466 * @param other peer that disconnected from @a me
467 */
468typedef void (*GNUNET_TRANSPORT_TESTING_NotifyDisconnect) (
469 void *cls,
470 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
471 const struct GNUNET_PeerIdentity *other);
472
473
474/**
475 * Closure that must be passed to
476 * #GNUNET_TRANSPORT_TESTING_connect_check.
477 */
478struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext
479{
480 /**
481 * How should we continue after the connect?
482 */
483 GNUNET_SCHEDULER_TaskCallback connect_continuation;
484
485 /**
486 * Closure for @e connect_continuation.
487 */
488 void *connect_continuation_cls;
489
490 /**
491 * Which configuration file should we pass to the
492 * #GNUNET_PROGRAM_run() of the testcase?
493 */
494 const char *config_file;
495
496 /**
497 * Receiver argument to give for peers we start.
498 */
499 GNUNET_TRANSPORT_TESTING_ReceiveCallback rec;
500
501 /**
502 * Notify connect argument to give for peers we start.
503 */
504 GNUNET_TRANSPORT_TESTING_NotifyConnect nc;
505
506 /**
507 * Notify disconnect argument to give for peers we start.
508 */
509 GNUNET_TRANSPORT_TESTING_NotifyDisconnect nd;
510
511 /**
512 * Closure for @e rec, @e nc and @e nd.
513 */
514 void *cls;
515
516 /**
517 * Custom task to run on shutdown.
518 */
519 GNUNET_SCHEDULER_TaskCallback shutdown_task;
520
521 /**
522 * Closure for @e shutdown_task.
523 */
524 void *shutdown_task_cls;
525
526 /**
527 * Custom task to run after peers were started but before we try to
528 * connect them. If this function is set, we wait ONE second after
529 * running this function until we continue with connecting the
530 * peers.
531 */
532 GNUNET_SCHEDULER_TaskCallback pre_connect_task;
533
534 /**
535 * Closure for @e shutdown_task.
536 */
537 void *pre_connect_task_cls;
538
539 /**
540 * When should the testcase time out?
541 */
542 struct GNUNET_TIME_Relative timeout;
543
544 /**
545 * Should we try to create connections in both directions?
546 */
547 int bi_directional;
548
549 /* ******* fields set by #GNUNET_TRANSPORT_TESTING_connect_check **** */
550
551 /**
552 * Number of peers involved in the test.
553 */
554 unsigned int num_peers;
555
556 /**
557 * Configuration files we have, array with @e num_peers entries.
558 */
559 char **cfg_files;
560
561 /**
562 * Array with @e num_peers entries.
563 */
564 struct GNUNET_TRANSPORT_TESTING_PeerContext **p;
565
566 /**
567 * Name of the plugin.
568 */
569 const char *test_plugin;
570
571 /**
572 * Name of the testcase.
573 */
574 const char *test_name;
575
576 /**
577 * Configuration object for the testcase.
578 */
579 const struct GNUNET_CONFIGURATION_Handle *cfg;
580
581 /**
582 * Main testing handle.
583 */
584 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
585
586 /**
587 * Result from the main function, set to #GNUNET_OK on success.
588 * Clients should set to #GNUNET_SYSERR to indicate test failure.
589 */
590 int global_ret;
591
592 /**
593 * Generator for the `num` field in test messages. Incremented each
594 * time #GNUNET_TRANSPORT_TESTING_simple_send or
595 * #GNUNET_TRANSPORT_TESTING_large_send are used to transmit a
596 * message.
597 */
598 uint32_t send_num_gen;
599
600 /* ******* internal state, clients should not mess with this **** */
601
602 /**
603 * Task run on timeout.
604 */
605 struct GNUNET_SCHEDULER_Task *timeout_task;
606
607 /**
608 * Task run to connect peers.
609 */
610 struct GNUNET_SCHEDULER_Task *connect_task;
611
612 /**
613 * Number of peers that have been started.
614 */
615 unsigned int started;
616
617 /**
618 * DLL of active connect requests.
619 */
620 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_head;
621
622 /**
623 * DLL of active connect requests.
624 */
625 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_tail;
626
627 /**
628 * Array with @e num_peers entries.
629 */
630 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ip;
631};
632
633
634/**
635 * Find peer by peer ID.
636 *
637 * @param ccc context to search
638 * @param peer peer to look for
639 * @return NULL if @a peer was not found
640 */
641struct GNUNET_TRANSPORT_TESTING_PeerContext *
642GNUNET_TRANSPORT_TESTING_find_peer (
643 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
644 const struct GNUNET_PeerIdentity *peer);
645
646
647/**
648 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
649 * Starts and connects the two peers, then invokes the
650 * `connect_continuation` from @a cls. Sets up a timeout to
651 * abort the test, and a shutdown handler to clean up properly
652 * on exit.
653 *
654 * @param cls closure of type `struct
655 * GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
656 * @param tth_ initialized testing handle
657 * @param test_plugin_ name of the plugin
658 * @param test_name_ name of the test
659 * @param num_peers number of entries in the @a cfg_file array
660 * @param cfg_files array of names of configuration files for the peers
661 * @return #GNUNET_SYSERR on error
662 */
663int
664GNUNET_TRANSPORT_TESTING_connect_check (
665 void *cls,
666 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
667 const char *test_plugin_,
668 const char *test_name_,
669 unsigned int num_peers,
670 char *cfg_files[]);
671
672
673/**
674 * Main function of a testcase. Called with the initial setup data
675 * for the test as derived from the source name and the binary name.
676 *
677 * @param cls closure
678 * @param tth_ initialized testing handle
679 * @param test_plugin_ name of the plugin
680 * @param test_name_ name of the test
681 * @param num_peers number of entries in the @a cfg_file array
682 * @param cfg_files array of names of configuration files for the peers
683 * @return #GNUNET_SYSERR on error
684 */
685typedef int (*GNUNET_TRANSPORT_TESTING_CheckCallback) (
686 void *cls,
687 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
688 const char *test_plugin_,
689 const char *test_name_,
690 unsigned int num_peers,
691 char *cfg_files[]);
692
693
694/**
695 * Setup testcase. Calls @a check with the data the test needs.
696 *
697 * @param argv0 binary name (argv[0])
698 * @param filename source file name (__FILE__)
699 * @param num_peers number of peers to start
700 * @param check main function to run
701 * @param check_cls closure for @a check
702 * @return #GNUNET_OK on success
703 */
704int
705GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
706 const char *filename,
707 unsigned int num_peers,
708 GNUNET_TRANSPORT_TESTING_CheckCallback check,
709 void *check_cls);
710
711
712/**
713 * Setup testcase. Calls @a check with the data the test needs.
714 *
715 * @param num_peers number of peers to start
716 * @param check main function to run
717 * @param check_cls closure for @a check
718 * @return #GNUNET_OK on success
719 */
720#define GNUNET_TRANSPORT_TESTING_main(num_peers, check, check_cls) \
721 GNUNET_TRANSPORT_TESTING_main_ (argv[0], \
722 __FILE__, \
723 num_peers, \
724 check, \
725 check_cls)
726
727/* ***************** Convenience functions for sending ********* */
728
729/**
730 * Send a test message of type @a mtype and size @a msize from
731 * peer @a sender to peer @a receiver. The peers should be
732 * connected when this function is called.
733 *
734 * @param sender the sending peer
735 * @param receiver the receiving peer
736 * @param mtype message type to use
737 * @param msize size of the message, at least `sizeof (struct
738 * GNUNET_TRANSPORT_TESTING_TestMessage)`
739 * @param num unique message number
740 * @param cont continuation to call after transmission
741 * @param cont_cls closure for @a cont
742 * @return #GNUNET_OK if message was queued,
743 * #GNUNET_NO if peers are not connected
744 * #GNUNET_SYSERR if @a msize is illegal
745 */
746int
747GNUNET_TRANSPORT_TESTING_send (
748 struct GNUNET_TRANSPORT_TESTING_PeerContext *sender,
749 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
750 uint16_t mtype,
751 uint16_t msize,
752 uint32_t num,
753 GNUNET_SCHEDULER_TaskCallback cont,
754 void *cont_cls);
755
756
757/**
758 * Message type used by #GNUNET_TRANSPORT_TESTING_simple_send().
759 */
760#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE 12345
761
762/**
763 * Alternative message type for tests.
764 */
765#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2 12346
766
767
768/**
769 * Type of the closure argument to pass to
770 * #GNUNET_TRANSPORT_TESTING_simple_send() and
771 * #GNUNET_TRANSPORT_TESTING_large_send().
772 */
773struct GNUNET_TRANSPORT_TESTING_SendClosure
774{
775 /**
776 * Context for the transmission.
777 */
778 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
779
780 /**
781 * Function that returns the desired message size. Overrides
782 * the message size, can be NULL in which case the message
783 * size is the default.
784 */
785 size_t (*get_size_cb) (unsigned int n);
786
787 /**
788 * Number of messages to be transmitted in a loop.
789 * Use zero for "forever" (until external shutdown).
790 */
791 unsigned int num_messages;
792
793 /**
794 * Function to call after all transmissions, can be NULL.
795 */
796 GNUNET_SCHEDULER_TaskCallback cont;
797
798 /**
799 * Closure for @e cont.
800 */
801 void *cont_cls;
802};
803
804
805/**
806 * Task that sends a minimalistic test message from the
807 * first peer to the second peer.
808 *
809 * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure`
810 * which should contain at least two peers, the first two
811 * of which should be currently connected
812 */
813void
814GNUNET_TRANSPORT_TESTING_simple_send (void *cls);
815
816/**
817 * Size of a message sent with
818 * #GNUNET_TRANSPORT_TESTING_large_send(). Big enough
819 * to usually force defragmentation.
820 */
821#define GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE 2600
822
823/**
824 * Task that sends a large test message from the
825 * first peer to the second peer.
826 *
827 * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure`
828 * which should contain at least two peers, the first two
829 * of which should be currently connected
830 */
831void
832GNUNET_TRANSPORT_TESTING_large_send (void *cls);
833
834
835/* ********************** log-only convenience functions ************* */
836
837
838/**
839 * Log a connect event.
840 *
841 * @param cls NULL
842 * @param me peer that had the event
843 * @param other peer that connected.
844 */
845void
846GNUNET_TRANSPORT_TESTING_log_connect (
847 void *cls,
848 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
849 const struct GNUNET_PeerIdentity *other);
850
851
852/**
853 * Log a disconnect event.
854 *
855 * @param cls NULL
856 * @param me peer that had the event
857 * @param other peer that disconnected.
858 */
859void
860GNUNET_TRANSPORT_TESTING_log_disconnect (
861 void *cls,
862 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
863 const struct GNUNET_PeerIdentity *other);
864
865
866/* ********************** low-level filename functions *************** */
867
868
869/**
870 * Extracts the test filename from an absolute file name and removes
871 * the extension.
872 *
873 * @param file absolute file name
874 * @return resulting test name
875 */
876char *
877GNUNET_TRANSPORT_TESTING_get_test_name (const char *file);
878
879
880/**
881 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
882 * if existing ".exe"-prefix and adds the peer-number
883 *
884 * @param file filename of the test, e.g. argv[0]
885 * @param count peer number
886 * @return configuration name to use
887 */
888char *
889GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, int count);
890
891
892/**
893 * Extracts the plugin anme from an absolute file name and the test name
894 * @param file absolute file name
895 * @param test test name
896 * @return the plugin name
897 */
898char *
899GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *executable,
900 const char *testname);
901
902
903/**
904 * Extracts the filename from an absolute file name and removes the
905 * extension
906 *
907 * @param file absolute file name
908 * @return the source name
909 */
910char *
911GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file);
912
913#endif
914/* end of transport_testing.h */
diff --git a/src/transport/transport-testing2.c b/src/transport/transport-testing2.c
deleted file mode 100644
index 6d41ec098..000000000
--- a/src/transport/transport-testing2.c
+++ /dev/null
@@ -1,961 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing.c
22 * @brief testing lib for transport service
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "transport-testing2.h"
27
28
29#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing", __VA_ARGS__)
30
31
32static struct GNUNET_TRANSPORT_TESTING_PeerContext *
33find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
34 const struct GNUNET_PeerIdentity *peer)
35{
36 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
37
38 for (t = tth->p_head; NULL != t; t = t->next)
39 if (0 == memcmp (&t->id,
40 peer,
41 sizeof(struct GNUNET_PeerIdentity)))
42 return t;
43 return NULL;
44}
45
46
47/**
48 * Find any connecting context matching the given pair of peers.
49 *
50 * @param p1 first peer
51 * @param p2 second peer
52 * @param cb function to call
53 * @param cb_cls closure for @a cb
54 */
55void
56GNUNET_TRANSPORT_TESTING_find_connecting_context (struct
57 GNUNET_TRANSPORT_TESTING_PeerContext
58 *p1,
59 struct
60 GNUNET_TRANSPORT_TESTING_PeerContext
61 *p2,
62 GNUNET_TRANSPORT_TESTING_ConnectContextCallback
63 cb,
64 void *cb_cls)
65{
66 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
67 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
68 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
69
70 for (cc = tth->cc_head; NULL != cc; cc = ccn)
71 {
72 ccn = cc->next;
73 if ((cc->p1 == p1) &&
74 (cc->p2 == p2))
75 cb (cb_cls,
76 cc);
77 }
78}
79
80
81static void
82set_p1c (void *cls,
83 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
84{
85 int *found = cls;
86
87 if (NULL != found)
88 *found = GNUNET_YES;
89 cx->p1_c = GNUNET_YES;
90}
91
92
93static void
94set_mq (void *cls,
95 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
96{
97 struct GNUNET_MQ_Handle *mq = cls;
98
99 cx->mq = mq;
100}
101
102
103static void
104set_p2c (void *cls,
105 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
106{
107 int *found = cls;
108
109 if (NULL != found)
110 *found = GNUNET_YES;
111 cx->p2_c = GNUNET_YES;
112}
113
114
115static void
116clear_p1c (void *cls,
117 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
118{
119 int *found = cls;
120
121 if (NULL != found)
122 *found = GNUNET_YES;
123 cx->p1_c = GNUNET_NO;
124}
125
126
127static void
128clear_p2c (void *cls,
129 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
130{
131 int *found = cls;
132
133 if (NULL != found)
134 *found = GNUNET_YES;
135 cx->p2_c = GNUNET_NO;
136}
137
138
139static void *
140notify_connect (void *cls,
141 const struct GNUNET_PeerIdentity *peer,
142 struct GNUNET_MQ_Handle *mq)
143{
144 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
145 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
146 char *p2_s;
147 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
148 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
149 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
150 int found;
151 void *ret;
152
153 p2 = find_peer_context (p->tth,
154 peer);
155 if (NULL != p->nc)
156 ret = p->nc (p->cb_cls,
157 peer,
158 mq);
159 else
160 ret = NULL;
161
162 if (NULL != p2)
163 GNUNET_asprintf (&p2_s,
164 "%u (`%s')",
165 p2->no,
166 GNUNET_i2s (&p2->id));
167 else
168 GNUNET_asprintf (&p2_s,
169 "`%s'",
170 GNUNET_i2s (peer));
171 LOG (GNUNET_ERROR_TYPE_DEBUG,
172 "Peers %s connected to peer %u (`%s')\n",
173 p2_s,
174 p->no,
175 GNUNET_i2s (&p->id));
176 GNUNET_free (p2_s);
177 /* update flags in connecting contexts */
178 found = GNUNET_NO;
179 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
180 p2,
181 &set_p1c,
182 &found);
183 if (GNUNET_NO == found)
184 {
185 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
186 cc->p1 = p;
187 cc->p2 = p2;
188 cc->p1_c = GNUNET_YES;
189 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
190 tth->cc_tail,
191 cc);
192 }
193 found = GNUNET_NO;
194 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
195 p,
196 &set_p2c,
197 &found);
198 if (GNUNET_NO == found)
199 {
200 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
201 cc->p1 = p2;
202 cc->p2 = p;
203 cc->p1_c = GNUNET_YES;
204 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
205 tth->cc_tail,
206 cc);
207 }
208 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
209 p2,
210 &set_mq,
211 mq);
212 /* update set connected flag for all requests */
213 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
214 {
215 if (GNUNET_YES == cc->connected)
216 continue;
217 if ((GNUNET_YES == cc->p1_c) &&
218 (GNUNET_YES == cc->p2_c))
219 {
220 cc->connected = GNUNET_YES;
221 /* stop trying to connect */
222 if (NULL != cc->tct)
223 {
224 GNUNET_SCHEDULER_cancel (cc->tct);
225 cc->tct = NULL;
226 }
227 if (NULL != cc->ats_sh)
228 {
229 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
230 cc->ats_sh = NULL;
231 }
232 }
233 }
234 /* then notify application */
235 for (cc = tth->cc_head; NULL != cc; cc = ccn)
236 {
237 ccn = cc->next;
238 if ((GNUNET_YES == cc->connected) &&
239 (NULL != cc->cb))
240 {
241 cc->cb (cc->cb_cls);
242 cc->cb = NULL; /* only notify once! */
243 }
244 }
245 return ret;
246}
247
248
249/**
250 * Offer the current HELLO of P2 to P1.
251 *
252 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
253 */
254static void
255offer_hello (void *cls);
256
257
258static void
259notify_disconnect (void *cls,
260 const struct GNUNET_PeerIdentity *peer,
261 void *handler_cls)
262{
263 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
264 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
265 char *p2_s;
266 /* Find PeerContext */
267 int no = 0;
268 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
269 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
270
271 p2 = find_peer_context (p->tth,
272 peer);
273 no = p->no;
274 if (NULL != p2)
275 GNUNET_asprintf (&p2_s,
276 "%u (`%s')",
277 p2->no,
278 GNUNET_i2s (&p2->id));
279 else
280 GNUNET_asprintf (&p2_s,
281 "`%s'",
282 GNUNET_i2s (peer));
283 LOG (GNUNET_ERROR_TYPE_DEBUG,
284 "Peers %s disconnected from peer %u (`%s')\n",
285 p2_s,
286 no,
287 GNUNET_i2s (&p->id));
288 GNUNET_free (p2_s);
289 /* notify about disconnect */
290 if (NULL != p->nd)
291 p->nd (p->cb_cls,
292 peer,
293 handler_cls);
294 if (NULL == p2)
295 return;
296 /* clear MQ, it is now invalid */
297 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
298 p2,
299 &set_mq,
300 NULL);
301 /* update set connected flags for all requests */
302 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
303 p2,
304 &clear_p1c,
305 NULL);
306 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
307 p,
308 &clear_p2c,
309 NULL);
310 /* resume connectivity requests as necessary */
311 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
312 {
313 if (GNUNET_NO == cc->connected)
314 continue;
315 if ((GNUNET_YES != cc->p1_c) ||
316 (GNUNET_YES != cc->p2_c))
317 {
318 cc->connected = GNUNET_NO;
319 /* start trying to connect */
320 if (NULL == cc->tct)
321 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
322 cc);
323 if (NULL == cc->ats_sh)
324 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
325 &p2->id,
326 1);
327 }
328 }
329}
330
331static void
332retrieve_hello (void *cls);
333
334static void
335hello_iter_cb (void *cb_cls,
336 const struct GNUNET_PEERSTORE_Record *record,
337 const char *emsg)
338{
339 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cb_cls;
340 if (NULL == record)
341 {
342 p->pic = NULL;
343 if (NULL != p->start_cb)
344 p->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, p);
345 return;
346 }
347 // Check record type et al?
348 p->hello_size = record->value_size;
349 p->hello = GNUNET_malloc (p->hello_size);
350 memcpy (p->hello, record->value, p->hello_size);
351 p->hello[p->hello_size - 1] = '\0';
352
353 GNUNET_PEERSTORE_iterate_cancel (p->pic);
354 p->pic = NULL;
355 if (NULL != p->start_cb)
356 {
357 LOG (GNUNET_ERROR_TYPE_DEBUG,
358 "Peer %u (`%s') successfully started\n",
359 p->no,
360 GNUNET_i2s (&p->id));
361 p->start_cb (p->start_cb_cls);
362 p->start_cb = NULL;
363 }
364}
365
366
367static void
368retrieve_hello (void *cls)
369{
370 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
371 p->rh_task = NULL;
372 p->pic = GNUNET_PEERSTORE_iterate (p->ph,
373 "transport",
374 &p->id,
375 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
376 hello_iter_cb,
377 p);
378
379}
380
381
382/**
383 * Start a peer with the given configuration
384 * @param tth the testing handle
385 * @param cfgname configuration file
386 * @param peer_id a unique number to identify the peer
387 * @param handlers functions for receiving messages
388 * @param nc connect callback
389 * @param nd disconnect callback
390 * @param cb_cls closure for callback
391 * @param start_cb start callback
392 * @param start_cb_cls closure for callback
393 * @return the peer context
394 */
395struct GNUNET_TRANSPORT_TESTING_PeerContext *
396GNUNET_TRANSPORT_TESTING_start_peer (struct
397 GNUNET_TRANSPORT_TESTING_Handle *tth,
398 const char *cfgname,
399 int peer_id,
400 const struct
401 GNUNET_MQ_MessageHandler *handlers,
402 GNUNET_TRANSPORT_NotifyConnect nc,
403 GNUNET_TRANSPORT_NotifyDisconnect nd,
404 void *cb_cls,
405 GNUNET_SCHEDULER_TaskCallback start_cb,
406 void *start_cb_cls)
407{
408 char *emsg = NULL;
409 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
410 struct GNUNET_PeerIdentity dummy;
411 unsigned int i;
412
413 if (GNUNET_NO == GNUNET_DISK_file_test (cfgname))
414 {
415 LOG (GNUNET_ERROR_TYPE_ERROR,
416 "File not found: `%s'\n",
417 cfgname);
418 return NULL;
419 }
420
421 p = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_PeerContext);
422 p->tth = tth;
423 p->nc = nc;
424 p->nd = nd;
425 if (NULL != handlers)
426 {
427 for (i = 0; NULL != handlers[i].cb; i++)
428 ;
429 p->handlers = GNUNET_new_array (i + 1,
430 struct GNUNET_MQ_MessageHandler);
431 GNUNET_memcpy (p->handlers,
432 handlers,
433 i * sizeof(struct GNUNET_MQ_MessageHandler));
434 }
435 if (NULL != cb_cls)
436 p->cb_cls = cb_cls;
437 else
438 p->cb_cls = p;
439 p->start_cb = start_cb;
440 if (NULL != start_cb_cls)
441 p->start_cb_cls = start_cb_cls;
442 else
443 p->start_cb_cls = p;
444 GNUNET_CONTAINER_DLL_insert (tth->p_head,
445 tth->p_tail,
446 p);
447
448 /* Create configuration and call testing lib to modify it */
449 p->cfg = GNUNET_CONFIGURATION_create ();
450 GNUNET_assert (GNUNET_OK ==
451 GNUNET_CONFIGURATION_load (p->cfg, cfgname));
452 if (GNUNET_SYSERR ==
453 GNUNET_TESTING_configuration_create (tth->tl_system,
454 p->cfg))
455 {
456 LOG (GNUNET_ERROR_TYPE_ERROR,
457 "Testing library failed to create unique configuration based on `%s'\n",
458 cfgname);
459 GNUNET_CONFIGURATION_destroy (p->cfg);
460 GNUNET_free (p);
461 return NULL;
462 }
463
464 p->no = peer_id;
465 /* Configure peer with configuration */
466 p->peer = GNUNET_TESTING_peer_configure (tth->tl_system,
467 p->cfg,
468 p->no,
469 NULL,
470 &emsg);
471 if (NULL == p->peer)
472 {
473 LOG (GNUNET_ERROR_TYPE_ERROR,
474 "Testing library failed to create unique configuration based on `%s': `%s'\n",
475 cfgname,
476 emsg);
477 GNUNET_TRANSPORT_TESTING_stop_peer (p);
478 GNUNET_free (emsg);
479 return NULL;
480 }
481
482 if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
483 {
484 LOG (GNUNET_ERROR_TYPE_ERROR,
485 "Testing library failed to create unique configuration based on `%s'\n",
486 cfgname);
487 GNUNET_TRANSPORT_TESTING_stop_peer (p);
488 return NULL;
489 }
490
491 memset (&dummy,
492 '\0',
493 sizeof(dummy));
494 GNUNET_TESTING_peer_get_identity (p->peer,
495 &p->id);
496 if (0 == memcmp (&dummy,
497 &p->id,
498 sizeof(struct GNUNET_PeerIdentity)))
499 {
500 LOG (GNUNET_ERROR_TYPE_ERROR,
501 "Testing library failed to obtain peer identity for peer %u\n",
502 p->no);
503 GNUNET_TRANSPORT_TESTING_stop_peer (p);
504 return NULL;
505 }
506 LOG (GNUNET_ERROR_TYPE_DEBUG,
507 "Peer %u configured with identity `%s'\n",
508 p->no,
509 GNUNET_i2s_full (&p->id));
510 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
511 NULL,
512 handlers,
513 p,
514 &notify_connect,
515 &notify_disconnect);
516 if (NULL == p->th)
517 {
518 LOG (GNUNET_ERROR_TYPE_ERROR,
519 "Failed to connect to transport service for peer `%s': `%s'\n",
520 cfgname,
521 emsg);
522 GNUNET_TRANSPORT_TESTING_stop_peer (p);
523 GNUNET_free (emsg);
524 return NULL;
525 }
526 p->ats = GNUNET_ATS_connectivity_init (p->cfg);
527 if (NULL == p->ats)
528 {
529 LOG (GNUNET_ERROR_TYPE_ERROR,
530 "Failed to connect to ATS service for peer `%s': `%s'\n",
531 cfgname,
532 emsg);
533 GNUNET_TRANSPORT_TESTING_stop_peer (p);
534 GNUNET_free (emsg);
535 return NULL;
536 }
537 p->ph = GNUNET_PEERSTORE_connect (p->cfg);
538 // FIXME Error handling
539 p->ah = GNUNET_TRANSPORT_application_init (p->cfg);
540 GNUNET_assert (NULL != p->ah);
541 // FIXME Error handling
542 p->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, p);
543
544 return p;
545}
546
547
548/**
549 * Stops and restarts the given peer, sleeping (!) for 5s in between.
550 *
551 * @param p the peer
552 * @param restart_cb callback to call when restarted
553 * @param restart_cb_cls callback closure
554 * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
555 */
556int
557GNUNET_TRANSPORT_TESTING_restart_peer (struct
558 GNUNET_TRANSPORT_TESTING_PeerContext *p,
559 GNUNET_SCHEDULER_TaskCallback restart_cb,
560 void *restart_cb_cls)
561{
562 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
563 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
564
565 /* shutdown */
566 LOG (GNUNET_ERROR_TYPE_DEBUG,
567 "Stopping peer %u (`%s')\n",
568 p->no,
569 GNUNET_i2s (&p->id));
570 if (NULL != p->pic)
571 {
572 GNUNET_PEERSTORE_iterate_cancel (p->pic);
573 p->pic = NULL;
574 }
575 if (NULL != p->th)
576 {
577 GNUNET_TRANSPORT_core_disconnect (p->th);
578 p->th = NULL;
579 }
580 for (cc = p->tth->cc_head; NULL != cc; cc = ccn)
581 {
582 ccn = cc->next;
583 if ((cc->p1 == p) ||
584 (cc->p2 == p))
585 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
586 }
587 if (NULL != p->ats)
588 {
589 GNUNET_ATS_connectivity_done (p->ats);
590 p->ats = NULL;
591 }
592 if (GNUNET_SYSERR ==
593 GNUNET_TESTING_peer_stop (p->peer))
594 {
595 LOG (GNUNET_ERROR_TYPE_ERROR,
596 "Failed to stop peer %u (`%s')\n",
597 p->no,
598 GNUNET_i2s (&p->id));
599 return GNUNET_SYSERR;
600 }
601
602 sleep (5); // YUCK!
603
604 LOG (GNUNET_ERROR_TYPE_DEBUG,
605 "Restarting peer %u (`%s')\n",
606 p->no,
607 GNUNET_i2s (&p->id));
608 /* restart */
609 if (GNUNET_SYSERR == GNUNET_TESTING_peer_start (p->peer))
610 {
611 LOG (GNUNET_ERROR_TYPE_ERROR,
612 "Failed to restart peer %u (`%s')\n",
613 p->no,
614 GNUNET_i2s (&p->id));
615 return GNUNET_SYSERR;
616 }
617
618 GNUNET_assert (NULL == p->start_cb);
619 p->start_cb = restart_cb;
620 p->start_cb_cls = restart_cb_cls;
621
622 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
623 NULL,
624 p->handlers,
625 p,
626 &notify_connect,
627 &notify_disconnect);
628 GNUNET_assert (NULL != p->th);
629 p->ats = GNUNET_ATS_connectivity_init (p->cfg);
630 p->pic = GNUNET_PEERSTORE_iterate (p->ph,
631 "transport",
632 &p->id,
633 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
634 hello_iter_cb,
635 p);
636 GNUNET_assert (NULL != p->pic);
637 return GNUNET_OK;
638}
639
640
641/**
642 * Shutdown the given peer
643 *
644 * @param p the peer
645 */
646void
647GNUNET_TRANSPORT_TESTING_stop_peer (struct
648 GNUNET_TRANSPORT_TESTING_PeerContext *p)
649{
650 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
651 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
652 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
653 /* shutdown */
654 LOG (GNUNET_ERROR_TYPE_DEBUG,
655 "Stopping peer %u (`%s')\n",
656 p->no,
657 GNUNET_i2s (&p->id));
658
659 for (cc = tth->cc_head; NULL != cc; cc = ccn)
660 {
661 ccn = cc->next;
662 if ((cc->p1 == p) ||
663 (cc->p2 == p))
664 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
665 }
666 if (NULL != p->pic)
667 {
668 GNUNET_PEERSTORE_iterate_cancel (p->pic);
669 p->pic = NULL;
670 }
671 if (NULL != p->th)
672 {
673 GNUNET_TRANSPORT_core_disconnect (p->th);
674 p->th = NULL;
675 }
676 if (NULL != p->ats)
677 {
678 GNUNET_ATS_connectivity_done (p->ats);
679 p->ats = NULL;
680 }
681 if (NULL != p->ah)
682 {
683 GNUNET_TRANSPORT_application_done (p->ah);
684 p->ah = NULL;
685 }
686 if (NULL != p->ph)
687 {
688 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
689 "Disconnecting from PEERSTORE service\n");
690 GNUNET_PEERSTORE_disconnect (p->ph, GNUNET_NO);
691 p->ph = NULL;
692 }
693
694 if (NULL != p->peer)
695 {
696 if (GNUNET_OK !=
697 GNUNET_TESTING_peer_stop (p->peer))
698 {
699 LOG (GNUNET_ERROR_TYPE_DEBUG,
700 "Testing lib failed to stop peer %u (`%s')\n",
701 p->no,
702 GNUNET_i2s (&p->id));
703 }
704 GNUNET_TESTING_peer_destroy (p->peer);
705 p->peer = NULL;
706 }
707 if (NULL != p->hello)
708 {
709 GNUNET_free (p->hello);
710 p->hello = NULL;
711 }
712 if (NULL != p->cfg)
713 {
714 GNUNET_CONFIGURATION_destroy (p->cfg);
715 p->cfg = NULL;
716 }
717 if (NULL != p->handlers)
718 {
719 GNUNET_free (p->handlers);
720 p->handlers = NULL;
721 }
722 GNUNET_CONTAINER_DLL_remove (tth->p_head,
723 tth->p_tail,
724 p);
725 LOG (GNUNET_ERROR_TYPE_DEBUG,
726 "Peer %u (`%s') stopped\n",
727 p->no,
728 GNUNET_i2s (&p->id));
729 if (NULL != p->rh_task)
730 GNUNET_SCHEDULER_cancel (p->rh_task);
731 p->rh_task = NULL;
732 GNUNET_free (p);
733}
734
735
736/**
737 * Function called after the HELLO was passed to the
738 * transport service.
739 * FIXME maybe schedule the application_validate somehow
740 */
741/*
742 static void
743 hello_offered (void *cls)
744 {
745 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
746
747 cc->oh = NULL;
748 cc->tct = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
749 &offer_hello,
750 cc);
751 }*/
752
753
754/**
755 * Offer the current HELLO of P2 to P1.
756 *
757 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequest`
758 */
759static void
760offer_hello (void *cls)
761{
762 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
763 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1 = cc->p1;
764 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = cc->p2;
765 struct GNUNET_TIME_Absolute t;
766 enum GNUNET_NetworkType nt = 0;
767 char *addr;
768
769 cc->tct = NULL;
770 {
771 char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));
772
773 LOG (GNUNET_ERROR_TYPE_DEBUG,
774 "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %s\n",
775 p1->no,
776 GNUNET_i2s (&p1->id),
777 p2->no,
778 p2_s,
779 p2->hello);
780 GNUNET_free (p2_s);
781 }
782
783 addr = GNUNET_HELLO_extract_address (p2->hello,
784 p2->hello_size,
785 &p2->id,
786 &nt,
787 &t);
788 GNUNET_assert (NULL != addr);
789 GNUNET_assert (NULL != p1->hello);
790 GNUNET_TRANSPORT_application_validate (p1->ah,
791 &p2->id,
792 nt,
793 addr);
794 GNUNET_free (addr);
795}
796
797
798/**
799 * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
800 *
801 * Remarks: start_peer's notify_connect callback can be called before.
802 *
803 * @param tth transport testing handle
804 * @param p1 peer 1
805 * @param p2 peer 2
806 * @param cb the callback to call when both peers notified that they are connected
807 * @param cls callback cls
808 * @return a connect request handle
809 */
810struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
811GNUNET_TRANSPORT_TESTING_connect_peers (struct
812 GNUNET_TRANSPORT_TESTING_PeerContext *p1,
813 struct
814 GNUNET_TRANSPORT_TESTING_PeerContext *p2,
815 GNUNET_SCHEDULER_TaskCallback cb,
816 void *cls)
817{
818 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
819 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
820 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
821
822 ccn = NULL;
823 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
824 {
825 if ((cc->p1 == p1) &&
826 (cc->p2 == p2))
827 {
828 ccn = cc;
829 break;
830 }
831 }
832
833 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
834 cc->p1 = p1;
835 cc->p2 = p2;
836 cc->cb = cb;
837 if (NULL != cls)
838 cc->cb_cls = cls;
839 else
840 cc->cb_cls = cc;
841 if (NULL != ccn)
842 {
843 cc->p1_c = ccn->p1_c;
844 cc->p2_c = ccn->p2_c;
845 cc->connected = ccn->connected;
846 }
847 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
848 tth->cc_tail,
849 cc);
850 cc->tct = GNUNET_SCHEDULER_add_now (&offer_hello,
851 cc);
852 cc->ats_sh = GNUNET_ATS_connectivity_suggest (cc->p1->ats,
853 &p2->id,
854 1);
855 LOG (GNUNET_ERROR_TYPE_DEBUG,
856 "New connect request %p\n",
857 cc);
858 return cc;
859}
860
861
862/**
863 * Cancel the request to connect two peers
864 * Tou MUST cancel the request if you stop the peers before the peers connected successfully
865 *
866 * @param tth transport testing handle
867 * @param cc a connect request handle
868 */
869void
870GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
871 GNUNET_TRANSPORT_TESTING_ConnectRequest
872 *cc)
873{
874 struct GNUNET_TRANSPORT_TESTING_Handle *tth = cc->p1->tth;
875
876 LOG (GNUNET_ERROR_TYPE_DEBUG,
877 "Canceling connect request!\n");
878 if (NULL != cc->tct)
879 {
880 GNUNET_SCHEDULER_cancel (cc->tct);
881 cc->tct = NULL;
882 }
883 if (NULL != cc->ats_sh)
884 {
885 GNUNET_ATS_connectivity_suggest_cancel (cc->ats_sh);
886 cc->ats_sh = NULL;
887 }
888 GNUNET_CONTAINER_DLL_remove (tth->cc_head,
889 tth->cc_tail,
890 cc);
891 GNUNET_free (cc);
892}
893
894
895/**
896 * Clean up the transport testing
897 *
898 * @param tth transport testing handle
899 */
900void
901GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth)
902{
903 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
904 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ct;
905 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
906 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
907
908 if (NULL == tth)
909 return;
910 cc = tth->cc_head;
911 while (NULL != cc)
912 {
913 ct = cc->next;
914 LOG (GNUNET_ERROR_TYPE_ERROR,
915 "Developer forgot to cancel connect request!\n");
916 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
917 cc = ct;
918 }
919 p = tth->p_head;
920 while (NULL != p)
921 {
922 t = p->next;
923 LOG (GNUNET_ERROR_TYPE_ERROR,
924 "Developer forgot to stop peer!\n");
925 GNUNET_TRANSPORT_TESTING_stop_peer (p);
926 p = t;
927 }
928 GNUNET_TESTING_system_destroy (tth->tl_system,
929 GNUNET_YES);
930
931 GNUNET_free (tth);
932}
933
934
935/**
936 * Initialize the transport testing
937 *
938 * @return transport testing handle
939 */
940struct GNUNET_TRANSPORT_TESTING_Handle *
941GNUNET_TRANSPORT_TESTING_init ()
942{
943 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
944
945 tth = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_Handle);
946 tth->tl_system = GNUNET_TESTING_system_create ("transport-testing",
947 NULL,
948 NULL,
949 NULL);
950 if (NULL == tth->tl_system)
951 {
952 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
953 "Failed to initialize testing library!\n");
954 GNUNET_free (tth);
955 return NULL;
956 }
957 return tth;
958}
959
960
961/* end of transport-testing.c */
diff --git a/src/transport/transport-testing2.h b/src/transport/transport-testing2.h
deleted file mode 100644
index e2167ca7e..000000000
--- a/src/transport/transport-testing2.h
+++ /dev/null
@@ -1,924 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport-testing.h
23 * @brief testing lib for transport service
24 * @author Matthias Wachs
25 * @author Christian Grothoff
26 */
27#ifndef TRANSPORT_TESTING_H
28#define TRANSPORT_TESTING_H
29#include "platform.h"
30#include "gnunet_util_lib.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_peerstore_service.h"
33#include "gnunet_transport_core_service.h"
34#include "gnunet_transport_application_service.h"
35#include "gnunet_transport_manipulation_service.h"
36#include "gnunet_testing_lib.h"
37
38
39/* ************* Basic functions for starting/stopping/connecting *********** */
40
41/**
42 * Context for a single peer
43 */
44struct GNUNET_TRANSPORT_TESTING_PeerContext;
45
46/**
47 * Definition for a transport testing handle
48 */
49struct GNUNET_TRANSPORT_TESTING_Handle;
50
51
52/**
53 * Context for a single peer
54 */
55struct GNUNET_TRANSPORT_TESTING_PeerContext
56{
57 /**
58 * Next element in the DLL
59 */
60 struct GNUNET_TRANSPORT_TESTING_PeerContext *next;
61
62 /**
63 * Previous element in the DLL
64 */
65 struct GNUNET_TRANSPORT_TESTING_PeerContext *prev;
66
67 /**
68 * Transport testing handle this peer belongs to
69 */
70 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
71
72 /**
73 * Application handle
74 */
75 struct GNUNET_TRANSPORT_ApplicationHandle *ah;
76
77 /**
78 * Peer's configuration
79 */
80 struct GNUNET_CONFIGURATION_Handle *cfg;
81
82 /**
83 * Peer's transport service handle
84 */
85 struct GNUNET_TRANSPORT_CoreHandle *th;
86
87 /**
88 * Peer's ATS handle.
89 */
90 struct GNUNET_ATS_ConnectivityHandle *ats;
91
92 /**
93 * Peer's PEERSTORE Handle
94 */
95 struct GNUNET_PEERSTORE_Handle *ph;
96
97 /**
98 * Peer's transport get hello handle to retrieve peer's HELLO message
99 */
100 struct GNUNET_PEERSTORE_IterateContext *pic;
101
102 /**
103 * Hello
104 */
105 char *hello;
106
107 /**
108 * Hello size
109 */
110 size_t hello_size;
111
112 /**
113 * Peer's testing handle
114 */
115 struct GNUNET_TESTING_Peer *peer;
116
117 /**
118 * Peer identity
119 */
120 struct GNUNET_PeerIdentity id;
121
122 /**
123 * Handle for the peer's ARM process
124 */
125 struct GNUNET_OS_Process *arm_proc;
126
127 /**
128 * Receive callback
129 */
130 struct GNUNET_MQ_MessageHandler *handlers;
131
132 /**
133 * Notify connect callback
134 */
135 GNUNET_TRANSPORT_NotifyConnect nc;
136
137 /**
138 * Notify disconnect callback
139 */
140 GNUNET_TRANSPORT_NotifyDisconnect nd;
141
142 /**
143 * Startup completed callback
144 */
145 GNUNET_SCHEDULER_TaskCallback start_cb;
146
147 /**
148 * Hello get task
149 */
150 struct GNUNET_SCHEDULER_Task *rh_task;
151
152 /**
153 * Closure for the @a nc and @a nd callbacks
154 */
155 void *cb_cls;
156
157 /**
158 * Closure for @e start_cb.
159 */
160 void *start_cb_cls;
161
162 /**
163 * An unique number to identify the peer
164 */
165 unsigned int no;
166};
167
168
169/**
170 * Handle for a request to connect two peers.
171 */
172struct GNUNET_TRANSPORT_TESTING_ConnectRequest
173{
174 /**
175 * Kept in a DLL.
176 */
177 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *next;
178
179 /**
180 * Kept in a DLL.
181 */
182 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *prev;
183
184 /**
185 * Peer we want to connect.
186 */
187 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
188
189 /**
190 * Peer we want to connect.
191 */
192 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
193
194 /**
195 * Task by which we accomplish the connection.
196 */
197 struct GNUNET_SCHEDULER_Task *tct;
198
199 /**
200 * Handle by which we ask ATS to facilitate the connection.
201 */
202 struct GNUNET_ATS_ConnectivitySuggestHandle *ats_sh;
203
204 /**
205 * Function to call upon completion.
206 */
207 GNUNET_SCHEDULER_TaskCallback cb;
208
209 /**
210 * Closure for @e cb.
211 */
212 void *cb_cls;
213
214 /**
215 * Message queue for sending from @a p1 to @a p2.
216 */
217 struct GNUNET_MQ_Handle *mq;
218
219 /**
220 * Set if peer1 says the connection is up to peer2.
221 */
222 int p1_c;
223
224 /**
225 * Set if peer2 says the connection is up to peer1.
226 */
227 int p2_c;
228
229 /**
230 * #GNUNET_YES if both @e p1_c and @e p2_c are #GNUNET_YES.
231 */
232 int connected;
233};
234
235
236/**
237 * Handle for a test run.
238 */
239struct GNUNET_TRANSPORT_TESTING_Handle
240{
241 /**
242 * Testing library system handle
243 */
244 struct GNUNET_TESTING_System *tl_system;
245
246 /**
247 * head DLL of connect contexts
248 */
249 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_head;
250
251 /**
252 * head DLL of connect contexts
253 */
254 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_tail;
255
256 /**
257 * head DLL of peers
258 */
259 struct GNUNET_TRANSPORT_TESTING_PeerContext *p_head;
260
261 /**
262 * tail DLL of peers
263 */
264 struct GNUNET_TRANSPORT_TESTING_PeerContext *p_tail;
265};
266
267
268/**
269 * Initialize the transport testing
270 *
271 * @return transport testing handle
272 */
273struct GNUNET_TRANSPORT_TESTING_Handle *
274GNUNET_TRANSPORT_TESTING_init (void);
275
276
277/**
278 * Clean up the transport testing
279 *
280 * @param tth transport testing handle
281 */
282void
283GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth);
284
285
286/**
287 * Start a peer with the given configuration
288 *
289 * @param tth the testing handle
290 * @param cfgname configuration file
291 * @param peer_id the peer_id
292 * @param handlers functions for receiving messages
293 * @param nc connect callback
294 * @param nd disconnect callback
295 * @param cb_cls closure for @a nc and @a nd callback
296 * @param start_cb start callback
297 * @param start_cb_cls closure for @a start_cb
298 * @return the peer context
299 */
300struct GNUNET_TRANSPORT_TESTING_PeerContext *
301GNUNET_TRANSPORT_TESTING_start_peer (
302 struct GNUNET_TRANSPORT_TESTING_Handle *tth,
303 const char *cfgname,
304 int peer_id,
305 const struct GNUNET_MQ_MessageHandler *handlers,
306 GNUNET_TRANSPORT_NotifyConnect nc,
307 GNUNET_TRANSPORT_NotifyDisconnect nd,
308 void *cb_cls,
309 GNUNET_SCHEDULER_TaskCallback start_cb,
310 void *start_cb_cls);
311
312
313/**
314 * Shutdown the given peer
315 *
316 * @param p the peer
317 */
318void
319GNUNET_TRANSPORT_TESTING_stop_peer (
320 struct GNUNET_TRANSPORT_TESTING_PeerContext *pc);
321
322
323/**
324 * Stops and restarts the given peer, sleeping (!) for 5s in between.
325 *
326 * @param p the peer
327 * @param restart_cb restart callback
328 * @param restart_cb_cls callback closure
329 * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
330 */
331int
332GNUNET_TRANSPORT_TESTING_restart_peer (
333 struct GNUNET_TRANSPORT_TESTING_PeerContext *p,
334 GNUNET_SCHEDULER_TaskCallback restart_cb,
335 void *restart_cb_cls);
336
337
338/**
339 * Connect the given peers and call the callback when both peers
340 * report the inbound connection. Remarks: start_peer's notify_connect
341 * callback can be called before.
342 *
343 * @param p1 peer 1
344 * @param p2 peer 2
345 * @param cb the callback to call when both peers notified that they are
346 * connected
347 * @param cls callback cls
348 * @return a connect request handle
349 */
350struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
351GNUNET_TRANSPORT_TESTING_connect_peers (
352 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
353 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
354 GNUNET_SCHEDULER_TaskCallback cb,
355 void *cls);
356
357
358/**
359 * Cancel the request to connect two peers. You MUST cancel the
360 * request if you stop the peers before the peers connected
361 * successfully.
362 *
363 * @param cc a connect request handle
364 */
365void
366GNUNET_TRANSPORT_TESTING_connect_peers_cancel (
367 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc);
368
369
370/**
371 * Function called on matching connect requests.
372 *
373 * @param cls closure
374 * @param cc request matching the query
375 */
376typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContextCallback) (
377 void *cls,
378 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc);
379
380
381/**
382 * Find any connecting context matching the given pair of peers.
383 *
384 * @param p1 first peer
385 * @param p2 second peer
386 * @param cb function to call
387 * @param cb_cls closure for @a cb
388 */
389void
390GNUNET_TRANSPORT_TESTING_find_connecting_context (
391 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
392 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
393 GNUNET_TRANSPORT_TESTING_ConnectContextCallback cb,
394 void *cb_cls);
395
396
397/* ********************** high-level process functions *************** */
398
399
400/**
401 * Function called once the peers have been launched and
402 * connected by #GNUNET_TRANSPORT_TESTING_connect_check().
403 *
404 * @param cls closure
405 * @param num_peers size of the @a p array
406 * @param p the peers that were launched
407 */
408typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContinuation) (
409 void *cls,
410 unsigned int num_peers,
411 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[]);
412
413
414/**
415 * Internal data structure.
416 */
417struct GNUNET_TRANSPORT_TESTING_ConnectRequestList;
418
419/**
420 * Internal data structure.
421 */
422struct GNUNET_TRANSPORT_TESTING_InternalPeerContext;
423
424
425GNUNET_NETWORK_STRUCT_BEGIN
426struct GNUNET_TRANSPORT_TESTING_TestMessage
427{
428 /**
429 * Type is (usually) #GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE.
430 */
431 struct GNUNET_MessageHeader header;
432
433 /**
434 * Monotonically increasing counter throughout the test.
435 */
436 uint32_t num GNUNET_PACKED;
437};
438GNUNET_NETWORK_STRUCT_END
439
440
441/**
442 * Function called by the transport for each received message.
443 *
444 * @param cls closure
445 * @param receiver receiver of the message
446 * @param sender sender of the message
447 * @param message the message
448 */
449typedef void (*GNUNET_TRANSPORT_TESTING_ReceiveCallback) (
450 void *cls,
451 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
452 const struct GNUNET_PeerIdentity *sender,
453 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message);
454
455
456/**
457 * Function called to notify transport users that another
458 * peer connected to us.
459 *
460 * @param cls closure
461 * @param me peer experiencing the event
462 * @param other peer that connected to @a me
463 */
464typedef void (*GNUNET_TRANSPORT_TESTING_NotifyConnect) (
465 void *cls,
466 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
467 const struct GNUNET_PeerIdentity *other);
468
469
470/**
471 * Function called to notify transport users that another
472 * peer disconnected from us.
473 *
474 * @param cls closure
475 * @param me peer experiencing the event
476 * @param other peer that disconnected from @a me
477 */
478typedef void (*GNUNET_TRANSPORT_TESTING_NotifyDisconnect) (
479 void *cls,
480 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
481 const struct GNUNET_PeerIdentity *other);
482
483
484/**
485 * Closure that must be passed to
486 * #GNUNET_TRANSPORT_TESTING_connect_check.
487 */
488struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext
489{
490 /**
491 * How should we continue after the connect?
492 */
493 GNUNET_SCHEDULER_TaskCallback connect_continuation;
494
495 /**
496 * Closure for @e connect_continuation.
497 */
498 void *connect_continuation_cls;
499
500 /**
501 * Which configuration file should we pass to the
502 * #GNUNET_PROGRAM_run() of the testcase?
503 */
504 const char *config_file;
505
506 /**
507 * Receiver argument to give for peers we start.
508 */
509 GNUNET_TRANSPORT_TESTING_ReceiveCallback rec;
510
511 /**
512 * Notify connect argument to give for peers we start.
513 */
514 GNUNET_TRANSPORT_TESTING_NotifyConnect nc;
515
516 /**
517 * Notify disconnect argument to give for peers we start.
518 */
519 GNUNET_TRANSPORT_TESTING_NotifyDisconnect nd;
520
521 /**
522 * Closure for @e rec, @e nc and @e nd.
523 */
524 void *cls;
525
526 /**
527 * Custom task to run on shutdown.
528 */
529 GNUNET_SCHEDULER_TaskCallback shutdown_task;
530
531 /**
532 * Closure for @e shutdown_task.
533 */
534 void *shutdown_task_cls;
535
536 /**
537 * Custom task to run after peers were started but before we try to
538 * connect them. If this function is set, we wait ONE second after
539 * running this function until we continue with connecting the
540 * peers.
541 */
542 GNUNET_SCHEDULER_TaskCallback pre_connect_task;
543
544 /**
545 * Closure for @e shutdown_task.
546 */
547 void *pre_connect_task_cls;
548
549 /**
550 * When should the testcase time out?
551 */
552 struct GNUNET_TIME_Relative timeout;
553
554 /**
555 * Should we try to create connections in both directions?
556 */
557 int bi_directional;
558
559 /* ******* fields set by #GNUNET_TRANSPORT_TESTING_connect_check **** */
560
561 /**
562 * Number of peers involved in the test.
563 */
564 unsigned int num_peers;
565
566 /**
567 * Configuration files we have, array with @e num_peers entries.
568 */
569 char **cfg_files;
570
571 /**
572 * Array with @e num_peers entries.
573 */
574 struct GNUNET_TRANSPORT_TESTING_PeerContext **p;
575
576 /**
577 * Name of the plugin.
578 */
579 const char *test_plugin;
580
581 /**
582 * Name of the testcase.
583 */
584 const char *test_name;
585
586 /**
587 * Configuration object for the testcase.
588 */
589 const struct GNUNET_CONFIGURATION_Handle *cfg;
590
591 /**
592 * Main testing handle.
593 */
594 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
595
596 /**
597 * Result from the main function, set to #GNUNET_OK on success.
598 * Clients should set to #GNUNET_SYSERR to indicate test failure.
599 */
600 int global_ret;
601
602 /**
603 * Generator for the `num` field in test messages. Incremented each
604 * time #GNUNET_TRANSPORT_TESTING_simple_send or
605 * #GNUNET_TRANSPORT_TESTING_large_send are used to transmit a
606 * message.
607 */
608 uint32_t send_num_gen;
609
610 /* ******* internal state, clients should not mess with this **** */
611
612 /**
613 * Task run on timeout.
614 */
615 struct GNUNET_SCHEDULER_Task *timeout_task;
616
617 /**
618 * Task run to connect peers.
619 */
620 struct GNUNET_SCHEDULER_Task *connect_task;
621
622 /**
623 * Number of peers that have been started.
624 */
625 unsigned int started;
626
627 /**
628 * DLL of active connect requests.
629 */
630 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_head;
631
632 /**
633 * DLL of active connect requests.
634 */
635 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_tail;
636
637 /**
638 * Array with @e num_peers entries.
639 */
640 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ip;
641};
642
643
644/**
645 * Find peer by peer ID.
646 *
647 * @param ccc context to search
648 * @param peer peer to look for
649 * @return NULL if @a peer was not found
650 */
651struct GNUNET_TRANSPORT_TESTING_PeerContext *
652GNUNET_TRANSPORT_TESTING_find_peer (
653 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
654 const struct GNUNET_PeerIdentity *peer);
655
656
657/**
658 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
659 * Starts and connects the two peers, then invokes the
660 * `connect_continuation` from @a cls. Sets up a timeout to
661 * abort the test, and a shutdown handler to clean up properly
662 * on exit.
663 *
664 * @param cls closure of type `struct
665 * GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
666 * @param tth_ initialized testing handle
667 * @param test_plugin_ name of the plugin
668 * @param test_name_ name of the test
669 * @param num_peers number of entries in the @a cfg_file array
670 * @param cfg_files array of names of configuration files for the peers
671 * @return #GNUNET_SYSERR on error
672 */
673int
674GNUNET_TRANSPORT_TESTING_connect_check (
675 void *cls,
676 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
677 const char *test_plugin_,
678 const char *test_name_,
679 unsigned int num_peers,
680 char *cfg_files[]);
681
682
683/**
684 * Main function of a testcase. Called with the initial setup data
685 * for the test as derived from the source name and the binary name.
686 *
687 * @param cls closure
688 * @param tth_ initialized testing handle
689 * @param test_plugin_ name of the plugin
690 * @param test_name_ name of the test
691 * @param num_peers number of entries in the @a cfg_file array
692 * @param cfg_files array of names of configuration files for the peers
693 * @return #GNUNET_SYSERR on error
694 */
695typedef int (*GNUNET_TRANSPORT_TESTING_CheckCallback) (
696 void *cls,
697 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
698 const char *test_plugin_,
699 const char *test_name_,
700 unsigned int num_peers,
701 char *cfg_files[]);
702
703
704/**
705 * Setup testcase. Calls @a check with the data the test needs.
706 *
707 * @param argv0 binary name (argv[0])
708 * @param filename source file name (__FILE__)
709 * @param num_peers number of peers to start
710 * @param check main function to run
711 * @param check_cls closure for @a check
712 * @return #GNUNET_OK on success
713 */
714int
715GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
716 const char *filename,
717 unsigned int num_peers,
718 GNUNET_TRANSPORT_TESTING_CheckCallback check,
719 void *check_cls);
720
721
722/**
723 * Setup testcase. Calls @a check with the data the test needs.
724 *
725 * @param num_peers number of peers to start
726 * @param check main function to run
727 * @param check_cls closure for @a check
728 * @return #GNUNET_OK on success
729 */
730#define GNUNET_TRANSPORT_TESTING_main(num_peers, check, check_cls) \
731 GNUNET_TRANSPORT_TESTING_main_ (argv[0], \
732 __FILE__, \
733 num_peers, \
734 check, \
735 check_cls)
736
737/* ***************** Convenience functions for sending ********* */
738
739/**
740 * Send a test message of type @a mtype and size @a msize from
741 * peer @a sender to peer @a receiver. The peers should be
742 * connected when this function is called.
743 *
744 * @param sender the sending peer
745 * @param receiver the receiving peer
746 * @param mtype message type to use
747 * @param msize size of the message, at least `sizeof (struct
748 * GNUNET_TRANSPORT_TESTING_TestMessage)`
749 * @param num unique message number
750 * @param cont continuation to call after transmission
751 * @param cont_cls closure for @a cont
752 * @return #GNUNET_OK if message was queued,
753 * #GNUNET_NO if peers are not connected
754 * #GNUNET_SYSERR if @a msize is illegal
755 */
756int
757GNUNET_TRANSPORT_TESTING_send (
758 struct GNUNET_TRANSPORT_TESTING_PeerContext *sender,
759 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
760 uint16_t mtype,
761 uint16_t msize,
762 uint32_t num,
763 GNUNET_SCHEDULER_TaskCallback cont,
764 void *cont_cls);
765
766
767/**
768 * Message type used by #GNUNET_TRANSPORT_TESTING_simple_send().
769 */
770#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE 12345
771
772/**
773 * Alternative message type for tests.
774 */
775#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2 12346
776
777
778/**
779 * Type of the closure argument to pass to
780 * #GNUNET_TRANSPORT_TESTING_simple_send() and
781 * #GNUNET_TRANSPORT_TESTING_large_send().
782 */
783struct GNUNET_TRANSPORT_TESTING_SendClosure
784{
785 /**
786 * Context for the transmission.
787 */
788 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
789
790 /**
791 * Function that returns the desired message size. Overrides
792 * the message size, can be NULL in which case the message
793 * size is the default.
794 */
795 size_t (*get_size_cb) (unsigned int n);
796
797 /**
798 * Number of messages to be transmitted in a loop.
799 * Use zero for "forever" (until external shutdown).
800 */
801 unsigned int num_messages;
802
803 /**
804 * Function to call after all transmissions, can be NULL.
805 */
806 GNUNET_SCHEDULER_TaskCallback cont;
807
808 /**
809 * Closure for @e cont.
810 */
811 void *cont_cls;
812};
813
814
815/**
816 * Task that sends a minimalistic test message from the
817 * first peer to the second peer.
818 *
819 * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure`
820 * which should contain at least two peers, the first two
821 * of which should be currently connected
822 */
823void
824GNUNET_TRANSPORT_TESTING_simple_send (void *cls);
825
826/**
827 * Size of a message sent with
828 * #GNUNET_TRANSPORT_TESTING_large_send(). Big enough
829 * to usually force defragmentation.
830 */
831#define GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE 2600
832
833/**
834 * Task that sends a large test message from the
835 * first peer to the second peer.
836 *
837 * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure`
838 * which should contain at least two peers, the first two
839 * of which should be currently connected
840 */
841void
842GNUNET_TRANSPORT_TESTING_large_send (void *cls);
843
844
845/* ********************** log-only convenience functions ************* */
846
847
848/**
849 * Log a connect event.
850 *
851 * @param cls NULL
852 * @param me peer that had the event
853 * @param other peer that connected.
854 */
855void
856GNUNET_TRANSPORT_TESTING_log_connect (
857 void *cls,
858 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
859 const struct GNUNET_PeerIdentity *other);
860
861
862/**
863 * Log a disconnect event.
864 *
865 * @param cls NULL
866 * @param me peer that had the event
867 * @param other peer that disconnected.
868 */
869void
870GNUNET_TRANSPORT_TESTING_log_disconnect (
871 void *cls,
872 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
873 const struct GNUNET_PeerIdentity *other);
874
875
876/* ********************** low-level filename functions *************** */
877
878
879/**
880 * Extracts the test filename from an absolute file name and removes
881 * the extension.
882 *
883 * @param file absolute file name
884 * @return resulting test name
885 */
886char *
887GNUNET_TRANSPORT_TESTING_get_test_name (const char *file);
888
889
890/**
891 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
892 * if existing ".exe"-prefix and adds the peer-number
893 *
894 * @param file filename of the test, e.g. argv[0]
895 * @param count peer number
896 * @return configuration name to use
897 */
898char *
899GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, int count);
900
901
902/**
903 * Extracts the plugin anme from an absolute file name and the test name
904 * @param file absolute file name
905 * @param test test name
906 * @return the plugin name
907 */
908char *
909GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *executable,
910 const char *testname);
911
912
913/**
914 * Extracts the filename from an absolute file name and removes the
915 * extension
916 *
917 * @param file absolute file name
918 * @return the source name
919 */
920char *
921GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file);
922
923#endif
924/* end of transport_testing.h */
diff --git a/src/transport/transport.conf.in b/src/transport/transport.conf.in
deleted file mode 100644
index c6b207ad7..000000000
--- a/src/transport/transport.conf.in
+++ /dev/null
@@ -1,237 +0,0 @@
1[transport]
2START_ON_DEMAND = @START_ON_DEMAND@
3@JAVAPORT@PORT = 2091
4HOSTNAME = localhost
5BINARY = gnunet-service-transport
6# PREFIX = valgrind
7
8# Maximum number of neighbours PER PLUGIN (not in total).
9NEIGHBOUR_LIMIT = 50
10ACCEPT_FROM = 127.0.0.1;
11ACCEPT_FROM6 = ::1;
12# TCP is the only transport plugin known to work "reliably"
13PLUGINS = tcp
14UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport.sock
15BLACKLIST_FILE = $GNUNET_CONFIG_HOME/transport/blacklist
16UNIX_MATCH_UID = NO
17UNIX_MATCH_GID = YES
18# DISABLE_SOCKET_FORWARDING = NO
19# USERNAME =
20# MAXBUF =
21# TIMEOUT =
22# DISABLEV6 =
23# BINDTO =
24# REJECT_FROM =
25# REJECT_FROM6 =
26# PREFIX = valgrind --leak-check=full
27
28# Configuration settings related to traffic manipulation for testing purposes
29# Distance
30# MANIPULATE_DISTANCE_IN = 1
31# MANIPULATE_DISTANCE_OUT = 1
32# Delay; WARNING: to large values may lead to peers not connecting!
33# MANIPULATE_DELAY_IN = 1 ms
34# MANIPULATE_DELAY_OUT = 1 ms
35
36
37[transport-unix]
38UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-transport-plugin-unix.sock
39TESTING_IGNORE_KEYS = ACCEPT_FROM;
40
41[transport-tcp]
42# Use 0 to ONLY advertise as a peer behind NAT (no port binding)
43PORT = 2086
44
45# Obsolete option, to be replaced by HOLE_EXTERNAL (soon)
46ADVERTISED_PORT = 2086
47
48# If we have a manually punched NAT, what is the external IP and port?
49# Can use DNS names for DynDNS-based detection of external IP.
50# Can use IPv6 addresses ([fefc::]:PORT).
51# Use "AUTO" for the hostname to automatically detect external IP.
52# Do not set if NAT is not manually punched.
53# HOLE_EXTERNAL = AUTO:2086
54
55TESTING_IGNORE_KEYS = ACCEPT_FROM;
56
57# Maximum number of open TCP connections allowed
58MAX_CONNECTIONS = 128
59
60TIMEOUT = 5 s
61# ACCEPT_FROM =
62# ACCEPT_FROM6 =
63# REJECT_FROM =
64# REJECT_FROM6 =
65# BINDTO =
66MAX_CONNECTIONS = 128
67
68# Enable TCP stealth?
69TCP_STEALTH = NO
70
71
72
73[transport-xt]
74# Use 0 to ONLY advertise as a peer behind NAT (no port binding)
75PORT = 2087
76
77# Obsolete option, to be replaced by HOLE_EXTERNAL (soon)
78ADVERTISED_PORT = 2087
79
80# If we have a manually punched NAT, what is the external IP and port?
81# Can use DNS names for DynDNS-based detection of external IP.
82# Can use IPv6 addresses ([fefc::]:PORT).
83# Use "AUTO" for the hostname to automatically detect external IP.
84# Do not set if NAT is not manually punched.
85# HOLE_EXTERNAL = AUTO:2087
86
87TESTING_IGNORE_KEYS = ACCEPT_FROM;
88
89# Maximum number of open TCP connections allowed
90MAX_CONNECTIONS = 128
91
92TIMEOUT = 5 s
93# ACCEPT_FROM =
94# ACCEPT_FROM6 =
95# REJECT_FROM =
96# REJECT_FROM6 =
97# BINDTO =
98MAX_CONNECTIONS = 128
99
100# Enable TCP stealth?
101TCP_STEALTH = NO
102
103
104[transport-udp]
105# Use PORT = 0 to autodetect a port available
106PORT = 2086
107BROADCAST = YES
108BROADCAST_RECEIVE = YES
109BROADCAST_INTERVAL = 30 s
110
111# This limits UDP to 1MB/s for SENDING. Higher values are advised
112# for benchmarking or well-connected systems. Note that this quota
113# applies IN ADDITION to the system-wide transport-wide WAN/LAN
114# quotas.
115MAX_BPS = 1000000
116TESTING_IGNORE_KEYS = ACCEPT_FROM;
117
118# If we have a manually punched NAT, what is the external IP and port?
119# Can use DNS names for DynDNS-based detection of external IP.
120# Can use IPv6 addresses ([fefc::]:PORT).
121# Use "AUTO" for the hostname to automatically detect external IP.
122# Do not set if NAT is not manually punched.
123# HOLE_EXTERNAL = AUTO:2086
124
125
126[transport-xu]
127# Use PORT = 0 to autodetect a port available
128PORT = 2087
129
130
131[transport-http_client]
132MAX_CONNECTIONS = 128
133TESTING_IGNORE_KEYS = ACCEPT_FROM;
134# Hostname or IP of proxy server
135# PROXY =
136
137# User name for proxy server
138# PROXY_USERNAME =
139# User password for proxy server
140# PROXY_PASSWORD =
141
142# Type of proxy server,
143# Valid values: HTTP, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME
144# Default: HTTP
145# PROXY_TYPE = HTTP
146
147# Enable tunneling proxy request instead of having proxy server evaluate it
148# Experimental, default: NO
149# PROXY_HTTP_TUNNELING = NO
150
151
152[transport-http_server]
153#EXTERNAL_HOSTNAME = <your hostname/path>
154PORT = 1080
155
156# Obsolete option, to be replaced by HOLE_EXTERNAL (soon)
157ADVERTISED_PORT = 1080
158
159# If we have a manually punched NAT, what is the external IP and port?
160# Can use DNS names for DynDNS-based detection of external IP.
161# Can use IPv6 addresses ([fefc::]:PORT).
162# Use "AUTO" for the hostname to automatically detect external IP.
163# Do not set if NAT is not manually punched.
164# HOLE_EXTERNAL = AUTO:1080
165
166MAX_CONNECTIONS = 128
167TESTING_IGNORE_KEYS = ACCEPT_FROM;
168
169# Enable TCP stealth?
170TCP_STEALTH = NO
171
172
173[transport-https_client]
174MAX_CONNECTIONS = 128
175TESTING_IGNORE_KEYS = ACCEPT_FROM;
176# Hostname or IP of proxy server
177# PROXY =
178
179# User name for proxy server
180# PROXY_USERNAME =
181# User password for proxy server
182# PROXY_PASSWORD =
183
184# Type of proxy server,
185# Valid values: HTTP, SOCKS4, SOCKS5, SOCKS4A, SOCKS5_HOSTNAME
186# Default: HTTP
187# PROXY_TYPE = HTTP
188
189# Enable tunneling proxy request instead of having proxy server evaluate it
190# Experimental, default: NO
191# PROXY_HTTP_TUNNELING = NO
192
193
194[transport-https_server]
195# EXTERNAL_HOSTNAME = <your hostname/path>
196# EXTERNAL_HOSTNAME_ONLY = YES
197# If you have a valid SSL certificate for your external hostname tell,
198# clients to verify it
199# VERIFY_EXTERNAL_HOSTNAME = YES
200# Does the external hostname use the same port?
201# EXTERNAL_HOSTNAME_USE_PORT = YES
202PORT = 4433
203
204# Obsolete option, to be replaced by HOLE_EXTERNAL (soon)
205ADVERTISED_PORT = 4433
206
207# If we have a manually punched NAT, what is the external IP and port?
208# Can use DNS names for DynDNS-based detection of external IP.
209# Can use IPv6 addresses ([fefc::]:PORT).
210# Use "AUTO" for the hostname to automatically detect external IP.
211# Do not set if NAT is not manually punched.
212# HOLE_EXTERNAL = AUTO:4433
213
214CRYPTO_INIT = NORMAL
215KEY_FILE = $GNUNET_DATA_HOME/transport/https.key
216CERT_FILE = $GNUNET_DATA_HOME/transport/https.cert
217MAX_CONNECTIONS = 128
218TESTING_IGNORE_KEYS = ACCEPT_FROM;
219
220# Enable TCP stealth?
221TCP_STEALTH = NO
222
223
224[transport-wlan]
225# Name of the interface in monitor mode (typically monX)
226INTERFACE = mon0
227# Real hardware, no testing
228TESTMODE = 0
229TESTING_IGNORE_KEYS = ACCEPT_FROM;
230
231
232[transport-bluetooth]
233# Name of the interface (typically hciX)
234INTERFACE = hci0
235# Real hardware, no testing
236TESTMODE = 0
237TESTING_IGNORE_KEYS = ACCEPT_FROM;
diff --git a/src/transport/transport.h b/src/transport/transport.h
deleted file mode 100644
index 8ffc87070..000000000
--- a/src/transport/transport.h
+++ /dev/null
@@ -1,1241 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2014 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport.h
23 * @brief common internal definitions for transport service
24 * @author Christian Grothoff
25 */
26#ifndef TRANSPORT_H
27#define TRANSPORT_H
28
29#include "gnunet_crypto_lib.h"
30#include "gnunet_time_lib.h"
31#include "gnunet_constants.h"
32
33#define DEBUG_TRANSPORT GNUNET_EXTRA_LOGGING
34
35
36/**
37 * For how long do we allow unused bandwidth
38 * from the past to carry over into the future? (in seconds)
39 */
40#define MAX_BANDWIDTH_CARRY_S GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S
41
42/**
43 * How often do we (at most) do a full quota
44 * recalculation? (in ms)
45 */
46#define MIN_QUOTA_REFRESH_TIME 2000
47
48/**
49 * What's the maximum number of sockets transport uses for validation and
50 * neighbors
51 */
52#define DEFAULT_MAX_FDS 256
53
54/**
55 * Maximum frequency for re-evaluating latencies for all transport addresses.
56 */
57#define LATENCY_EVALUATION_MAX_DELAY \
58 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
59
60/**
61 * Maximum frequency for re-evaluating latencies for connected addresses.
62 */
63#define CONNECTED_LATENCY_EVALUATION_MAX_DELAY \
64 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
65
66/**
67 * Similar to GNUNET_TRANSPORT_NotifyDisconnect but in and out quotas are
68 * included here. These values are not required outside transport_api
69 *
70 * @param cls closure
71 * @param peer the peer that connected
72 * @param bandwidth_in inbound bandwidth in NBO
73 * @param bandwidth_out outbound bandwidth in NBO
74 *
75 */
76typedef void (*NotifyConnect) (
77 void *cls,
78 const struct GNUNET_PeerIdentity *peer,
79 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
80 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out);
81
82
83GNUNET_NETWORK_STRUCT_BEGIN
84
85
86/**
87 * Message from the transport service to the library
88 * asking to check if both processes agree about this
89 * peers identity.
90 */
91struct StartMessage
92{
93 /**
94 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_START
95 */
96 struct GNUNET_MessageHeader header;
97
98 /**
99 * 0: no options
100 * 1: The @e self field should be checked
101 * 2: this client is interested in payload traffic
102 */
103 uint32_t options;
104
105 /**
106 * Identity we think we have. If it does not match, the
107 * receiver should print out an error message and disconnect.
108 */
109 struct GNUNET_PeerIdentity self;
110};
111
112
113/**
114 * Message from the transport service to the library
115 * informing about neighbors.
116 */
117struct ConnectInfoMessage
118{
119 /**
120 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT
121 */
122 struct GNUNET_MessageHeader header;
123
124#if (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
125 defined(GNUNET_TRANSPORT_CORE_VERSION))
126
127 /**
128 * Always zero, for alignment.
129 */
130 uint32_t reserved GNUNET_PACKED;
131#else
132 /**
133 * Current outbound quota for this peer
134 */
135 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
136#endif
137
138 /**
139 * Identity of the new neighbour.
140 */
141 struct GNUNET_PeerIdentity id;
142};
143
144
145/**
146 * Message from the transport service to the library
147 * informing about disconnects.
148 */
149struct DisconnectInfoMessage
150{
151 /**
152 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT
153 */
154 struct GNUNET_MessageHeader header;
155
156 /**
157 * Reserved, always zero.
158 */
159 uint32_t reserved GNUNET_PACKED;
160
161 /**
162 * Who got disconnected?
163 */
164 struct GNUNET_PeerIdentity peer;
165};
166
167
168/**
169 * Message used to set a particular bandwidth quota. Sent TO the
170 * service to set an incoming quota, sent FROM the service to update
171 * an outgoing quota.
172 *
173 * NOTE: no longer used in TNG!
174 */
175struct QuotaSetMessage
176{
177 /**
178 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA
179 */
180 struct GNUNET_MessageHeader header;
181
182 /**
183 * Quota.
184 */
185 struct GNUNET_BANDWIDTH_Value32NBO quota;
186
187 /**
188 * About which peer are we talking here?
189 */
190 struct GNUNET_PeerIdentity peer;
191};
192
193
194/**
195 * Message used to notify the transport API about a message
196 * received from the network. The actual message follows.
197 */
198struct InboundMessage
199{
200 /**
201 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_RECV
202 */
203 struct GNUNET_MessageHeader header;
204
205 /**
206 * Which peer sent the message?
207 */
208 struct GNUNET_PeerIdentity peer;
209};
210
211
212/**
213 * Message used to notify the transport API that it can
214 * send another message to the transport service.
215 */
216struct SendOkMessage
217{
218 /**
219 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK
220 */
221 struct GNUNET_MessageHeader header;
222
223#if (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
224 defined(GNUNET_TRANSPORT_CORE_VERSION))
225
226 uint32_t reserved GNUNET_PACKED;
227#else
228 /**
229 * #GNUNET_OK if the transmission succeeded,
230 * #GNUNET_SYSERR if it failed (i.e. network disconnect);
231 * in either case, it is now OK for this client to
232 * send us another message for the given peer.
233 */
234 uint16_t success GNUNET_PACKED;
235
236 /**
237 * Size of message sent
238 */
239 uint16_t bytes_msg GNUNET_PACKED;
240
241 /**
242 * Size of message sent over wire.
243 * Includes plugin and protocol specific overheads.
244 */
245 uint32_t bytes_physical GNUNET_PACKED;
246#endif
247
248 /**
249 * Which peer can send more now?
250 */
251 struct GNUNET_PeerIdentity peer;
252};
253
254
255/**
256 * Message used to notify the transport API that it can
257 * send another message to the transport service.
258 * (Used to implement flow control.)
259 */
260struct RecvOkMessage
261{
262 /**
263 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK
264 */
265 struct GNUNET_MessageHeader header;
266
267 /**
268 * Number of messages by which to increase the window, greater or
269 * equal to one.
270 */
271 uint32_t increase_window_delta GNUNET_PACKED;
272
273 /**
274 * Which peer can CORE handle more from now?
275 */
276 struct GNUNET_PeerIdentity peer;
277};
278
279
280/**
281 * Message used to notify the transport service about a message
282 * to be transmitted to another peer. The actual message follows.
283 */
284struct OutboundMessage
285{
286 /**
287 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND
288 */
289 struct GNUNET_MessageHeader header;
290
291 /**
292 * An `enum GNUNET_MQ_PriorityPreferences` in NBO.
293 */
294 uint32_t priority GNUNET_PACKED;
295
296#if ! (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
297 defined(GNUNET_TRANSPORT_CORE_VERSION))
298
299 /**
300 * Allowed delay.
301 */
302 struct GNUNET_TIME_RelativeNBO timeout;
303#endif
304
305 /**
306 * Which peer should receive the message?
307 */
308 struct GNUNET_PeerIdentity peer;
309};
310
311
312#if ! (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
313 defined(GNUNET_TRANSPORT_CORE_VERSION))
314
315
316/**
317 * Message used to notify the transport API about an address to string
318 * conversion. Message is followed by the string with the humand-readable
319 * address. For each lookup, multiple results may be returned. The
320 * last message must have a @e res of #GNUNET_OK and an @e addr_len
321 * of zero.
322 */
323struct AddressToStringResultMessage
324{
325 /**
326 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY
327 */
328 struct GNUNET_MessageHeader header;
329
330 /**
331 * #GNUNET_OK if the conversion succeeded,
332 * #GNUNET_SYSERR if it failed
333 */
334 uint32_t res GNUNET_PACKED;
335
336 /**
337 * Length of the following string, zero if @e is #GNUNET_SYSERR
338 */
339 uint32_t addr_len GNUNET_PACKED;
340};
341
342
343/**
344 * Message from the library to the transport service
345 * asking for converting a transport address to a
346 * human-readable UTF-8 string.
347 */
348struct AddressLookupMessage
349{
350 /**
351 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING
352 */
353 struct GNUNET_MessageHeader header;
354
355 /**
356 * Should the conversion use numeric IP addresses (otherwise
357 * a reverse DNS lookup is OK -- if applicable).
358 */
359 int16_t numeric_only GNUNET_PACKED;
360
361 /**
362 * Length of the (binary) address in bytes, in big-endian.
363 */
364 uint16_t addrlen GNUNET_PACKED;
365
366 /**
367 * timeout to give up (for DNS resolution timeout mostly)
368 */
369 struct GNUNET_TIME_RelativeNBO timeout;
370
371 /* followed by @e addrlen bytes of the actual address, then
372 * followed by the 0-terminated name of the transport */
373};
374
375
376/**
377 * Message from the transport service to the library containing information
378 * about a peer. Information contained are:
379 * - current address used to communicate with this peer
380 * - state
381 * - state timeout
382 *
383 * Memory layout:
384 * [AddressIterateResponseMessage][address[addrlen]][transportname[pluginlen]]
385 */
386struct ValidationIterateResponseMessage
387{
388 /**
389 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_RESPONSE
390 */
391 struct GNUNET_MessageHeader header;
392
393 /**
394 * For alignment.
395 */
396 uint32_t reserved;
397
398 /**
399 * Peer identity
400 */
401 struct GNUNET_PeerIdentity peer;
402
403 /**
404 * Local info about the address
405 */
406 uint32_t local_address_info GNUNET_PACKED;
407
408 /**
409 * Address length
410 */
411 uint32_t addrlen GNUNET_PACKED;
412
413 /**
414 * Length of the plugin name
415 */
416 uint32_t pluginlen GNUNET_PACKED;
417
418 /**
419 * State
420 */
421 uint32_t state GNUNET_PACKED;
422
423 /**
424 * At what time did we successfully validate the address last.
425 * Will be NEVER if the address failed validation.
426 */
427 struct GNUNET_TIME_AbsoluteNBO last_validation;
428
429 /**
430 * Until when is the address believed to be valid.
431 * Will be ZERO if the address is not believed to be valid.
432 */
433 struct GNUNET_TIME_AbsoluteNBO valid_until;
434
435 /**
436 * When will we next try to validate the address (typically
437 * done before @e valid_until happens).
438 */
439 struct GNUNET_TIME_AbsoluteNBO next_validation;
440};
441
442
443/**
444 * Message from the library to the transport service
445 * asking for binary addresses known for a peer.
446 */
447struct ValidationMonitorMessage
448{
449 /**
450 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_VALIDATION_REQUEST
451 */
452 struct GNUNET_MessageHeader header;
453
454 /**
455 * One shot call or continuous replies?
456 */
457 uint32_t one_shot GNUNET_PACKED;
458
459 /**
460 * The identity of the peer to look up.
461 */
462 struct GNUNET_PeerIdentity peer;
463};
464
465
466/**
467 * Message from the library to the transport service
468 * asking for binary addresses known for a peer.
469 */
470struct PeerMonitorMessage
471{
472 /**
473 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST
474 */
475 struct GNUNET_MessageHeader header;
476
477 /**
478 * One shot call or continuous replies?
479 */
480 uint32_t one_shot GNUNET_PACKED;
481
482 /**
483 * The identity of the peer to look up.
484 */
485 struct GNUNET_PeerIdentity peer;
486};
487
488
489/**
490 * Message from the library to the transport service
491 * asking for binary addresses known for a peer.
492 */
493struct TrafficMetricMessage
494{
495 /**
496 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC
497 */
498 struct GNUNET_MessageHeader header;
499
500 /**
501 * Always zero.
502 */
503 uint32_t reserved GNUNET_PACKED;
504
505 /**
506 * The identity of the peer to look up.
507 */
508 struct GNUNET_PeerIdentity peer;
509
510 /**
511 * Fake properties to generate.
512 */
513 struct GNUNET_ATS_PropertiesNBO properties;
514
515 /**
516 * Fake delay to add on inbound traffic.
517 */
518 struct GNUNET_TIME_RelativeNBO delay_in;
519
520 /**
521 * Fake delay to add on outbound traffic.
522 */
523 struct GNUNET_TIME_RelativeNBO delay_out;
524};
525
526
527/**
528 * Message from the transport service to the library containing information
529 * about a peer. Information contained are:
530 * - current address used to communicate with this peer
531 * - state
532 * - state timeout
533 *
534 * Memory layout:
535 * [AddressIterateResponseMessage][address[addrlen]][transportname[pluginlen]]
536 */
537struct PeerIterateResponseMessage
538{
539 /**
540 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE
541 */
542 struct GNUNET_MessageHeader header;
543
544 /**
545 * For alignment.
546 */
547 uint32_t reserved;
548
549 /**
550 * Peer identity
551 */
552 struct GNUNET_PeerIdentity peer;
553
554 /**
555 * Timeout for the state this peer is in
556 */
557 struct GNUNET_TIME_AbsoluteNBO state_timeout;
558
559 /**
560 * Local info about the address
561 */
562 uint32_t local_address_info GNUNET_PACKED;
563
564 /**
565 * State this peer is in as an `enum GNUNET_TRANSPORT_PeerState`
566 */
567 uint32_t state GNUNET_PACKED;
568
569 /**
570 * Address length
571 */
572 uint32_t addrlen GNUNET_PACKED;
573
574 /**
575 * Length of the plugin name
576 */
577 uint32_t pluginlen GNUNET_PACKED;
578};
579
580
581/**
582 * Change in blacklisting (either request or notification,
583 * depending on which direction it is going).
584 */
585struct BlacklistMessage
586{
587 /**
588 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY or
589 * #GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY.
590 */
591 struct GNUNET_MessageHeader header;
592
593 /**
594 * 0 for the query, #GNUNET_OK (allowed) or #GNUNET_SYSERR (disallowed)
595 * for the response.
596 */
597 uint32_t is_allowed GNUNET_PACKED;
598
599 /**
600 * Which peer is being blacklisted or queried?
601 */
602 struct GNUNET_PeerIdentity peer;
603};
604
605
606/**
607 * Transport-level connection status update.
608 */
609struct TransportPluginMonitorMessage
610{
611 /**
612 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT.
613 */
614 struct GNUNET_MessageHeader header;
615
616 /**
617 * An `enum GNUNET_TRANSPORT_SessionState` in NBO.
618 */
619 uint16_t session_state GNUNET_PACKED;
620
621 /**
622 * #GNUNET_YES if this is an inbound connection,
623 * #GNUNET_NO if this is an outbound connection,
624 * #GNUNET_SYSERR if connections of this plugin
625 * are so fundamentally bidirectional
626 * that they have no 'initiator'
627 * Value given in NBO.
628 */
629 int16_t is_inbound GNUNET_PACKED;
630
631 /**
632 * Number of messages waiting transmission.
633 */
634 uint32_t msgs_pending GNUNET_PACKED;
635
636 /**
637 * Number of bytes waiting for transmission.
638 */
639 uint32_t bytes_pending GNUNET_PACKED;
640
641 /**
642 * When will this transport plugin session time out?
643 */
644 struct GNUNET_TIME_AbsoluteNBO timeout;
645
646 /**
647 * Until how long is this plugin currently blocked from reading?
648 */
649 struct GNUNET_TIME_AbsoluteNBO delay;
650
651 /**
652 * Which peer is this connection for?
653 */
654 struct GNUNET_PeerIdentity peer;
655
656 /**
657 * Unique identifier for the session.
658 */
659 uint64_t session_id;
660
661 /**
662 * Length of the plugin name in bytes, including 0-termination.
663 */
664 uint16_t plugin_name_len GNUNET_PACKED;
665
666 /**
667 * Length of the plugin address in bytes.
668 */
669 uint16_t plugin_address_len GNUNET_PACKED;
670
671 /* followed by 0-terminated plugin name and
672 @e plugin_address_len bytes of plugin address */
673};
674
675#else
676
677/* *********************** TNG messages ***************** */
678
679/**
680 * Communicator goes online. Note which addresses it can
681 * work with.
682 */
683struct GNUNET_TRANSPORT_CommunicatorAvailableMessage
684{
685 /**
686 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR.
687 */
688 struct GNUNET_MessageHeader header;
689
690 /**
691 * NBO encoding of `enum GNUNET_TRANSPORT_CommunicatorCharacteristics`
692 */
693 uint32_t cc;
694
695 /* Followed by the address prefix of the communicator */
696};
697
698
699/**
700 * Add address to the list.
701 */
702struct GNUNET_TRANSPORT_AddAddressMessage
703{
704 /**
705 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS.
706 */
707 struct GNUNET_MessageHeader header;
708
709 /**
710 * Address identifier (used during deletion).
711 */
712 uint32_t aid GNUNET_PACKED;
713
714 /**
715 * When does the address expire?
716 */
717 struct GNUNET_TIME_RelativeNBO expiration;
718
719 /**
720 * An `enum GNUNET_NetworkType` in NBO.
721 */
722 uint32_t nt;
723
724 /* followed by UTF-8 encoded, 0-terminated human-readable address */
725};
726
727
728/**
729 * Remove address from the list.
730 */
731struct GNUNET_TRANSPORT_DelAddressMessage
732{
733 /**
734 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS.
735 */
736 struct GNUNET_MessageHeader header;
737
738 /**
739 * Address identifier.
740 */
741 uint32_t aid GNUNET_PACKED;
742};
743
744
745/**
746 * Inform transport about an incoming message.
747 */
748struct GNUNET_TRANSPORT_IncomingMessage
749{
750 /**
751 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG.
752 */
753 struct GNUNET_MessageHeader header;
754
755 /**
756 * Do we use flow control or not?
757 */
758 uint32_t fc_on GNUNET_PACKED;
759
760 /**
761 * 64-bit number to identify the matching ACK.
762 */
763 uint64_t fc_id GNUNET_PACKED;
764
765 /**
766 * How long does the communicator believe the address on which
767 * the message was received to remain valid?
768 */
769 struct GNUNET_TIME_RelativeNBO expected_address_validity;
770
771 /**
772 * Sender identifier.
773 */
774 struct GNUNET_PeerIdentity sender;
775
776 /* followed by the message */
777};
778
779
780/**
781 * Transport informs us about being done with an incoming message.
782 * (only sent if fc_on was set).
783 */
784struct GNUNET_TRANSPORT_IncomingMessageAck
785{
786 /**
787 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK.
788 */
789 struct GNUNET_MessageHeader header;
790
791 /**
792 * Reserved (0)
793 */
794 uint32_t reserved GNUNET_PACKED;
795
796 /**
797 * Which message is being ACKed?
798 */
799 uint64_t fc_id GNUNET_PACKED;
800
801 /**
802 * Sender identifier of the original message.
803 */
804 struct GNUNET_PeerIdentity sender;
805};
806
807
808/**
809 * Add queue to the transport
810 */
811struct GNUNET_TRANSPORT_AddQueueMessage
812{
813 /**
814 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP.
815 */
816 struct GNUNET_MessageHeader header;
817
818 /**
819 * Queue identifier (used to identify the queue).
820 */
821 uint32_t qid GNUNET_PACKED;
822
823 /**
824 * Receiver that can be addressed via the queue.
825 */
826 struct GNUNET_PeerIdentity receiver;
827
828 /**
829 * An `enum GNUNET_NetworkType` in NBO.
830 */
831 uint32_t nt;
832
833 /**
834 * Maximum transmission unit, in NBO. UINT32_MAX for unlimited.
835 */
836 uint32_t mtu;
837
838 /**
839 * Queue length, in NBO. Defines how many messages may be
840 * send through this queue. UINT64_MAX for unlimited.
841 */
842 uint64_t q_len;
843
844 /**
845 * Priority of the queue in relation to other queues.
846 */
847 uint32_t priority;
848
849 /**
850 * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO.
851 */
852 uint32_t cs;
853
854 /* followed by UTF-8 encoded, 0-terminated human-readable address */
855};
856
857
858/**
859 * Update queue
860 */
861struct GNUNET_TRANSPORT_UpdateQueueMessage
862{
863 /**
864 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP.
865 */
866 struct GNUNET_MessageHeader header;
867
868 /**
869 * Queue identifier (used to identify the queue).
870 */
871 uint32_t qid GNUNET_PACKED;
872
873 /**
874 * Receiver that can be addressed via the queue.
875 */
876 struct GNUNET_PeerIdentity receiver;
877
878 /**
879 * An `enum GNUNET_NetworkType` in NBO.
880 */
881 uint32_t nt;
882
883 /**
884 * Maximum transmission unit, in NBO. UINT32_MAX for unlimited.
885 */
886 uint32_t mtu;
887
888 /**
889 * Queue length, in NBO. Defines how many messages may be
890 * send through this queue. UINT64_MAX for unlimited.
891 */
892 uint64_t q_len;
893
894 /**
895 * Priority of the queue in relation to other queues.
896 */
897 uint32_t priority;
898
899 /**
900 * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO.
901 */
902 uint32_t cs;
903};
904
905
906/**
907 * Remove queue, it is no longer available.
908 */
909struct GNUNET_TRANSPORT_DelQueueMessage
910{
911 /**
912 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN.
913 */
914 struct GNUNET_MessageHeader header;
915
916 /**
917 * Address identifier.
918 */
919 uint32_t qid GNUNET_PACKED;
920
921 /**
922 * Receiver that can be addressed via the queue.
923 */
924 struct GNUNET_PeerIdentity receiver;
925};
926
927
928/**
929 * Transport tells communicator that it wants a new queue.
930 */
931struct GNUNET_TRANSPORT_CreateQueue
932{
933 /**
934 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE.
935 */
936 struct GNUNET_MessageHeader header;
937
938 /**
939 * Unique ID for the request.
940 */
941 uint32_t request_id GNUNET_PACKED;
942
943 /**
944 * Receiver that can be addressed via the queue.
945 */
946 struct GNUNET_PeerIdentity receiver;
947
948 /* followed by UTF-8 encoded, 0-terminated human-readable address */
949};
950
951
952/**
953 * Communicator tells transport how queue creation went down.
954 */
955struct GNUNET_TRANSPORT_CreateQueueResponse
956{
957 /**
958 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK or
959 * #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL.
960 */
961 struct GNUNET_MessageHeader header;
962
963 /**
964 * Unique ID for the request.
965 */
966 uint32_t request_id GNUNET_PACKED;
967};
968
969
970/**
971 * Inform communicator about transport's desire to send a message.
972 */
973struct GNUNET_TRANSPORT_SendMessageTo
974{
975 /**
976 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG.
977 */
978 struct GNUNET_MessageHeader header;
979
980 /**
981 * Which queue should we use?
982 */
983 uint32_t qid GNUNET_PACKED;
984
985 /**
986 * Message ID, used for flow control.
987 */
988 uint64_t mid GNUNET_PACKED;
989
990 /**
991 * Receiver identifier.
992 */
993 struct GNUNET_PeerIdentity receiver;
994
995 /* followed by the message */
996};
997
998
999/**
1000 * Inform transport that message was sent.
1001 */
1002struct GNUNET_TRANSPORT_SendMessageToAck
1003{
1004 /**
1005 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK.
1006 */
1007 struct GNUNET_MessageHeader header;
1008
1009 /**
1010 * Success (#GNUNET_OK), failure (#GNUNET_SYSERR).
1011 */
1012 uint32_t status GNUNET_PACKED;
1013
1014 /**
1015 * Message ID of the original message.
1016 */
1017 uint64_t mid GNUNET_PACKED;
1018
1019 /**
1020 * Receiver identifier.
1021 */
1022 struct GNUNET_PeerIdentity receiver;
1023};
1024
1025
1026/**
1027 * Message from communicator to transport service asking for
1028 * transmission of a backchannel message with the given peer @e pid
1029 * and communicator.
1030 */
1031struct GNUNET_TRANSPORT_CommunicatorBackchannel
1032{
1033 /**
1034 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL
1035 */
1036 struct GNUNET_MessageHeader header;
1037
1038 /**
1039 * Always zero, for alignment.
1040 */
1041 uint32_t reserved;
1042
1043 /**
1044 * Target peer.
1045 */
1046 struct GNUNET_PeerIdentity pid;
1047
1048 /* Followed by a `struct GNUNET_MessageHeader` with the encapsulated
1049 message to the communicator */
1050
1051 /* Followed by the 0-terminated string specifying the desired
1052 communicator at the target (@e pid) peer */
1053};
1054
1055
1056/**
1057 * Message from transport to communicator passing along a backchannel
1058 * message from the given peer @e pid.
1059 */
1060struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming
1061{
1062 /**
1063 * Type will be
1064 * #GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING
1065 */
1066 struct GNUNET_MessageHeader header;
1067
1068 /**
1069 * Always zero, for alignment.
1070 */
1071 uint32_t reserved;
1072
1073 /**
1074 * Origin peer.
1075 */
1076 struct GNUNET_PeerIdentity pid;
1077
1078 /* Followed by a `struct GNUNET_MessageHeader` with the encapsulated
1079 message to the communicator */
1080};
1081
1082
1083/**
1084 * Request to start monitoring.
1085 */
1086struct GNUNET_TRANSPORT_MonitorStart
1087{
1088 /**
1089 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START.
1090 */
1091 struct GNUNET_MessageHeader header;
1092
1093 /**
1094 * #GNUNET_YES for one-shot montoring, #GNUNET_NO for continuous monitoring.
1095 */
1096 uint32_t one_shot;
1097
1098 /**
1099 * Target identifier to monitor, all zeros for "all peers".
1100 */
1101 struct GNUNET_PeerIdentity peer;
1102};
1103
1104
1105/**
1106 * Monitoring data.
1107 */
1108struct GNUNET_TRANSPORT_MonitorData
1109{
1110 /**
1111 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA.
1112 */
1113 struct GNUNET_MessageHeader header;
1114
1115 /**
1116 * Network type (an `enum GNUNET_NetworkType` in NBO).
1117 */
1118 uint32_t nt GNUNET_PACKED;
1119
1120 /**
1121 * Target identifier.
1122 */
1123 struct GNUNET_PeerIdentity peer;
1124
1125 /**
1126 * @deprecated To be discussed if we keep these...
1127 */
1128 struct GNUNET_TIME_AbsoluteNBO last_validation;
1129 struct GNUNET_TIME_AbsoluteNBO valid_until;
1130 struct GNUNET_TIME_AbsoluteNBO next_validation;
1131
1132 /**
1133 * Current round-trip time estimate.
1134 */
1135 struct GNUNET_TIME_RelativeNBO rtt;
1136
1137 /**
1138 * Connection status (in NBO).
1139 */
1140 uint32_t cs GNUNET_PACKED;
1141
1142 /**
1143 * Messages pending (in NBO).
1144 */
1145 uint32_t num_msg_pending GNUNET_PACKED;
1146
1147 /**
1148 * Bytes pending (in NBO).
1149 */
1150 uint32_t num_bytes_pending GNUNET_PACKED;
1151
1152 /* Followed by 0-terminated address of the peer */
1153};
1154
1155
1156/**
1157 * Request to verify address.
1158 */
1159struct GNUNET_TRANSPORT_AddressToVerify
1160{
1161 /**
1162 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY.
1163 */
1164 struct GNUNET_MessageHeader header;
1165
1166 /**
1167 * Reserved. 0.
1168 */
1169 uint32_t reserved;
1170
1171 /**
1172 * Peer the address is from.
1173 */
1174 struct GNUNET_PeerIdentity peer;
1175
1176 /* followed by variable-size raw address */
1177};
1178
1179
1180/**
1181 * Application client to TRANSPORT service: we would like to have
1182 * address suggestions for this peer.
1183 */
1184struct ExpressPreferenceMessage
1185{
1186 /**
1187 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST or
1188 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL to stop
1189 * suggestions.
1190 */
1191 struct GNUNET_MessageHeader header;
1192
1193 /**
1194 * What type of performance preference does the client have?
1195 * A `enum GNUNET_MQ_PreferenceKind` in NBO.
1196 */
1197 uint32_t pk GNUNET_PACKED;
1198
1199 /**
1200 * Peer to get address suggestions for.
1201 */
1202 struct GNUNET_PeerIdentity peer;
1203
1204 /**
1205 * How much bandwidth in bytes/second does the application expect?
1206 */
1207 struct GNUNET_BANDWIDTH_Value32NBO bw;
1208};
1209
1210
1211/**
1212 * We got an address of another peer, TRANSPORT service
1213 * should validate it. There is no response.
1214 */
1215struct RequestHelloValidationMessage
1216{
1217 /**
1218 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION.
1219 */
1220 struct GNUNET_MessageHeader header;
1221
1222 /**
1223 * What type of network does the other peer claim this is?
1224 * A `enum GNUNET_NetworkType` in NBO.
1225 */
1226 uint32_t nt GNUNET_PACKED;
1227
1228 /**
1229 * Peer to the address is presumably for.
1230 */
1231 struct GNUNET_PeerIdentity peer;
1232
1233 /* followed by 0-terminated address to validate */
1234};
1235
1236#endif
1237
1238GNUNET_NETWORK_STRUCT_END
1239
1240/* end of transport.h */
1241#endif
diff --git a/src/transport/transport_api2_application.c b/src/transport/transport_api2_application.c
deleted file mode 100644
index 00f5f62eb..000000000
--- a/src/transport/transport_api2_application.c
+++ /dev/null
@@ -1,397 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010--2019 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/transport_api2_application.c
22 * @brief enable clients to ask TRANSPORT about establishing connections to peers
23 * @author Christian Grothoff
24 * @author Matthias Wachs
25 */
26#include "platform.h"
27#include "gnunet_transport_application_service.h"
28#include "gnunet_transport_core_service.h"
29#include "transport.h"
30
31
32#define LOG(kind, ...) \
33 GNUNET_log_from (kind, "transport-application-api", __VA_ARGS__)
34
35
36/**
37 * Handle for TRANSPORT address suggestion requests.
38 */
39struct GNUNET_TRANSPORT_ApplicationSuggestHandle
40{
41 /**
42 * ID of the peer for which address suggestion was requested.
43 */
44 struct GNUNET_PeerIdentity id;
45
46 /**
47 * Connecitivity handle this suggestion handle belongs to.
48 */
49 struct GNUNET_TRANSPORT_ApplicationHandle *ch;
50
51 /**
52 * What preference is being expressed?
53 */
54 enum GNUNET_MQ_PriorityPreferences pk;
55
56 /**
57 * How much bandwidth does the client expect?
58 */
59 struct GNUNET_BANDWIDTH_Value32NBO bw;
60};
61
62
63/**
64 * Handle to the TRANSPORT subsystem for application management.
65 */
66struct GNUNET_TRANSPORT_ApplicationHandle
67{
68 /**
69 * Our configuration.
70 */
71 const struct GNUNET_CONFIGURATION_Handle *cfg;
72
73 /**
74 * Map with the identities of all the peers for which we would
75 * like to have address suggestions. The key is the PID, the
76 * value is currently the `struct GNUNET_TRANSPORT_ApplicationSuggestHandle`
77 */
78 struct GNUNET_CONTAINER_MultiPeerMap *sug_requests;
79
80 /**
81 * Message queue for sending requests to the TRANSPORT service.
82 */
83 struct GNUNET_MQ_Handle *mq;
84
85 /**
86 * Task to trigger reconnect.
87 */
88 struct GNUNET_SCHEDULER_Task *task;
89
90 /**
91 * Reconnect backoff delay.
92 */
93 struct GNUNET_TIME_Relative backoff;
94};
95
96
97/**
98 * Re-establish the connection to the TRANSPORT service.
99 *
100 * @param ch handle to use to re-connect.
101 */
102static void
103reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch);
104
105
106/**
107 * Re-establish the connection to the TRANSPORT service.
108 *
109 * @param cls handle to use to re-connect.
110 */
111static void
112reconnect_task (void *cls)
113{
114 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
115
116 ch->task = NULL;
117 reconnect (ch);
118}
119
120
121/**
122 * Disconnect from TRANSPORT and then reconnect.
123 *
124 * @param ch our handle
125 */
126static void
127force_reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
128{
129 if (NULL != ch->mq)
130 {
131 GNUNET_MQ_destroy (ch->mq);
132 ch->mq = NULL;
133 }
134 ch->backoff = GNUNET_TIME_STD_BACKOFF (ch->backoff);
135 ch->task = GNUNET_SCHEDULER_add_delayed (ch->backoff, &reconnect_task, ch);
136}
137
138
139/**
140 * We encountered an error handling the MQ to the
141 * TRANSPORT service. Reconnect.
142 *
143 * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle`
144 * @param error details about the error
145 */
146static void
147error_handler (void *cls, enum GNUNET_MQ_Error error)
148{
149 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
150
151 LOG (GNUNET_ERROR_TYPE_DEBUG,
152 "TRANSPORT connection died (code %d), reconnecting\n",
153 (int) error);
154 force_reconnect (ch);
155}
156
157
158/**
159 * Transmit request for an address suggestion.
160 *
161 * @param cls the `struct GNUNET_TRANSPORT_ApplicationHandle`
162 * @param peer peer to ask for an address suggestion for
163 * @param value the `struct GNUNET_TRANSPORT_SuggestHandle`
164 * @return #GNUNET_OK (continue to iterate), #GNUNET_SYSERR on
165 * failure (message queue no longer exists)
166 */
167static int
168transmit_suggestion (void *cls,
169 const struct GNUNET_PeerIdentity *peer,
170 void *value)
171{
172 struct GNUNET_TRANSPORT_ApplicationHandle *ch = cls;
173 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh = value;
174 struct GNUNET_MQ_Envelope *ev;
175 struct ExpressPreferenceMessage *m;
176
177 if (NULL == ch->mq)
178 return GNUNET_SYSERR;
179 ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST);
180 m->pk = htonl ((uint32_t) sh->pk);
181 m->bw = sh->bw;
182 m->peer = *peer;
183 GNUNET_MQ_send (ch->mq, ev);
184 return GNUNET_OK;
185}
186
187
188/**
189 * Re-establish the connection to the TRANSPORT service.
190 *
191 * @param ch handle to use to re-connect.
192 */
193static void
194reconnect (struct GNUNET_TRANSPORT_ApplicationHandle *ch)
195{
196 static const struct GNUNET_MQ_MessageHandler handlers[] = { { NULL, 0, 0 } };
197
198 GNUNET_assert (NULL == ch->mq);
199 ch->mq =
200 GNUNET_CLIENT_connect (ch->cfg, "transport", handlers, &error_handler, ch);
201 if (NULL == ch->mq)
202 {
203 force_reconnect (ch);
204 return;
205 }
206 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
207 &transmit_suggestion,
208 ch);
209}
210
211
212/**
213 * Initialize the TRANSPORT application suggestion client handle.
214 *
215 * @param cfg configuration to use
216 * @return transport application handle, NULL on error
217 */
218struct GNUNET_TRANSPORT_ApplicationHandle *
219GNUNET_TRANSPORT_application_init (
220 const struct GNUNET_CONFIGURATION_Handle *cfg)
221{
222 struct GNUNET_TRANSPORT_ApplicationHandle *ch;
223
224 ch = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationHandle);
225 ch->cfg = cfg;
226 ch->sug_requests = GNUNET_CONTAINER_multipeermap_create (32, GNUNET_YES);
227 reconnect (ch);
228 return ch;
229}
230
231
232/**
233 * Function called to free all `struct GNUNET_TRANSPORT_ApplicationSuggestHandle`s
234 * in the map.
235 *
236 * @param cls NULL
237 * @param key the key
238 * @param value the value to free
239 * @return #GNUNET_OK (continue to iterate)
240 */
241static int
242free_sug_handle (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
243{
244 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *cur = value;
245
246 GNUNET_free (cur);
247 return GNUNET_OK;
248}
249
250
251/**
252 * Client is done with TRANSPORT application management, release resources.
253 *
254 * @param ch handle to release
255 */
256void
257GNUNET_TRANSPORT_application_done (
258 struct GNUNET_TRANSPORT_ApplicationHandle *ch)
259{
260 if (NULL != ch->mq)
261 {
262 GNUNET_MQ_destroy (ch->mq);
263 ch->mq = NULL;
264 }
265 if (NULL != ch->task)
266 {
267 GNUNET_SCHEDULER_cancel (ch->task);
268 ch->task = NULL;
269 }
270 GNUNET_CONTAINER_multipeermap_iterate (ch->sug_requests,
271 &free_sug_handle,
272 NULL);
273 GNUNET_CONTAINER_multipeermap_destroy (ch->sug_requests);
274 GNUNET_free (ch);
275}
276
277
278/**
279 * An application would like TRANSPORT to connect to a peer.
280 *
281 * @param ch handle
282 * @param peer identity of the peer we need an address for
283 * @param pk what kind of application will the application require (can be
284 * #GNUNET_MQ_PRIO_BACKGROUND, we will still try to connect)
285 * @param bw desired bandwidth, can be zero (we will still try to connect)
286 * @return suggest handle, NULL if a request is already pending
287 */
288struct GNUNET_TRANSPORT_ApplicationSuggestHandle *
289GNUNET_TRANSPORT_application_suggest (
290 struct GNUNET_TRANSPORT_ApplicationHandle *ch,
291 const struct GNUNET_PeerIdentity *peer,
292 enum GNUNET_MQ_PriorityPreferences pk,
293 struct GNUNET_BANDWIDTH_Value32NBO bw)
294{
295 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *s;
296
297 s = GNUNET_new (struct GNUNET_TRANSPORT_ApplicationSuggestHandle);
298 s->ch = ch;
299 s->id = *peer;
300 s->pk = pk;
301 s->bw = bw;
302 (void) GNUNET_CONTAINER_multipeermap_put (
303 ch->sug_requests,
304 &s->id,
305 s,
306 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
307 LOG (GNUNET_ERROR_TYPE_DEBUG,
308 "Requesting TRANSPORT to suggest address for `%s'\n",
309 GNUNET_i2s (peer));
310 if (NULL == ch->mq)
311 return s;
312 GNUNET_assert (GNUNET_OK == transmit_suggestion (ch, &s->id, s));
313 return s;
314}
315
316
317/**
318 * We no longer care about being connected to a peer.
319 *
320 * @param sh handle to stop
321 */
322void
323GNUNET_TRANSPORT_application_suggest_cancel (
324 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *sh)
325{
326 struct GNUNET_TRANSPORT_ApplicationHandle *ch = sh->ch;
327 struct GNUNET_MQ_Envelope *ev;
328 struct ExpressPreferenceMessage *m;
329
330 LOG (GNUNET_ERROR_TYPE_DEBUG,
331 "Telling TRANSPORT we no longer care for an address for `%s'\n",
332 GNUNET_i2s (&sh->id));
333 GNUNET_assert (
334 GNUNET_OK ==
335 GNUNET_CONTAINER_multipeermap_remove (ch->sug_requests, &sh->id, sh));
336 if (NULL == ch->mq)
337 {
338 GNUNET_free (sh);
339 return;
340 }
341 ev = GNUNET_MQ_msg (m, GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL);
342 m->pk = htonl ((uint32_t) sh->pk);
343 m->bw = sh->bw;
344 m->peer = sh->id;
345 GNUNET_MQ_send (ch->mq, ev);
346 GNUNET_free (sh);
347}
348
349
350/**
351 * An application (or a communicator) has received a HELLO (or other address
352 * data of another peer) and wants TRANSPORT to validate that the address is
353 * correct. The result is NOT returned, in fact TRANSPORT may do nothing
354 * (i.e. if it has too many active validations or recently tried this one
355 * already). If the @a addr validates, TRANSPORT will persist the address
356 * with PEERSTORE.
357 *
358 * @param ch handle
359 * @param peer identity of the peer we have an address for
360 * @param nt network type of @a addr (as claimed by the other peer);
361 * used by TRANSPORT to avoid trying @a addr's that really cannot work
362 * due to network type mismatches
363 * @param addr address to validate
364 */
365void
366GNUNET_TRANSPORT_application_validate (
367 struct GNUNET_TRANSPORT_ApplicationHandle *ch,
368 const struct GNUNET_PeerIdentity *peer,
369 enum GNUNET_NetworkType nt,
370 const char *addr)
371{
372 struct GNUNET_MQ_Envelope *ev;
373 struct RequestHelloValidationMessage *m;
374 size_t alen;
375
376 if (NULL == ch->mq)
377 {
378 GNUNET_log (
379 GNUNET_ERROR_TYPE_WARNING,
380 "Address validation for %s:%s skipped as transport is not connected\n",
381 GNUNET_i2s (peer),
382 addr);
383 return;
384 }
385 alen = strlen (addr) + 1;
386 ev =
387 GNUNET_MQ_msg_extra (m,
388 alen,
389 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION);
390 m->peer = *peer;
391 m->nt = htonl ((uint32_t) nt);
392 memcpy (&m[1], addr, alen);
393 GNUNET_MQ_send (ch->mq, ev);
394}
395
396
397/* end of transport_api2_application.c */
diff --git a/src/transport/transport_api2_communication.c b/src/transport/transport_api2_communication.c
deleted file mode 100644
index 2a80db87b..000000000
--- a/src/transport/transport_api2_communication.c
+++ /dev/null
@@ -1,1165 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api2_communication.c
23 * @brief implementation of the gnunet_transport_communication_service.h API
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_transport_communication_service.h"
30#include "gnunet_ats_transport_service.h"
31#include "transport.h"
32
33
34/**
35 * How many messages do we keep at most in the queue to the
36 * transport service before we start to drop (default,
37 * can be changed via the configuration file).
38 */
39#define DEFAULT_MAX_QUEUE_LENGTH 16
40
41
42/**
43 * Information we track per packet to enable flow control.
44 */
45struct FlowControl
46{
47 /**
48 * Kept in a DLL.
49 */
50 struct FlowControl *next;
51
52 /**
53 * Kept in a DLL.
54 */
55 struct FlowControl *prev;
56
57 /**
58 * Function to call once the message was processed.
59 */
60 GNUNET_TRANSPORT_MessageCompletedCallback cb;
61
62 /**
63 * Closure for @e cb
64 */
65 void *cb_cls;
66
67 /**
68 * Which peer is this about?
69 */
70 struct GNUNET_PeerIdentity sender;
71
72 /**
73 * More-or-less unique ID for the message.
74 */
75 uint64_t id;
76};
77
78
79/**
80 * Information we track per message to tell the transport about
81 * success or failures.
82 */
83struct AckPending
84{
85 /**
86 * Kept in a DLL.
87 */
88 struct AckPending *next;
89
90 /**
91 * Kept in a DLL.
92 */
93 struct AckPending *prev;
94
95 /**
96 * Communicator this entry belongs to.
97 */
98 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
99
100 /**
101 * Which peer is this about?
102 */
103 struct GNUNET_PeerIdentity receiver;
104
105 /**
106 * More-or-less unique ID for the message.
107 */
108 uint64_t mid;
109};
110
111
112/**
113 * Opaque handle to the transport service for communicators.
114 */
115struct GNUNET_TRANSPORT_CommunicatorHandle
116{
117 /**
118 * Head of DLL of addresses this communicator offers to the transport service.
119 */
120 struct GNUNET_TRANSPORT_AddressIdentifier *ai_head;
121
122 /**
123 * Tail of DLL of addresses this communicator offers to the transport service.
124 */
125 struct GNUNET_TRANSPORT_AddressIdentifier *ai_tail;
126
127 /**
128 * DLL of messages awaiting flow control confirmation (ack).
129 */
130 struct FlowControl *fc_head;
131
132 /**
133 * DLL of messages awaiting flow control confirmation (ack).
134 */
135 struct FlowControl *fc_tail;
136
137 /**
138 * DLL of messages awaiting transmission confirmation (ack).
139 */
140 struct AckPending *ap_head;
141
142 /**
143 * DLL of messages awaiting transmission confirmation (ack).
144 */
145 struct AckPending *ap_tail;
146
147 /**
148 * DLL of queues we offer.
149 */
150 struct GNUNET_TRANSPORT_QueueHandle *queue_head;
151
152 /**
153 * DLL of queues we offer.
154 */
155 struct GNUNET_TRANSPORT_QueueHandle *queue_tail;
156
157 /**
158 * Our configuration.
159 */
160 const struct GNUNET_CONFIGURATION_Handle *cfg;
161
162 /**
163 * Config section to use.
164 */
165 const char *config_section;
166
167 /**
168 * Address prefix to use.
169 */
170 const char *addr_prefix;
171
172 /**
173 * Function to call when the transport service wants us to initiate
174 * a communication channel with another peer.
175 */
176 GNUNET_TRANSPORT_CommunicatorMqInit mq_init;
177
178 /**
179 * Closure for @e mq_init.
180 */
181 void *mq_init_cls;
182
183 /**
184 * Function to call when the transport service receives messages
185 * for a communicator (i.e. for NAT traversal or for non-bidirectional
186 * communicators).
187 */
188 GNUNET_TRANSPORT_CommunicatorNotify notify_cb;
189
190 /**
191 * Closure for @e notify_Cb.
192 */
193 void *notify_cb_cls;
194
195 /**
196 * Queue to talk to the transport service.
197 */
198 struct GNUNET_MQ_Handle *mq;
199
200 /**
201 * Maximum permissible queue length.
202 */
203 unsigned long long max_queue_length;
204
205 /**
206 * Flow-control identifier generator.
207 */
208 uint64_t fc_gen;
209
210 /**
211 * Internal UUID for the address used in communication with the
212 * transport service.
213 */
214 uint32_t aid_gen;
215
216 /**
217 * Queue identifier generator.
218 */
219 uint32_t queue_gen;
220
221 /**
222 * Characteristics of the communicator.
223 */
224 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
225};
226
227
228/**
229 * Handle returned to identify the internal data structure the transport
230 * API has created to manage a message queue to a particular peer.
231 */
232struct GNUNET_TRANSPORT_QueueHandle
233{
234 /**
235 * Kept in a DLL.
236 */
237 struct GNUNET_TRANSPORT_QueueHandle *next;
238
239 /**
240 * Kept in a DLL.
241 */
242 struct GNUNET_TRANSPORT_QueueHandle *prev;
243
244 /**
245 * Handle this queue belongs to.
246 */
247 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
248
249 /**
250 * Address used by the communication queue.
251 */
252 char *address;
253
254 /**
255 * The queue itself.
256 */
257 struct GNUNET_MQ_Handle *mq;
258
259 /**
260 * Which peer we can communciate with.
261 */
262 struct GNUNET_PeerIdentity peer;
263
264 /**
265 * Network type of the communication queue.
266 */
267 enum GNUNET_NetworkType nt;
268
269 /**
270 * Communication status of the queue.
271 */
272 enum GNUNET_TRANSPORT_ConnectionStatus cs;
273
274 /**
275 * ID for this queue when talking to the transport service.
276 */
277 uint32_t queue_id;
278
279 /**
280 * Maximum transmission unit for the queue.
281 */
282 uint32_t mtu;
283
284 /**
285 * Queue length.
286 */
287 uint64_t q_len;
288 /**
289 * Queue priority.
290 */
291 uint32_t priority;
292};
293
294
295/**
296 * Internal representation of an address a communicator is
297 * currently providing for the transport service.
298 */
299struct GNUNET_TRANSPORT_AddressIdentifier
300{
301 /**
302 * Kept in a DLL.
303 */
304 struct GNUNET_TRANSPORT_AddressIdentifier *next;
305
306 /**
307 * Kept in a DLL.
308 */
309 struct GNUNET_TRANSPORT_AddressIdentifier *prev;
310
311 /**
312 * Transport handle where the address was added.
313 */
314 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
315
316 /**
317 * The actual address.
318 */
319 char *address;
320
321 /**
322 * When does the address expire? (Expected lifetime of the
323 * address.)
324 */
325 struct GNUNET_TIME_Relative expiration;
326
327 /**
328 * Internal UUID for the address used in communication with the
329 * transport service.
330 */
331 uint32_t aid;
332
333 /**
334 * Network type for the address.
335 */
336 enum GNUNET_NetworkType nt;
337};
338
339
340/**
341 * (re)connect our communicator to the transport service
342 *
343 * @param ch handle to reconnect
344 */
345static void
346reconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch);
347
348
349/**
350 * Send message to the transport service about address @a ai
351 * being now available.
352 *
353 * @param ai address to add
354 */
355static void
356send_add_address (struct GNUNET_TRANSPORT_AddressIdentifier *ai)
357{
358 struct GNUNET_MQ_Envelope *env;
359 struct GNUNET_TRANSPORT_AddAddressMessage *aam;
360
361 if (NULL == ai->ch->mq)
362 return;
363 env = GNUNET_MQ_msg_extra (aam,
364 strlen (ai->address) + 1,
365 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS);
366 aam->expiration = GNUNET_TIME_relative_hton (ai->expiration);
367 aam->nt = htonl ((uint32_t) ai->nt);
368 memcpy (&aam[1], ai->address, strlen (ai->address) + 1);
369 GNUNET_MQ_send (ai->ch->mq, env);
370}
371
372
373/**
374 * Send message to the transport service about address @a ai
375 * being no longer available.
376 *
377 * @param ai address to delete
378 */
379static void
380send_del_address (struct GNUNET_TRANSPORT_AddressIdentifier *ai)
381{
382 struct GNUNET_MQ_Envelope *env;
383 struct GNUNET_TRANSPORT_DelAddressMessage *dam;
384
385 if (NULL == ai->ch->mq)
386 return;
387 env = GNUNET_MQ_msg (dam, GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS);
388 dam->aid = htonl (ai->aid);
389 GNUNET_MQ_send (ai->ch->mq, env);
390}
391
392
393/**
394 * Send message to the transport service about queue @a qh
395 * being now available.
396 *
397 * @param qh queue to add
398 */
399static void
400send_add_queue (struct GNUNET_TRANSPORT_QueueHandle *qh)
401{
402 struct GNUNET_MQ_Envelope *env;
403 struct GNUNET_TRANSPORT_AddQueueMessage *aqm;
404
405 if (NULL == qh->ch->mq)
406 return;
407 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
408 "Sending `GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP` message\n");
409 env = GNUNET_MQ_msg_extra (aqm,
410 strlen (qh->address) + 1,
411 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP);
412 aqm->qid = htonl (qh->queue_id);
413 aqm->receiver = qh->peer;
414 aqm->nt = htonl ((uint32_t) qh->nt);
415 aqm->mtu = htonl (qh->mtu);
416 aqm->q_len = GNUNET_htonll (qh->q_len);
417 aqm->priority = htonl (qh->priority);
418 aqm->cs = htonl ((uint32_t) qh->cs);
419 memcpy (&aqm[1], qh->address, strlen (qh->address) + 1);
420 GNUNET_MQ_send (qh->ch->mq, env);
421}
422
423
424/**
425 * Send message to the transport service about queue @a qh
426 * updated.
427 *
428 * @param qh queue to add
429 */
430static void
431send_update_queue (struct GNUNET_TRANSPORT_QueueHandle *qh)
432{
433 struct GNUNET_MQ_Envelope *env;
434 struct GNUNET_TRANSPORT_UpdateQueueMessage *uqm;
435
436 if (NULL == qh->ch->mq)
437 return;
438 env = GNUNET_MQ_msg (uqm, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE);
439 uqm->qid = htonl (qh->queue_id);
440 uqm->receiver = qh->peer;
441 uqm->nt = htonl ((uint32_t) qh->nt);
442 uqm->mtu = htonl (qh->mtu);
443 uqm->q_len = GNUNET_htonll (qh->q_len);
444 uqm->priority = htonl (qh->priority);
445 uqm->cs = htonl ((uint32_t) qh->cs);
446 GNUNET_MQ_send (qh->ch->mq, env);
447}
448
449
450/**
451 * Send message to the transport service about queue @a qh
452 * being no longer available.
453 *
454 * @param qh queue to delete
455 */
456static void
457send_del_queue (struct GNUNET_TRANSPORT_QueueHandle *qh)
458{
459 struct GNUNET_MQ_Envelope *env;
460 struct GNUNET_TRANSPORT_DelQueueMessage *dqm;
461
462 if (NULL == qh->ch->mq)
463 return;
464 env = GNUNET_MQ_msg (dqm, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN);
465 dqm->qid = htonl (qh->queue_id);
466 dqm->receiver = qh->peer;
467 GNUNET_MQ_send (qh->ch->mq, env);
468}
469
470
471/**
472 * Disconnect from the transport service. Purges
473 * all flow control entries as we will no longer receive
474 * the ACKs. Purges the ack pending entries as the
475 * transport will no longer expect the confirmations.
476 *
477 * @param ch service to disconnect from
478 */
479static void
480disconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
481{
482 struct FlowControl *fcn;
483 struct AckPending *apn;
484
485 for (struct FlowControl *fc = ch->fc_head; NULL != fc; fc = fcn)
486 {
487 fcn = fc->next;
488 GNUNET_CONTAINER_DLL_remove (ch->fc_head, ch->fc_tail, fc);
489 fc->cb (fc->cb_cls, GNUNET_SYSERR);
490 GNUNET_free (fc);
491 }
492 for (struct AckPending *ap = ch->ap_head; NULL != ap; ap = apn)
493 {
494 apn = ap->next;
495 GNUNET_CONTAINER_DLL_remove (ch->ap_head, ch->ap_tail, ap);
496 GNUNET_free (ap);
497 }
498 if (NULL == ch->mq)
499 return;
500 GNUNET_MQ_destroy (ch->mq);
501 ch->mq = NULL;
502}
503
504
505/**
506 * Function called on MQ errors.
507 */
508static void
509error_handler (void *cls, enum GNUNET_MQ_Error error)
510{
511 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
512
513 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
514 "MQ failure %d, reconnecting to transport service.\n",
515 error);
516 disconnect (ch);
517 /* TODO: maybe do this with exponential backoff/delay */
518 reconnect (ch);
519}
520
521
522/**
523 * Transport service acknowledged a message we gave it
524 * (with flow control enabled). Tell the communicator.
525 *
526 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
527 * @param incoming_ack the ack
528 */
529static void
530handle_incoming_ack (
531 void *cls,
532 const struct GNUNET_TRANSPORT_IncomingMessageAck *incoming_ack)
533{
534 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
535
536 for (struct FlowControl *fc = ch->fc_head; NULL != fc; fc = fc->next)
537 {
538 if ((fc->id == incoming_ack->fc_id) &&
539 (0 == memcmp (&fc->sender,
540 &incoming_ack->sender,
541 sizeof(struct GNUNET_PeerIdentity))))
542 {
543 GNUNET_CONTAINER_DLL_remove (ch->fc_head, ch->fc_tail, fc);
544 fc->cb (fc->cb_cls, GNUNET_OK);
545 GNUNET_free (fc);
546 return;
547 }
548 }
549 GNUNET_break (0);
550 disconnect (ch);
551 /* TODO: maybe do this with exponential backoff/delay */
552 reconnect (ch);
553}
554
555
556/**
557 * Transport service wants us to create a queue. Check if @a cq
558 * is well-formed.
559 *
560 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
561 * @param cq the queue creation request
562 * @return #GNUNET_OK if @a smt is well-formed
563 */
564static int
565check_create_queue (void *cls, const struct GNUNET_TRANSPORT_CreateQueue *cq)
566{
567 (void) cls;
568 GNUNET_MQ_check_zero_termination (cq);
569 return GNUNET_OK;
570}
571
572
573/**
574 * Transport service wants us to create a queue. Tell the communicator.
575 *
576 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
577 * @param cq the queue creation request
578 */
579static void
580handle_create_queue (void *cls, const struct GNUNET_TRANSPORT_CreateQueue *cq)
581{
582 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
583 const char *addr = (const char *) &cq[1];
584 struct GNUNET_TRANSPORT_CreateQueueResponse *cqr;
585 struct GNUNET_MQ_Envelope *env;
586
587 if (GNUNET_OK != ch->mq_init (ch->mq_init_cls, &cq->receiver, addr))
588 {
589 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
590 "Address `%s' invalid for this communicator\n",
591 addr);
592 env = GNUNET_MQ_msg (cqr, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL);
593 }
594 else
595 {
596 env = GNUNET_MQ_msg (cqr, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK);
597 }
598 cqr->request_id = cq->request_id;
599 GNUNET_MQ_send (ch->mq, env);
600}
601
602
603/**
604 * Transport service wants us to send a message. Check if @a smt
605 * is well-formed.
606 *
607 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
608 * @param smt the transmission request
609 * @return #GNUNET_OK if @a smt is well-formed
610 */
611static int
612check_send_msg (void *cls, const struct GNUNET_TRANSPORT_SendMessageTo *smt)
613{
614 (void) cls;
615 GNUNET_MQ_check_boxed_message (smt);
616 return GNUNET_OK;
617}
618
619
620/**
621 * Notify transport service about @a status of a message with
622 * @a mid sent to @a receiver.
623 *
624 * @param ch handle
625 * @param status #GNUNET_OK on success, #GNUNET_SYSERR on failure
626 * @param receiver which peer was the receiver
627 * @param mid message that the ack is about
628 */
629static void
630send_ack (struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
631 int status,
632 const struct GNUNET_PeerIdentity *receiver,
633 uint64_t mid)
634{
635 struct GNUNET_MQ_Envelope *env;
636 struct GNUNET_TRANSPORT_SendMessageToAck *ack;
637
638 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK);
639 ack->status = htonl (status);
640 ack->mid = mid;
641 ack->receiver = *receiver;
642 GNUNET_MQ_send (ch->mq, env);
643}
644
645
646/**
647 * Message queue transmission by communicator was successful,
648 * notify transport service.
649 *
650 * @param cls an `struct AckPending *`
651 */
652static void
653send_ack_cb (void *cls)
654{
655 struct AckPending *ap = cls;
656 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = ap->ch;
657
658 GNUNET_CONTAINER_DLL_remove (ch->ap_head, ch->ap_tail, ap);
659 send_ack (ch, GNUNET_OK, &ap->receiver, ap->mid);
660 GNUNET_free (ap);
661}
662
663
664/**
665 * Transport service wants us to send a message. Tell the communicator.
666 *
667 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
668 * @param smt the transmission request
669 */
670static void
671handle_send_msg (void *cls, const struct GNUNET_TRANSPORT_SendMessageTo *smt)
672{
673 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
674 const struct GNUNET_MessageHeader *mh;
675 struct GNUNET_MQ_Envelope *env;
676 struct AckPending *ap;
677 struct GNUNET_TRANSPORT_QueueHandle *qh;
678
679 for (qh = ch->queue_head; NULL != qh; qh = qh->next)
680 if ((qh->queue_id == ntohl (smt->qid)) &&
681 (0 == memcmp (&qh->peer,
682 &smt->receiver,
683 sizeof(struct GNUNET_PeerIdentity))))
684 break;
685 if (NULL == qh)
686 {
687 /* queue is already gone, tell transport this one failed */
688 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
689 "Transmission failed, queue no longer exists.\n");
690 send_ack (ch, GNUNET_NO, &smt->receiver, smt->mid);
691 return;
692 }
693 ap = GNUNET_new (struct AckPending);
694 ap->ch = ch;
695 ap->receiver = smt->receiver;
696 ap->mid = smt->mid;
697 GNUNET_CONTAINER_DLL_insert (ch->ap_head, ch->ap_tail, ap);
698 mh = (const struct GNUNET_MessageHeader *) &smt[1];
699 env = GNUNET_MQ_msg_copy (mh);
700 GNUNET_MQ_notify_sent (env, &send_ack_cb, ap);
701 GNUNET_MQ_send (qh->mq, env);
702}
703
704
705/**
706 * Transport service gives us backchannel message. Check if @a bi
707 * is well-formed.
708 *
709 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
710 * @param bi the backchannel message
711 * @return #GNUNET_OK if @a smt is well-formed
712 */
713static int
714check_backchannel_incoming (
715 void *cls,
716 const struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *bi)
717{
718 (void) cls;
719 GNUNET_MQ_check_boxed_message (bi);
720 return GNUNET_OK;
721}
722
723
724/**
725 * Transport service gives us backchannel message. Handle it.
726 *
727 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
728 * @param bi the backchannel message
729 */
730static void
731handle_backchannel_incoming (
732 void *cls,
733 const struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *bi)
734{
735 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
736 if (NULL != ch->notify_cb)
737 ch->notify_cb (ch->notify_cb_cls,
738 &bi->pid,
739 (const struct GNUNET_MessageHeader *) &bi[1]);
740 else
741 GNUNET_log (
742 GNUNET_ERROR_TYPE_INFO,
743 _ ("Dropped backchanel message: handler not provided by communicator\n"));
744}
745
746
747/**
748 * (re)connect our communicator to the transport service
749 *
750 * @param ch handle to reconnect
751 */
752static void
753reconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
754{
755 struct GNUNET_MQ_MessageHandler handlers[] =
756 { GNUNET_MQ_hd_fixed_size (incoming_ack,
757 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK,
758 struct GNUNET_TRANSPORT_IncomingMessageAck,
759 ch),
760 GNUNET_MQ_hd_var_size (create_queue,
761 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE,
762 struct GNUNET_TRANSPORT_CreateQueue,
763 ch),
764 GNUNET_MQ_hd_var_size (send_msg,
765 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG,
766 struct GNUNET_TRANSPORT_SendMessageTo,
767 ch),
768 GNUNET_MQ_hd_var_size (
769 backchannel_incoming,
770 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING,
771 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming,
772 ch),
773 GNUNET_MQ_handler_end () };
774 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam;
775 struct GNUNET_MQ_Envelope *env;
776
777 ch->mq =
778 GNUNET_CLIENT_connect (ch->cfg, "transport", handlers, &error_handler, ch);
779 if (NULL == ch->mq)
780 return;
781 env = GNUNET_MQ_msg_extra (cam,
782 strlen (ch->addr_prefix) + 1,
783 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR);
784 cam->cc = htonl ((uint32_t) ch->cc);
785 memcpy (&cam[1], ch->addr_prefix, strlen (ch->addr_prefix) + 1);
786 GNUNET_MQ_send (ch->mq, env);
787 for (struct GNUNET_TRANSPORT_AddressIdentifier *ai = ch->ai_head; NULL != ai;
788 ai = ai->next)
789 send_add_address (ai);
790 for (struct GNUNET_TRANSPORT_QueueHandle *qh = ch->queue_head; NULL != qh;
791 qh = qh->next)
792 send_add_queue (qh);
793}
794
795
796/**
797 * Connect to the transport service.
798 *
799 * @param cfg configuration to use
800 * @param config_section section of the configuration to use for options
801 * @param addr_prefix address prefix for addresses supported by this
802 * communicator, could be NULL for incoming-only communicators
803 * @param cc what characteristics does the communicator have?
804 * @param mtu maximum message size supported by communicator, 0 if
805 * sending is not supported, SIZE_MAX for no MTU
806 * @param mq_init function to call to initialize a message queue given
807 * the address of another peer, can be NULL if the
808 * communicator only supports receiving messages
809 * @param mq_init_cls closure for @a mq_init
810 * @param notify_cb function to pass backchannel messages to communicator
811 * @param notify_cb_cls closure for @a notify_cb
812 * @return NULL on error
813 */
814struct GNUNET_TRANSPORT_CommunicatorHandle *
815GNUNET_TRANSPORT_communicator_connect (
816 const struct GNUNET_CONFIGURATION_Handle *cfg,
817 const char *config_section,
818 const char *addr_prefix,
819 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc,
820 GNUNET_TRANSPORT_CommunicatorMqInit mq_init,
821 void *mq_init_cls,
822 GNUNET_TRANSPORT_CommunicatorNotify notify_cb,
823 void *notify_cb_cls)
824{
825 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
826
827 ch = GNUNET_new (struct GNUNET_TRANSPORT_CommunicatorHandle);
828 ch->cfg = cfg;
829 ch->config_section = config_section;
830 ch->addr_prefix = addr_prefix;
831 ch->mq_init = mq_init;
832 ch->mq_init_cls = mq_init_cls;
833 ch->notify_cb = notify_cb;
834 ch->notify_cb_cls = notify_cb_cls;
835 ch->cc = cc;
836 reconnect (ch);
837 if (GNUNET_OK !=
838 GNUNET_CONFIGURATION_get_value_number (cfg,
839 config_section,
840 "MAX_QUEUE_LENGTH",
841 &ch->max_queue_length))
842 ch->max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
843 if (NULL == ch->mq)
844 {
845 GNUNET_free (ch);
846 return NULL;
847 }
848 return ch;
849}
850
851
852/**
853 * Disconnect from the transport service.
854 *
855 * @param ch handle returned from connect
856 */
857void
858GNUNET_TRANSPORT_communicator_disconnect (
859 struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
860{
861 disconnect (ch);
862 while (NULL != ch->ai_head)
863 {
864 GNUNET_break (0); /* communicator forgot to remove address, warn! */
865 GNUNET_TRANSPORT_communicator_address_remove (ch->ai_head);
866 }
867 GNUNET_free (ch);
868}
869
870
871/* ************************* Receiving *************************** */
872
873
874/**
875 * Notify transport service that the communicator has received
876 * a message.
877 *
878 * @param ch connection to transport service
879 * @param sender presumed sender of the message (details to be checked
880 * by higher layers)
881 * @param msg the message
882 * @param expected_addr_validity how long does the communicator believe it
883 * will continue to be able to receive messages from the same address
884 * on which it received this message?
885 * @param cb function to call once handling the message is done, NULL if
886 * flow control is not supported by this communicator
887 * @param cb_cls closure for @a cb
888 * @return #GNUNET_OK if all is well, #GNUNET_NO if the message was
889 * immediately dropped due to memory limitations (communicator
890 * should try to apply back pressure),
891 * #GNUNET_SYSERR if the message could not be delivered because
892 * the transport service is not yet up
893 */
894int
895GNUNET_TRANSPORT_communicator_receive (
896 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
897 const struct GNUNET_PeerIdentity *sender,
898 const struct GNUNET_MessageHeader *msg,
899 struct GNUNET_TIME_Relative expected_addr_validity,
900 GNUNET_TRANSPORT_MessageCompletedCallback cb,
901 void *cb_cls)
902{
903 struct GNUNET_MQ_Envelope *env;
904 struct GNUNET_TRANSPORT_IncomingMessage *im;
905 uint16_t msize;
906
907
908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
909 "communicator receive\n");
910
911 if (NULL == ch->mq)
912 return GNUNET_SYSERR;
913 if ((NULL == cb) && (GNUNET_MQ_get_length (ch->mq) >= ch->max_queue_length))
914 {
915 GNUNET_log (
916 GNUNET_ERROR_TYPE_WARNING,
917 "Dropping message: transport is too slow, queue length %llu exceeded\n",
918 ch->max_queue_length);
919 return GNUNET_NO;
920 }
921
922 msize = ntohs (msg->size);
923 env =
924 GNUNET_MQ_msg_extra (im, msize, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG);
925 if (NULL == env)
926 {
927 GNUNET_break (0);
928 return GNUNET_SYSERR;
929 }
930 im->expected_address_validity =
931 GNUNET_TIME_relative_hton (expected_addr_validity);
932 im->sender = *sender;
933 // FIXME: this is expensive, would be better if we would
934 // re-design the API to allow us to create the envelope first,
935 // and then have the application fill in the body so we do
936 // not have to memcpy()
937 memcpy (&im[1], msg, msize);
938 im->fc_on = htonl (GNUNET_NO);
939 if (NULL != cb)
940 {
941 struct FlowControl *fc;
942
943 im->fc_on = htonl (GNUNET_YES);
944 im->fc_id = ch->fc_gen++;
945 fc = GNUNET_new (struct FlowControl);
946 fc->sender = *sender;
947 fc->id = im->fc_id;
948 fc->cb = cb;
949 fc->cb_cls = cb_cls;
950 GNUNET_CONTAINER_DLL_insert (ch->fc_head, ch->fc_tail, fc);
951 }
952 GNUNET_MQ_send (ch->mq, env);
953 return GNUNET_OK;
954}
955
956
957/* ************************* Discovery *************************** */
958
959
960/**
961 * Notify transport service that an MQ became available due to an
962 * "inbound" connection or because the communicator discovered the
963 * presence of another peer.
964 *
965 * @param ch connection to transport service
966 * @param peer peer with which we can now communicate
967 * @param address address in human-readable format, 0-terminated, UTF-8
968 * @param mtu maximum message size supported by queue, 0 if
969 * sending is not supported, SIZE_MAX for no MTU
970 * @param q_len number of messages that can be send through this queue
971 * @param priority queue priority. Queues with highest priority should be
972 * used
973 * @param nt which network type does the @a address belong to?
974 * @param cc what characteristics does the communicator have?
975 * @param cs what is the connection status of the queue?
976 * @param mq message queue of the @a peer
977 * @return API handle identifying the new MQ
978 */
979struct GNUNET_TRANSPORT_QueueHandle *
980GNUNET_TRANSPORT_communicator_mq_add (
981 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
982 const struct GNUNET_PeerIdentity *peer,
983 const char *address,
984 uint32_t mtu,
985 uint64_t q_len,
986 uint32_t priority,
987 enum GNUNET_NetworkType nt,
988 enum GNUNET_TRANSPORT_ConnectionStatus cs,
989 struct GNUNET_MQ_Handle *mq)
990{
991 struct GNUNET_TRANSPORT_QueueHandle *qh;
992
993 // Do not notify the service if there is no intial capacity.
994 GNUNET_assert (0 < q_len);
995
996 qh = GNUNET_new (struct GNUNET_TRANSPORT_QueueHandle);
997 qh->ch = ch;
998 qh->peer = *peer;
999 qh->address = GNUNET_strdup (address);
1000 qh->nt = nt;
1001 qh->mtu = mtu;
1002 qh->q_len = q_len;
1003 qh->priority = priority;
1004 qh->cs = cs;
1005 qh->mq = mq;
1006 qh->queue_id = ch->queue_gen++;
1007 GNUNET_CONTAINER_DLL_insert (ch->queue_head, ch->queue_tail, qh);
1008 send_add_queue (qh);
1009 return qh;
1010}
1011
1012
1013/**
1014 * Notify transport service that an MQ was updated
1015 *
1016 * @param ch connection to transport service
1017 * @param qh the queue to update
1018 * @param q_len number of messages that can be send through this queue
1019 * @param priority queue priority. Queues with highest priority should be
1020 * used
1021 */
1022void
1023GNUNET_TRANSPORT_communicator_mq_update (
1024 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1025 const struct GNUNET_TRANSPORT_QueueHandle *u_qh,
1026 uint64_t q_len,
1027 uint32_t priority)
1028{
1029 struct GNUNET_TRANSPORT_QueueHandle *qh;
1030
1031 for (qh = ch->queue_head; NULL != qh; qh = qh->next)
1032 {
1033 if (u_qh == qh)
1034 break;
1035 }
1036 GNUNET_assert (NULL != qh);
1037 qh->q_len = q_len;
1038 qh->priority = priority;
1039 send_update_queue (qh);
1040}
1041
1042
1043/**
1044 * Notify transport service that an MQ became unavailable due to a
1045 * disconnect or timeout.
1046 *
1047 * @param qh handle for the queue that must be invalidated
1048 */
1049void
1050GNUNET_TRANSPORT_communicator_mq_del (struct GNUNET_TRANSPORT_QueueHandle *qh)
1051{
1052 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = qh->ch;
1053
1054 send_del_queue (qh);
1055 GNUNET_CONTAINER_DLL_remove (ch->queue_head, ch->queue_tail, qh);
1056 GNUNET_MQ_destroy (qh->mq);
1057 GNUNET_free (qh->address);
1058 GNUNET_free (qh);
1059}
1060
1061
1062/**
1063 * Notify transport service about an address that this communicator
1064 * provides for this peer.
1065 *
1066 * @param ch connection to transport service
1067 * @param address our address in human-readable format, 0-terminated, UTF-8
1068 * @param nt which network type does the address belong to?
1069 * @param expiration when does the communicator forsee this address expiring?
1070 */
1071struct GNUNET_TRANSPORT_AddressIdentifier *
1072GNUNET_TRANSPORT_communicator_address_add (
1073 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1074 const char *address,
1075 enum GNUNET_NetworkType nt,
1076 struct GNUNET_TIME_Relative expiration)
1077{
1078 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
1079
1080 ai = GNUNET_new (struct GNUNET_TRANSPORT_AddressIdentifier);
1081 ai->ch = ch;
1082 ai->address = GNUNET_strdup (address);
1083 ai->nt = nt;
1084 ai->expiration = expiration;
1085 ai->aid = ch->aid_gen++;
1086 GNUNET_CONTAINER_DLL_insert (ch->ai_head, ch->ai_tail, ai);
1087 send_add_address (ai);
1088 return ai;
1089}
1090
1091/**
1092 * Notify transport service about an address that this communicator no
1093 * longer provides for this peer.
1094 *
1095 * @param ai address that is no longer provided
1096 */
1097void
1098GNUNET_TRANSPORT_communicator_address_remove (
1099 struct GNUNET_TRANSPORT_AddressIdentifier *ai)
1100{
1101 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = ai->ch;
1102
1103 send_del_address (ai);
1104 GNUNET_CONTAINER_DLL_remove (ch->ai_head, ch->ai_tail, ai);
1105 GNUNET_free (ai->address);
1106 GNUNET_free (ai);
1107}
1108
1109/**
1110 * Notify transport service that this communicator no longer provides all its addresses for this peer.
1111 *
1112 * @param ch The communicator handle.
1113 */
1114void
1115GNUNET_TRANSPORT_communicator_address_remove_all (
1116 struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
1117{
1118 for (struct GNUNET_TRANSPORT_AddressIdentifier *ai = ch->ai_head; NULL != ai;
1119 ai = ai->next)
1120 GNUNET_TRANSPORT_communicator_address_remove (ai);
1121}
1122
1123
1124/* ************************* Backchannel *************************** */
1125
1126
1127/**
1128 * The communicator asks the transport service to route a message via
1129 * a different path to another communicator service at another peer.
1130 * This must only be done for special control traffic (as there is no
1131 * flow control for this API), such as acknowledgements, and generally
1132 * only be done if the communicator is uni-directional (i.e. cannot
1133 * send the message back itself).
1134 *
1135 * @param ch handle of this communicator
1136 * @param pid peer to send the message to
1137 * @param comm name of the communicator to send the message to
1138 * @param header header of the message to transmit and pass via the
1139 * notify-API to @a pid's communicator @a comm
1140 */
1141void
1142GNUNET_TRANSPORT_communicator_notify (
1143 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1144 const struct GNUNET_PeerIdentity *pid,
1145 const char *comm,
1146 const struct GNUNET_MessageHeader *header)
1147{
1148 struct GNUNET_MQ_Envelope *env;
1149 struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb;
1150 size_t slen = strlen (comm) + 1;
1151 uint16_t mlen = ntohs (header->size);
1152
1153 GNUNET_assert (mlen + slen + sizeof(*cb) < UINT16_MAX);
1154 env =
1155 GNUNET_MQ_msg_extra (cb,
1156 slen + mlen,
1157 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL);
1158 cb->pid = *pid;
1159 memcpy (&cb[1], header, mlen);
1160 memcpy (((char *) &cb[1]) + mlen, comm, slen);
1161 GNUNET_MQ_send (ch->mq, env);
1162}
1163
1164
1165/* end of transport_api2_communication.c */
diff --git a/src/transport/transport_api2_core.c b/src/transport/transport_api2_core.c
deleted file mode 100644
index 8cd0b7c8c..000000000
--- a/src/transport/transport_api2_core.c
+++ /dev/null
@@ -1,804 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016, 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_core.c
23 * @brief library to access the transport service for message exchange
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_protocols.h"
32#include "gnunet_transport_core_service.h"
33#include "transport.h"
34
35#define LOG(kind, ...) GNUNET_log_from (kind, "transport-api-core", __VA_ARGS__)
36
37/**
38 * How large to start with for the hashmap of neighbours.
39 */
40#define STARTING_NEIGHBOURS_SIZE 16
41
42/**
43 * Window size. How many messages to the same target do we pass
44 * to TRANSPORT without a SEND_OK in between? Small values limit
45 * thoughput, large values will increase latency.
46 *
47 * FIXME-OPTIMIZE: find out what good values are experimentally,
48 * maybe set adaptively (i.e. to observed available bandwidth).
49 */
50#define SEND_WINDOW_SIZE 4
51
52
53/**
54 * Entry in hash table of all of our current (connected) neighbours.
55 */
56struct Neighbour
57{
58 /**
59 * Identity of this neighbour.
60 */
61 struct GNUNET_PeerIdentity id;
62
63 /**
64 * Overall transport handle.
65 */
66 struct GNUNET_TRANSPORT_CoreHandle *h;
67
68 /**
69 * Active message queue for the peer.
70 */
71 struct GNUNET_MQ_Handle *mq;
72
73 /**
74 * Envelope with the message we are currently transmitting (or NULL).
75 */
76 struct GNUNET_MQ_Envelope *env;
77
78 /**
79 * Closure for @e mq handlers.
80 */
81 void *handlers_cls;
82
83 /**
84 * How many messages can we still send to this peer before we should
85 * throttle?
86 */
87 unsigned int ready_window;
88
89 /**
90 * Used to indicate our status if @e env is non-NULL. Set to
91 * #GNUNET_YES if we did pass a message to the MQ and are waiting
92 * for the call to #notify_send_done(). Set to #GNUNET_NO if the @e
93 * ready_window is 0 and @e env is waiting for a
94 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK?
95 */
96 int16_t awaiting_done;
97
98 /**
99 * Size of the message in @e env.
100 */
101 uint16_t env_size;
102};
103
104
105/**
106 * Handle for the transport service (includes all of the
107 * state for the transport service).
108 */
109struct GNUNET_TRANSPORT_CoreHandle
110{
111 /**
112 * Closure for the callbacks.
113 */
114 void *cls;
115
116 /**
117 * Functions to call for received data (template for
118 * new message queues).
119 */
120 struct GNUNET_MQ_MessageHandler *handlers;
121
122 /**
123 * function to call on connect events
124 */
125 GNUNET_TRANSPORT_NotifyConnect nc_cb;
126
127 /**
128 * function to call on disconnect events
129 */
130 GNUNET_TRANSPORT_NotifyDisconnect nd_cb;
131
132 /**
133 * My client connection to the transport service.
134 */
135 struct GNUNET_MQ_Handle *mq;
136
137 /**
138 * My configuration.
139 */
140 const struct GNUNET_CONFIGURATION_Handle *cfg;
141
142 /**
143 * Hash map of the current connected neighbours of this peer.
144 * Maps peer identities to `struct Neighbour` entries.
145 */
146 struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
147
148 /**
149 * Peer identity as assumed by this process, or all zeros.
150 */
151 struct GNUNET_PeerIdentity self;
152
153 /**
154 * ID of the task trying to reconnect to the service.
155 */
156 struct GNUNET_SCHEDULER_Task *reconnect_task;
157
158 /**
159 * Delay until we try to reconnect.
160 */
161 struct GNUNET_TIME_Relative reconnect_delay;
162
163 /**
164 * Should we check that @e self matches what the service thinks?
165 * (if #GNUNET_NO, then @e self is all zeros!).
166 */
167 int check_self;
168};
169
170
171/**
172 * Function that will schedule the job that will try
173 * to connect us again to the client.
174 *
175 * @param h transport service to reconnect
176 */
177static void
178disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h);
179
180
181/**
182 * Get the neighbour list entry for the given peer
183 *
184 * @param h our context
185 * @param peer peer to look up
186 * @return NULL if no such peer entry exists
187 */
188static struct Neighbour *
189neighbour_find (struct GNUNET_TRANSPORT_CoreHandle *h,
190 const struct GNUNET_PeerIdentity *peer)
191{
192 return GNUNET_CONTAINER_multipeermap_get (h->neighbours, peer);
193}
194
195
196/**
197 * Iterator over hash map entries, for deleting state of a neighbour.
198 *
199 * @param cls the `struct GNUNET_TRANSPORT_CoreHandle *`
200 * @param key peer identity
201 * @param value value in the hash map, the neighbour entry to delete
202 * @return #GNUNET_YES if we should continue to
203 * iterate,
204 * #GNUNET_NO if not.
205 */
206static int
207neighbour_delete (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
208{
209 struct GNUNET_TRANSPORT_CoreHandle *handle = cls;
210 struct Neighbour *n = value;
211
212 LOG (GNUNET_ERROR_TYPE_DEBUG,
213 "Dropping entry for neighbour `%s'.\n",
214 GNUNET_i2s (key));
215 if (NULL != handle->nd_cb)
216 handle->nd_cb (handle->cls, &n->id, n->handlers_cls);
217 if (NULL != n->env)
218 {
219 GNUNET_MQ_send_cancel (n->env);
220 n->env = NULL;
221 }
222 GNUNET_MQ_destroy (n->mq);
223 GNUNET_assert (NULL == n->mq);
224 GNUNET_assert (
225 GNUNET_YES ==
226 GNUNET_CONTAINER_multipeermap_remove (handle->neighbours, key, n));
227 GNUNET_free (n);
228 return GNUNET_YES;
229}
230
231
232/**
233 * Generic error handler, called with the appropriate
234 * error code and the same closure specified at the creation of
235 * the message queue.
236 * Not every message queue implementation supports an error handler.
237 *
238 * @param cls closure with the `struct GNUNET_TRANSPORT_CoreHandle *`
239 * @param error error code
240 */
241static void
242mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
243{
244 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
245
246 LOG (GNUNET_ERROR_TYPE_DEBUG,
247 "Error %u received from transport service, disconnecting temporarily.\n",
248 error);
249 disconnect_and_schedule_reconnect (h);
250}
251
252
253/**
254 * A message from the handler's message queue to a neighbour was
255 * transmitted. Now trigger (possibly delayed) notification of the
256 * neighbour's message queue that we are done and thus ready for
257 * the next message. Note that the MQ being ready is independent
258 * of the send window, as we may queue many messages and simply
259 * not pass them to TRANSPORT if the send window is insufficient.
260 *
261 * @param cls the `struct Neighbour` where the message was sent
262 */
263static void
264notify_send_done (void *cls)
265{
266 struct Neighbour *n = cls;
267
268 n->awaiting_done = GNUNET_NO;
269 n->env = NULL;
270 GNUNET_MQ_impl_send_continue (n->mq);
271}
272
273
274/**
275 * We have an envelope waiting for transmission at @a n, and
276 * our transmission window is positive. Perform the transmission.
277 *
278 * @param n neighbour to perform transmission for
279 */
280static void
281do_send (struct Neighbour *n)
282{
283 GNUNET_assert (0 < n->ready_window);
284 GNUNET_assert (NULL != n->env);
285 n->ready_window--;
286 n->awaiting_done = GNUNET_YES;
287 GNUNET_MQ_notify_sent (n->env, &notify_send_done, n);
288 GNUNET_MQ_send (n->h->mq, n->env);
289 LOG (GNUNET_ERROR_TYPE_DEBUG,
290 "Passed message of type %u for neighbour `%s' to TRANSPORT.\n",
291 ntohs (GNUNET_MQ_env_get_msg (n->env)->type),
292 GNUNET_i2s (&n->id));
293}
294
295
296/**
297 * Implement sending functionality of a message queue.
298 * Called one message at a time. Should send the @a msg
299 * to the transport service and then notify the queue
300 * once we are ready for the next one.
301 *
302 * @param mq the message queue
303 * @param msg the message to send
304 * @param impl_state state of the implementation
305 */
306static void
307mq_send_impl (struct GNUNET_MQ_Handle *mq,
308 const struct GNUNET_MessageHeader *msg,
309 void *impl_state)
310{
311 struct Neighbour *n = impl_state;
312 struct OutboundMessage *obm;
313 uint16_t msize;
314
315 msize = ntohs (msg->size);
316 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(*obm))
317 {
318 GNUNET_break (0);
319 GNUNET_MQ_impl_send_continue (mq);
320 return;
321 }
322 LOG (GNUNET_ERROR_TYPE_DEBUG,
323 "CORE requested transmission of message of type %u to neighbour `%s'.\n",
324 ntohs (msg->type),
325 GNUNET_i2s (&n->id));
326
327 GNUNET_assert (NULL == n->env);
328 n->env =
329 GNUNET_MQ_msg_nested_mh (obm, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, msg);
330 n->env_size = ntohs (msg->size);
331 {
332 struct GNUNET_MQ_Envelope *env;
333
334 env = GNUNET_MQ_get_current_envelope (mq);
335 obm->priority = htonl ((uint32_t) GNUNET_MQ_env_get_options (env));
336 }
337 obm->peer = n->id;
338 if (0 == n->ready_window)
339 {
340 LOG (GNUNET_ERROR_TYPE_DEBUG,
341 "Flow control delays transmission to CORE until we see SEND_OK.\n");
342 return; /* can't send yet, need to wait for SEND_OK */
343 }
344 do_send (n);
345}
346
347
348/**
349 * Handle destruction of a message queue. Implementations must not
350 * free @a mq, but should take care of @a impl_state.
351 *
352 * @param mq the message queue to destroy
353 * @param impl_state state of the implementation
354 */
355static void
356mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
357{
358 struct Neighbour *n = impl_state;
359
360 GNUNET_assert (mq == n->mq);
361 n->mq = NULL;
362}
363
364
365/**
366 * Implementation function that cancels the currently sent message.
367 * Should basically undo whatever #mq_send_impl() did.
368 *
369 * @param mq message queue
370 * @param impl_state state specific to the implementation
371 */
372static void
373mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
374{
375 struct Neighbour *n = impl_state;
376
377 n->ready_window++;
378 if (GNUNET_YES == n->awaiting_done)
379 {
380 GNUNET_MQ_send_cancel (n->env);
381 n->env = NULL;
382 n->awaiting_done = GNUNET_NO;
383 }
384 else
385 {
386 GNUNET_assert (0 == n->ready_window);
387 n->env = NULL;
388 }
389}
390
391
392/**
393 * We had an error processing a message we forwarded from a peer to
394 * the CORE service. We should just complain about it but otherwise
395 * continue processing.
396 *
397 * @param cls closure
398 * @param error error code
399 */
400static void
401peer_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
402{
403 /* struct Neighbour *n = cls; */
404
405 GNUNET_break_op (0);
406}
407
408
409/**
410 * Function we use for handling incoming connect messages.
411 *
412 * @param cls closure, a `struct GNUNET_TRANSPORT_Handle *`
413 * @param cim message received
414 */
415static void
416handle_connect (void *cls, const struct ConnectInfoMessage *cim)
417{
418 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
419 struct Neighbour *n;
420
421 LOG (GNUNET_ERROR_TYPE_DEBUG,
422 "Receiving CONNECT message for `%s'\n",
423 GNUNET_i2s (&cim->id));
424 n = neighbour_find (h, &cim->id);
425 if (NULL != n)
426 {
427 GNUNET_break (0);
428 disconnect_and_schedule_reconnect (h);
429 return;
430 }
431 n = GNUNET_new (struct Neighbour);
432 n->id = cim->id;
433 n->h = h;
434 n->ready_window = SEND_WINDOW_SIZE;
435 GNUNET_assert (GNUNET_OK ==
436 GNUNET_CONTAINER_multipeermap_put (
437 h->neighbours,
438 &n->id,
439 n,
440 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
441
442 n->mq = GNUNET_MQ_queue_for_callbacks (&mq_send_impl,
443 &mq_destroy_impl,
444 &mq_cancel_impl,
445 n,
446 h->handlers,
447 &peer_mq_error_handler,
448 n);
449 if (NULL != h->nc_cb)
450 {
451 n->handlers_cls = h->nc_cb (h->cls, &n->id, n->mq);
452 GNUNET_MQ_set_handlers_closure (n->mq, n->handlers_cls);
453 }
454}
455
456
457/**
458 * Function we use for handling incoming disconnect messages.
459 *
460 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
461 * @param dim message received
462 */
463static void
464handle_disconnect (void *cls, const struct DisconnectInfoMessage *dim)
465{
466 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
467 struct Neighbour *n;
468
469 GNUNET_break (ntohl (dim->reserved) == 0);
470 LOG (GNUNET_ERROR_TYPE_DEBUG,
471 "Receiving DISCONNECT message for `%s'.\n",
472 GNUNET_i2s (&dim->peer));
473 n = neighbour_find (h, &dim->peer);
474 if (NULL == n)
475 {
476 GNUNET_break (0);
477 disconnect_and_schedule_reconnect (h);
478 return;
479 }
480 GNUNET_assert (GNUNET_YES == neighbour_delete (h, &dim->peer, n));
481}
482
483
484/**
485 * Function we use for handling incoming send-ok messages.
486 *
487 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
488 * @param okm message received
489 */
490static void
491handle_send_ok (void *cls, const struct SendOkMessage *okm)
492{
493 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
494 struct Neighbour *n;
495
496 LOG (GNUNET_ERROR_TYPE_DEBUG,
497 "Receiving SEND_OK message for transmission to %s\n",
498 GNUNET_i2s (&okm->peer));
499 n = neighbour_find (h, &okm->peer);
500 if (NULL == n)
501 {
502 /* We should never get a 'SEND_OK' for a peer that we are not
503 connected to */
504 GNUNET_break (0);
505 disconnect_and_schedule_reconnect (h);
506 return;
507 }
508 n->ready_window++;
509 if ((NULL != n->env) && (1 == n->ready_window))
510 do_send (n);
511}
512
513
514/**
515 * Function we use for checking incoming "inbound" messages.
516 *
517 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
518 * @param im message received
519 */
520static int
521check_recv (void *cls, const struct InboundMessage *im)
522{
523 const struct GNUNET_MessageHeader *imm;
524 uint16_t size;
525
526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
527 "check_recv\n");
528 size = ntohs (im->header.size) - sizeof(*im);
529 if (size < sizeof(struct GNUNET_MessageHeader))
530 {
531 GNUNET_break (0);
532 return GNUNET_SYSERR;
533 }
534 imm = (const struct GNUNET_MessageHeader *) &im[1];
535 if (ntohs (imm->size) != size)
536 {
537 GNUNET_break (0);
538 return GNUNET_SYSERR;
539 }
540 return GNUNET_OK;
541}
542
543
544/**
545 * Function we use for handling incoming messages.
546 *
547 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
548 * @param im message received
549 */
550static void
551handle_recv (void *cls, const struct InboundMessage *im)
552{
553 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
554 const struct GNUNET_MessageHeader *imm =
555 (const struct GNUNET_MessageHeader *) &im[1];
556 struct Neighbour *n;
557
558 LOG (GNUNET_ERROR_TYPE_DEBUG,
559 "Received message of type %u with %u bytes from `%s'.\n",
560 (unsigned int) ntohs (imm->type),
561 (unsigned int) ntohs (imm->size),
562 GNUNET_i2s (&im->peer));
563 n = neighbour_find (h, &im->peer);
564 if (NULL == n)
565 {
566 GNUNET_break (0);
567 disconnect_and_schedule_reconnect (h);
568 return;
569 }
570 GNUNET_MQ_inject_message (n->mq, imm);
571}
572
573
574/**
575 * Try again to connect to transport service.
576 *
577 * @param cls the handle to the transport service
578 */
579static void
580reconnect (void *cls)
581{
582 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
583 struct GNUNET_MQ_MessageHandler handlers[] =
584 { GNUNET_MQ_hd_fixed_size (connect,
585 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT,
586 struct ConnectInfoMessage,
587 h),
588 GNUNET_MQ_hd_fixed_size (disconnect,
589 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT,
590 struct DisconnectInfoMessage,
591 h),
592 GNUNET_MQ_hd_fixed_size (send_ok,
593 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK,
594 struct SendOkMessage,
595 h),
596 GNUNET_MQ_hd_var_size (recv,
597 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV,
598 struct InboundMessage,
599 h),
600 GNUNET_MQ_handler_end () };
601 struct GNUNET_MQ_Envelope *env;
602 struct StartMessage *s;
603 uint32_t options;
604
605 h->reconnect_task = NULL;
606 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n");
607 GNUNET_assert (NULL == h->mq);
608 h->mq =
609 GNUNET_CLIENT_connect (h->cfg, "transport", handlers, &mq_error_handler, h);
610 if (NULL == h->mq)
611 return;
612 env = GNUNET_MQ_msg (s, GNUNET_MESSAGE_TYPE_TRANSPORT_START);
613 options = 0;
614 if (h->check_self)
615 options |= 1;
616 if (NULL != h->handlers)
617 options |= 2;
618 s->options = htonl (options);
619 s->self = h->self;
620 GNUNET_MQ_send (h->mq, env);
621}
622
623
624/**
625 * Disconnect from the transport service.
626 *
627 * @param h transport service to reconnect
628 */
629static void
630disconnect (struct GNUNET_TRANSPORT_CoreHandle *h)
631{
632 GNUNET_CONTAINER_multipeermap_iterate (h->neighbours, &neighbour_delete, h);
633 if (NULL != h->mq)
634 {
635 GNUNET_MQ_destroy (h->mq);
636 h->mq = NULL;
637 }
638}
639
640
641/**
642 * Function that will schedule the job that will try
643 * to connect us again to the client.
644 *
645 * @param h transport service to reconnect
646 */
647static void
648disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h)
649{
650 GNUNET_assert (NULL == h->reconnect_task);
651 disconnect (h);
652 LOG (GNUNET_ERROR_TYPE_DEBUG,
653 "Scheduling task to reconnect to transport service in %s.\n",
654 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
655 h->reconnect_task =
656 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
657 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
658}
659
660
661/**
662 * Checks if a given peer is connected to us and get the message queue.
663 *
664 * @param handle connection to transport service
665 * @param peer the peer to check
666 * @return NULL if disconnected, otherwise message queue for @a peer
667 */
668struct GNUNET_MQ_Handle *
669GNUNET_TRANSPORT_core_get_mq (struct GNUNET_TRANSPORT_CoreHandle *handle,
670 const struct GNUNET_PeerIdentity *peer)
671{
672 struct Neighbour *n;
673
674 n = neighbour_find (handle, peer);
675 if (NULL == n)
676 return NULL;
677 return n->mq;
678}
679
680
681/**
682 * Notification from the CORE service to the TRANSPORT service
683 * that the CORE service has finished processing a message from
684 * TRANSPORT (via the @code{handlers} of #GNUNET_TRANSPORT_core_connect())
685 * and that it is thus now OK for TRANSPORT to send more messages
686 * for @a pid.
687 *
688 * Used to provide flow control, this is our equivalent to
689 * #GNUNET_SERVICE_client_continue() of an ordinary service.
690 *
691 * Note that due to the use of a window, TRANSPORT may send multiple
692 * messages destined for the same peer even without an intermediate
693 * call to this function. However, CORE must still call this function
694 * once per message received, as otherwise eventually the window will
695 * be full and TRANSPORT will stop providing messages to CORE for @a
696 * pid.
697 *
698 * @param ch core handle
699 * @param pid which peer was the message from that was fully processed by CORE
700 */
701void
702GNUNET_TRANSPORT_core_receive_continue (struct GNUNET_TRANSPORT_CoreHandle *ch,
703 const struct GNUNET_PeerIdentity *pid)
704{
705 struct GNUNET_MQ_Envelope *env;
706 struct RecvOkMessage *rok;
707
708 LOG (GNUNET_ERROR_TYPE_DEBUG,
709 "Message for %s finished CORE processing, sending RECV_OK.\n",
710 GNUNET_i2s (pid));
711 if (NULL == ch->mq)
712 return;
713 env = GNUNET_MQ_msg (rok, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK);
714 rok->increase_window_delta = htonl (1);
715 rok->peer = *pid;
716 GNUNET_MQ_send (ch->mq, env);
717}
718
719
720/**
721 * Connect to the transport service. Note that the connection may
722 * complete (or fail) asynchronously.
723 *
724 * @param cfg configuration to use
725 * @param self our own identity (API should check that it matches
726 * the identity found by transport), or NULL (no check)
727 * @param cls closure for the callbacks
728 * @param rec receive function to call
729 * @param nc function to call on connect events
730 * @param nd function to call on disconnect events
731 * @return NULL on error
732 */
733struct GNUNET_TRANSPORT_CoreHandle *
734GNUNET_TRANSPORT_core_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
735 const struct GNUNET_PeerIdentity *self,
736 const struct GNUNET_MQ_MessageHandler *handlers,
737 void *cls,
738 GNUNET_TRANSPORT_NotifyConnect nc,
739 GNUNET_TRANSPORT_NotifyDisconnect nd)
740{
741 struct GNUNET_TRANSPORT_CoreHandle *h;
742 unsigned int i;
743
744 h = GNUNET_new (struct GNUNET_TRANSPORT_CoreHandle);
745 if (NULL != self)
746 {
747 h->self = *self;
748 h->check_self = GNUNET_YES;
749 }
750 h->cfg = cfg;
751 h->cls = cls;
752 h->nc_cb = nc;
753 h->nd_cb = nd;
754 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
755 if (NULL != handlers)
756 {
757 for (i = 0; NULL != handlers[i].cb; i++)
758 ;
759 h->handlers = GNUNET_new_array (i + 1, struct GNUNET_MQ_MessageHandler);
760 GNUNET_memcpy (h->handlers,
761 handlers,
762 i * sizeof(struct GNUNET_MQ_MessageHandler));
763 }
764 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service\n");
765 reconnect (h);
766 if (NULL == h->mq)
767 {
768 GNUNET_free (h->handlers);
769 GNUNET_free (h);
770 return NULL;
771 }
772 h->neighbours =
773 GNUNET_CONTAINER_multipeermap_create (STARTING_NEIGHBOURS_SIZE, GNUNET_YES);
774 return h;
775}
776
777
778/**
779 * Disconnect from the transport service.
780 *
781 * @param handle handle to the service as returned from
782 * #GNUNET_TRANSPORT_core_connect()
783 */
784void
785GNUNET_TRANSPORT_core_disconnect (struct GNUNET_TRANSPORT_CoreHandle *handle)
786{
787 LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n");
788 /* this disconnects all neighbours... */
789 disconnect (handle);
790 /* and now we stop trying to connect again... */
791 if (NULL != handle->reconnect_task)
792 {
793 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
794 handle->reconnect_task = NULL;
795 }
796 GNUNET_CONTAINER_multipeermap_destroy (handle->neighbours);
797 handle->neighbours = NULL;
798 GNUNET_free (handle->handlers);
799 handle->handlers = NULL;
800 GNUNET_free (handle);
801}
802
803
804/* end of transport_api_core.c */
diff --git a/src/transport/transport_api2_monitor.c b/src/transport/transport_api2_monitor.c
deleted file mode 100644
index 67aa1985e..000000000
--- a/src/transport/transport_api2_monitor.c
+++ /dev/null
@@ -1,292 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2018 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api2_monitor.c
23 * @brief implementation of the gnunet_transport_monitor_service.h API
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_protocols.h"
29#include "gnunet_transport_monitor_service.h"
30#include "transport.h"
31
32
33/**
34 * Opaque handle to the transport service for monitors.
35 */
36struct GNUNET_TRANSPORT_MonitorContext
37{
38 /**
39 * Our configuration.
40 */
41 const struct GNUNET_CONFIGURATION_Handle *cfg;
42
43 /**
44 * Queue to talk to the transport service.
45 */
46 struct GNUNET_MQ_Handle *mq;
47
48 /**
49 * Peer we monitor, all zeros for "all"
50 */
51 struct GNUNET_PeerIdentity peer;
52
53 /**
54 * #GNUNET_YES to return the current state and then end.
55 */
56 int one_shot;
57
58 /**
59 * Function to call with monitor data.
60 */
61 GNUNET_TRANSPORT_MonitorCallback cb;
62
63 /**
64 * Closure for @e cb.
65 */
66 void *cb_cls;
67};
68
69
70/**
71 * (re)connect our monitor to the transport service
72 *
73 * @param mc handle to reconnect
74 */
75static void
76reconnect (struct GNUNET_TRANSPORT_MonitorContext *mc);
77
78
79/**
80 * Send message to the transport service about our montoring
81 * desire.
82 *
83 * @param ai address to delete
84 */
85static void
86send_start_monitor (struct GNUNET_TRANSPORT_MonitorContext *mc)
87{
88 struct GNUNET_MQ_Envelope *env;
89 struct GNUNET_TRANSPORT_MonitorStart *smm;
90
91 if (NULL == mc->mq)
92 return;
93 env = GNUNET_MQ_msg (smm, GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START);
94 smm->one_shot = htonl ((uint32_t) mc->one_shot);
95 smm->peer = mc->peer;
96 GNUNET_MQ_send (mc->mq, env);
97}
98
99
100/**
101 * Disconnect from the transport service.
102 *
103 * @param mc service to disconnect from
104 */
105static void
106disconnect (struct GNUNET_TRANSPORT_MonitorContext *mc)
107{
108 if (NULL == mc->mq)
109 return;
110 GNUNET_MQ_destroy (mc->mq);
111 mc->mq = NULL;
112}
113
114
115/**
116 * Function called on MQ errors. Reconnects to the service.
117 *
118 * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
119 * @param error what error happened?
120 */
121static void
122error_handler (void *cls, enum GNUNET_MQ_Error error)
123{
124 struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
125
126 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
127 "MQ failure %d, reconnecting to transport service.\n",
128 error);
129 disconnect (mc);
130 /* TODO: maybe do this with exponential backoff/delay */
131 reconnect (mc);
132}
133
134
135/**
136 * Transport service sends us information about what is going on.
137 * Check if @a md is well-formed.
138 *
139 * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
140 * @param md the monitor data we got
141 * @return #GNUNET_OK if @a smt is well-formed
142 */
143static int
144check_monitor_data (void *cls, const struct GNUNET_TRANSPORT_MonitorData *md)
145{
146 (void) cls;
147 GNUNET_MQ_check_zero_termination (md);
148 return GNUNET_OK;
149}
150
151
152/**
153 * Transport service sends us information about what is going on.
154 *
155 * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
156 * @param md monitor data
157 */
158static void
159handle_monitor_data (void *cls, const struct GNUNET_TRANSPORT_MonitorData *md)
160{
161 struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
162 struct GNUNET_TRANSPORT_MonitorInformation mi;
163
164 mi.address = (const char *) &md[1];
165 mi.nt = (enum GNUNET_NetworkType) ntohl (md->nt);
166 mi.cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (md->cs);
167 mi.num_msg_pending = ntohl (md->num_msg_pending);
168 mi.num_bytes_pending = ntohl (md->num_bytes_pending);
169 mi.last_validation = GNUNET_TIME_absolute_ntoh (md->last_validation);
170 mi.valid_until = GNUNET_TIME_absolute_ntoh (md->valid_until);
171 mi.next_validation = GNUNET_TIME_absolute_ntoh (md->next_validation);
172 mi.rtt = GNUNET_TIME_relative_ntoh (md->rtt);
173 mc->cb (mc->cb_cls, &md->peer, &mi);
174}
175
176
177/**
178 * One shot was requested, and transport service is done.
179 *
180 * @param cls our `struct GNUNET_TRANSPORT_MonitorContext *`
181 * @param me end message
182 */
183static void
184handle_monitor_end (void *cls, const struct GNUNET_MessageHeader *me)
185{
186 struct GNUNET_TRANSPORT_MonitorContext *mc = cls;
187
188 if (GNUNET_YES != mc->one_shot)
189 {
190 GNUNET_break (0);
191 disconnect (mc);
192 reconnect (mc);
193 return;
194 }
195 mc->cb (mc->cb_cls, NULL, NULL);
196 GNUNET_TRANSPORT_monitor_cancel (mc);
197}
198
199
200/**
201 * (re)connect our monitor to the transport service
202 *
203 * @param mc handle to reconnect
204 */
205static void
206reconnect (struct GNUNET_TRANSPORT_MonitorContext *mc)
207{
208 struct GNUNET_MQ_MessageHandler handlers[] =
209 { GNUNET_MQ_hd_var_size (monitor_data,
210 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA,
211 struct GNUNET_TRANSPORT_MonitorData,
212 mc),
213 GNUNET_MQ_hd_fixed_size (monitor_end,
214 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_END,
215 struct GNUNET_MessageHeader,
216 mc),
217 GNUNET_MQ_handler_end () };
218
219 mc->mq =
220 GNUNET_CLIENT_connect (mc->cfg, "transport", handlers, &error_handler, mc);
221 if (NULL == mc->mq)
222 return;
223 send_start_monitor (mc);
224}
225
226
227/**
228 * Return information about a specific peer or all peers currently known to
229 * transport service once or in monitoring mode. To obtain information about
230 * a specific peer, a peer identity can be passed. To obtain information about
231 * all peers currently known to transport service, NULL can be passed as peer
232 * identity.
233 *
234 * For each peer, the callback is called with information about the address used
235 * to communicate with this peer, the state this peer is currently in and the
236 * the current timeout for this state.
237 *
238 * Upon completion, the #GNUNET_TRANSPORT_PeerIterateCallback is called one
239 * more time with `NULL`. After this, the operation must no longer be
240 * explicitly canceled.
241 *
242 * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
243 * the peer_callback!
244 *
245 * @param cfg configuration to use
246 * @param peer a specific peer identity to obtain information for,
247 * NULL for all peers
248 * @param one_shot #GNUNET_YES to return the current state and then end (with NULL+NULL),
249 * #GNUNET_NO to monitor peers continuously
250 * @param cb function to call with the results
251 * @param cb_cls closure for @a mc
252 */
253struct GNUNET_TRANSPORT_MonitorContext *
254GNUNET_TRANSPORT_monitor (const struct GNUNET_CONFIGURATION_Handle *cfg,
255 const struct GNUNET_PeerIdentity *peer,
256 int one_shot,
257 GNUNET_TRANSPORT_MonitorCallback cb,
258 void *cb_cls)
259{
260 struct GNUNET_TRANSPORT_MonitorContext *mc;
261
262 mc = GNUNET_new (struct GNUNET_TRANSPORT_MonitorContext);
263 mc->cfg = cfg;
264 if (NULL != peer)
265 mc->peer = *peer;
266 mc->one_shot = one_shot;
267 mc->cb = cb;
268 mc->cb_cls = cb_cls;
269 reconnect (mc);
270 if (NULL == mc->mq)
271 {
272 GNUNET_free (mc);
273 return NULL;
274 }
275 return mc;
276}
277
278
279/**
280 * Cancel request to monitor peers
281 *
282 * @param pmc handle for the request to cancel
283 */
284void
285GNUNET_TRANSPORT_monitor_cancel (struct GNUNET_TRANSPORT_MonitorContext *mc)
286{
287 disconnect (mc);
288 GNUNET_free (mc);
289}
290
291
292/* end of transport_api2_monitor.c */
diff --git a/src/transport/transport_api_address_to_string.c b/src/transport/transport_api_address_to_string.c
deleted file mode 100644
index c7de39ea8..000000000
--- a/src/transport/transport_api_address_to_string.c
+++ /dev/null
@@ -1,264 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport/transport_api_address_to_string.c
22 * @author Christian Grothoff
23 * @brief enable clients to convert addresses to human readable strings
24 */
25#include "platform.h"
26#include "gnunet_util_lib.h"
27#include "gnunet_arm_service.h"
28#include "gnunet_hello_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_transport_service.h"
31#include "transport.h"
32
33/**
34 * Context for the address lookup.
35 */
36struct GNUNET_TRANSPORT_AddressToStringContext
37{
38 /**
39 * Function to call with the human-readable address.
40 */
41 GNUNET_TRANSPORT_AddressToStringCallback cb;
42
43 /**
44 * Closure for @e cb.
45 */
46 void *cb_cls;
47
48 /**
49 * Connection to the service.
50 */
51 struct GNUNET_MQ_Handle *mq;
52};
53
54
55/**
56 * Function called with responses from the service.
57 *
58 * @param cls our `struct GNUNET_TRANSPORT_AddressToStringContext *`
59 * @param msg message with the human-readable address
60 * @return #GNUNET_OK if message is well-formed
61 */
62static int
63check_reply (void *cls,
64 const struct AddressToStringResultMessage *atsm)
65{
66 uint16_t size = ntohs (atsm->header.size) - sizeof(*atsm);
67 const char *address;
68 int result;
69 uint32_t addr_len;
70
71 result = (int) ntohl (atsm->res);
72 addr_len = ntohl (atsm->addr_len);
73 if (GNUNET_SYSERR == result)
74 return GNUNET_OK;
75 if (0 == size)
76 {
77 if (GNUNET_OK != result)
78 {
79 GNUNET_break (0);
80 return GNUNET_SYSERR;
81 }
82 return GNUNET_OK;
83 }
84 address = (const char *) &atsm[1];
85 if ((addr_len > size) ||
86 (address[addr_len - 1] != '\0'))
87 {
88 /* invalid reply */
89 GNUNET_break (0);
90 return GNUNET_SYSERR;
91 }
92 return GNUNET_OK;
93}
94
95
96/**
97 * Function called with responses from the service.
98 *
99 * @param cls our `struct GNUNET_TRANSPORT_AddressToStringContext *`
100 * @param msg message with the human-readable address
101 */
102static void
103handle_reply (void *cls,
104 const struct AddressToStringResultMessage *atsm)
105{
106 struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls;
107 uint16_t size = ntohs (atsm->header.size) - sizeof(*atsm);
108 const char *address;
109 int result;
110
111 result = (int) ntohl (atsm->res);
112 if (GNUNET_SYSERR == result)
113 {
114 /* expect more replies; as this is not the last
115 call, we must pass the empty string for the address */
116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
117 "Address resolution failed\n");
118 alucb->cb (alucb->cb_cls,
119 "",
120 GNUNET_NO);
121 return;
122 }
123 if (0 == size)
124 {
125 /* we are done (successfully, without communication errors) */
126 alucb->cb (alucb->cb_cls,
127 NULL,
128 GNUNET_OK);
129 GNUNET_TRANSPORT_address_to_string_cancel (alucb);
130 return;
131 }
132 address = (const char *) &atsm[1];
133 /* return normal reply to caller, also expect more replies */
134 alucb->cb (alucb->cb_cls,
135 address,
136 GNUNET_OK);
137}
138
139
140/**
141 * Generic error handler, called with the appropriate
142 * error code and the same closure specified at the creation of
143 * the message queue.
144 * Not every message queue implementation supports an error handler.
145 *
146 * @param cls the `struct GNUNET_TRANSPORT_AddressToStringContext *`
147 * @param error error code
148 */
149static void
150mq_error_handler (void *cls,
151 enum GNUNET_MQ_Error error)
152{
153 struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls;
154
155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156 "Disconnected from transport, address resolution failed\n");
157 alucb->cb (alucb->cb_cls,
158 NULL,
159 GNUNET_SYSERR);
160 GNUNET_TRANSPORT_address_to_string_cancel (alucb);
161}
162
163
164/**
165 * Convert a binary address into a human readable address.
166 *
167 * @param cfg configuration to use
168 * @param address address to convert (binary format)
169 * @param numeric should (IP) addresses be displayed in numeric form
170 * (otherwise do reverse DNS lookup)
171 * @param timeout how long is the lookup allowed to take at most
172 * @param aluc function to call with the results
173 * @param aluc_cls closure for @a aluc
174 * @return handle to cancel the operation, NULL on error
175 */
176struct GNUNET_TRANSPORT_AddressToStringContext *
177GNUNET_TRANSPORT_address_to_string (const struct
178 GNUNET_CONFIGURATION_Handle *cfg,
179 const struct GNUNET_HELLO_Address *address,
180 int numeric,
181 struct GNUNET_TIME_Relative timeout,
182 GNUNET_TRANSPORT_AddressToStringCallback
183 aluc,
184 void *aluc_cls)
185{
186 struct GNUNET_TRANSPORT_AddressToStringContext *alc
187 = GNUNET_new (struct GNUNET_TRANSPORT_AddressToStringContext);
188 struct GNUNET_MQ_MessageHandler handlers[] = {
189 GNUNET_MQ_hd_var_size (reply,
190 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY,
191 struct AddressToStringResultMessage,
192 alc),
193 GNUNET_MQ_handler_end ()
194 };
195 size_t alen;
196 size_t slen;
197 struct AddressLookupMessage *msg;
198 struct GNUNET_MQ_Envelope *env;
199 char *addrbuf;
200
201 alen = address->address_length;
202 slen = strlen (address->transport_name) + 1;
203 if ((alen + slen >= GNUNET_MAX_MESSAGE_SIZE
204 - sizeof(struct AddressLookupMessage)) ||
205 (alen >= GNUNET_MAX_MESSAGE_SIZE) ||
206 (slen >= GNUNET_MAX_MESSAGE_SIZE))
207 {
208 GNUNET_break (0);
209 GNUNET_free (alc);
210 return NULL;
211 }
212 alc->cb = aluc;
213 alc->cb_cls = aluc_cls;
214 alc->mq = GNUNET_CLIENT_connect (cfg,
215 "transport",
216 handlers,
217 &mq_error_handler,
218 alc);
219 if (NULL == alc->mq)
220 {
221 GNUNET_break (0);
222 GNUNET_free (alc);
223 return NULL;
224 }
225 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
226 "Client tries to resolve for peer `%s' address plugin %s len %u\n",
227 GNUNET_i2s (&address->peer),
228 address->transport_name,
229 (unsigned int) address->address_length);
230 env = GNUNET_MQ_msg_extra (msg,
231 alen + slen,
232 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING);
233 msg->numeric_only = htons ((int16_t) numeric);
234 msg->addrlen = htons ((uint16_t) alen);
235 msg->timeout = GNUNET_TIME_relative_hton (timeout);
236 addrbuf = (char *) &msg[1];
237 GNUNET_memcpy (addrbuf,
238 address->address,
239 alen);
240 GNUNET_memcpy (&addrbuf[alen],
241 address->transport_name,
242 slen);
243 GNUNET_MQ_send (alc->mq,
244 env);
245 return alc;
246}
247
248
249/**
250 * Cancel request for address conversion.
251 *
252 * @param alc the context handle
253 */
254void
255GNUNET_TRANSPORT_address_to_string_cancel (struct
256 GNUNET_TRANSPORT_AddressToStringContext
257 *alc)
258{
259 GNUNET_MQ_destroy (alc->mq);
260 GNUNET_free (alc);
261}
262
263
264/* end of transport_api_address_to_string.c */
diff --git a/src/transport/transport_api_blacklist.c b/src/transport/transport_api_blacklist.c
deleted file mode 100644
index b195a7fc7..000000000
--- a/src/transport/transport_api_blacklist.c
+++ /dev/null
@@ -1,197 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2010-2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_blacklist.c
23 * @brief library to access the blacklisting functions of the transport service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_arm_service.h"
29#include "gnunet_hello_lib.h"
30#include "gnunet_protocols.h"
31#include "gnunet_transport_service.h"
32#include "transport.h"
33
34/**
35 * Handle for blacklisting requests.
36 */
37struct GNUNET_TRANSPORT_Blacklist
38{
39 /**
40 * Connection to transport service.
41 */
42 struct GNUNET_MQ_Handle *mq;
43
44 /**
45 * Configuration to use.
46 */
47 const struct GNUNET_CONFIGURATION_Handle *cfg;
48
49 /**
50 * Function to call for determining if a peer is allowed
51 * to communicate with us.
52 */
53 GNUNET_TRANSPORT_BlacklistCallback cb;
54
55 /**
56 * Closure for @e cb.
57 */
58 void *cb_cls;
59};
60
61
62/**
63 * Establish blacklist connection to transport service.
64 *
65 * @param br overall handle
66 */
67static void
68reconnect (struct GNUNET_TRANSPORT_Blacklist *br);
69
70
71/**
72 * Handle blacklist queries.
73 *
74 * @param cls our overall handle
75 * @param bm query
76 */
77static void
78handle_query (void *cls,
79 const struct BlacklistMessage *bm)
80{
81 struct GNUNET_TRANSPORT_Blacklist *br = cls;
82 struct GNUNET_MQ_Envelope *env;
83 struct BlacklistMessage *res;
84
85 GNUNET_break (0 == ntohl (bm->is_allowed));
86 env = GNUNET_MQ_msg (res,
87 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY);
88 res->is_allowed = htonl (br->cb (br->cb_cls,
89 &bm->peer));
90 res->peer = bm->peer;
91 GNUNET_MQ_send (br->mq,
92 env);
93}
94
95
96/**
97 * Generic error handler, called with the appropriate error code and
98 * the same closure specified at the creation of the message queue.
99 * Not every message queue implementation supports an error handler.
100 *
101 * @param cls closure with the `struct GNUNET_TRANSPORT_Blacklist *`
102 * @param error error code
103 */
104static void
105mq_error_handler (void *cls,
106 enum GNUNET_MQ_Error error)
107{
108 struct GNUNET_TRANSPORT_Blacklist *br = cls;
109
110 reconnect (br);
111}
112
113
114/**
115 * Establish blacklist connection to transport service.
116 *
117 * @param br overall handle
118 */
119static void
120reconnect (struct GNUNET_TRANSPORT_Blacklist *br)
121{
122 struct GNUNET_MQ_MessageHandler handlers[] = {
123 GNUNET_MQ_hd_fixed_size (query,
124 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY,
125 struct BlacklistMessage,
126 br),
127 GNUNET_MQ_handler_end ()
128 };
129 struct GNUNET_MQ_Envelope *env;
130 struct GNUNET_MessageHeader *req;
131
132 if (NULL != br->mq)
133 GNUNET_MQ_destroy (br->mq);
134 br->mq = GNUNET_CLIENT_connect (br->cfg,
135 "transport",
136 handlers,
137 &mq_error_handler,
138 br);
139 if (NULL == br->mq)
140 return;
141 env = GNUNET_MQ_msg (req,
142 GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT);
143 GNUNET_MQ_send (br->mq,
144 env);
145}
146
147
148/**
149 * Install a blacklist callback. The service will be queried for all
150 * existing connections as well as any fresh connections to check if
151 * they are permitted. If the blacklisting callback is unregistered,
152 * all hosts that were denied in the past will automatically be
153 * whitelisted again. Cancelling the blacklist handle is also the
154 * only way to re-enable connections from peers that were previously
155 * blacklisted.
156 *
157 * @param cfg configuration to use
158 * @param cb callback to invoke to check if connections are allowed
159 * @param cb_cls closure for @a cb
160 * @return NULL on error, otherwise handle for cancellation
161 */
162struct GNUNET_TRANSPORT_Blacklist *
163GNUNET_TRANSPORT_blacklist (const struct GNUNET_CONFIGURATION_Handle *cfg,
164 GNUNET_TRANSPORT_BlacklistCallback cb,
165 void *cb_cls)
166{
167 struct GNUNET_TRANSPORT_Blacklist *br;
168
169 br = GNUNET_new (struct GNUNET_TRANSPORT_Blacklist);
170 br->cfg = cfg;
171 br->cb = cb;
172 br->cb_cls = cb_cls;
173 reconnect (br);
174 if (NULL == br->mq)
175 {
176 GNUNET_free (br);
177 return NULL;
178 }
179 return br;
180}
181
182
183/**
184 * Abort the blacklist. Note that this function is the only way for
185 * removing a peer from the blacklist.
186 *
187 * @param br handle of the request that is to be cancelled
188 */
189void
190GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_Blacklist *br)
191{
192 GNUNET_MQ_destroy (br->mq);
193 GNUNET_free (br);
194}
195
196
197/* end of transport_api_blacklist.c */
diff --git a/src/transport/transport_api_cmd_backchannel_check.c b/src/transport/transport_api_cmd_backchannel_check.c
deleted file mode 100644
index 4ffd96210..000000000
--- a/src/transport/transport_api_cmd_backchannel_check.c
+++ /dev/null
@@ -1,602 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_backchannel_check.c
23 * @brief cmd to start a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_common.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_testing_ng_lib.h"
30#include "gnunet_testing_netjail_lib.h"
31#include "gnunet_transport_application_service.h"
32#include "gnunet_hello_lib.h"
33#include "gnunet_transport_service.h"
34#include "transport-testing-cmds.h"
35
36/**
37 * Generic logging shortcut
38 */
39#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
40
41#define UDP "udp"
42
43/**
44 * Maximum length allowed for line input.
45 */
46#define MAX_LINE_LENGTH 1024
47
48/**
49 * Struct to store information needed in callbacks.
50 *
51 */
52struct CheckState
53{
54 /**
55 * Context for our asynchronous completion.
56 */
57 struct GNUNET_TESTING_AsyncContext ac;
58
59 /**
60 * The number of the node in a network namespace.
61 */
62 unsigned int node_n;
63
64 /**
65 * The number of the network namespace.
66 */
67 unsigned int namespace_n;
68
69 /**
70 * The testing system of this node.
71 */
72 const struct GNUNET_TESTING_System *tl_system;
73
74 // Label of the cmd which started the test system.
75 const char *create_label;
76
77 /**
78 * Number globally identifying the node.
79 *
80 */
81 uint32_t num;
82
83 /**
84 * Label of the cmd to start a peer.
85 *
86 */
87 const char *start_peer_label;
88
89 /**
90 * The topology of the test setup.
91 */
92 struct GNUNET_TESTING_NetjailTopology *topology;
93
94 /**
95 * Connections to other peers.
96 */
97 struct GNUNET_TESTING_NodeConnection *node_connections_head;
98
99 /**
100 * Number of connections.
101 */
102 unsigned int con_num;
103
104 /**
105 * Number of received backchannel messages.
106 */
107 unsigned int received_backchannel_msgs;
108
109 /**
110 * Array with search strings.
111 */
112 char **search_string;
113
114 /**
115 * File handle for log file.
116 */
117 struct GNUNET_DISK_FileHandle *fh;
118
119 /**
120 * Task which handles the reading
121 */
122 struct GNUNET_SCHEDULER_Task *task;
123
124 /**
125 * Stream to read log file lines.
126 */
127 FILE *stream;
128};
129
130/**
131 *
132 * @param cls The cmd state CheckState.
133 */
134static void
135read_from_log (void *cls)
136{
137 struct CheckState *cs = cls;
138 char line[MAX_LINE_LENGTH + 1];
139 char *search_string;
140
141
142 LOG (GNUNET_ERROR_TYPE_DEBUG,
143 "read_from_log\n");
144
145 cs->fh = GNUNET_DISK_file_open ("test.out",
146 GNUNET_DISK_OPEN_READ,
147 GNUNET_DISK_PERM_USER_READ);
148
149 cs->task = NULL;
150
151 /* read message from line and handle it */
152 cs->stream = fdopen (cs->fh->fd, "r");
153 memset (line, 0, MAX_LINE_LENGTH + 1);
154
155 // fgets (line, MAX_LINE_LENGTH, cs->stream);
156 // while (NULL != line && 0 != strcmp (line, ""))// '\0' != line[0])
157 while (NULL != fgets (line, MAX_LINE_LENGTH, cs->stream))
158 {
159 /*LOG (GNUNET_ERROR_TYPE_DEBUG,
160 "cs->received_backchannel_msgs: %u\n",
161 cs->received_backchannel_msgs);*/
162 /*if (NULL == strstr (line, "line"))
163 LOG (GNUNET_ERROR_TYPE_DEBUG,
164 "line: %s",
165 line);*/
166
167
168 for (int i = 0; i < cs->con_num; i++)
169 {
170 search_string = cs->search_string[i];
171 /*LOG (GNUNET_ERROR_TYPE_DEBUG,
172 "search %u %u: %s %p\n",
173 i,
174 cs->con_num,
175 cs->search_string[i],
176 cs->search_string);
177 fprintf (stderr,
178 line);*/
179 if (NULL != strstr (line,
180 search_string))
181 // "Delivering backchannel message from 4TTC to F7B5 of type 1460 to udp"))
182 // cs->search_string[i]))
183 {
184 cs->received_backchannel_msgs++;
185 LOG (GNUNET_ERROR_TYPE_DEBUG,
186 "received_backchannel_msgs %u con_num %u\n",
187 cs->received_backchannel_msgs,
188 cs->con_num);
189 if (cs->received_backchannel_msgs == cs->con_num)
190 {
191 LOG (GNUNET_ERROR_TYPE_DEBUG,
192 "search finished %lu %lu %u\n",
193 strlen (cs->search_string[i]),
194 strlen (
195 "Delivering backchannel message from 4TTC to F7B5 of type 1460 to udp"),
196 strcmp (
197 "Delivering backchannel message from 4TTC to F7B5 of type 1460 to udp",
198 cs->search_string[i]));
199 GNUNET_TESTING_async_finish (&cs->ac);
200 fclose (cs->stream);
201 return;
202 }
203 }
204 }
205 }
206 LOG (GNUNET_ERROR_TYPE_DEBUG,
207 "read_from_log end\n");
208 fclose (cs->stream);
209 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
210 &read_from_log,
211 cs);
212 /*if (NULL == fgets (line, MAX_LINE_LENGTH, cs->stream))
213 {
214 LOG (GNUNET_ERROR_TYPE_DEBUG,
215 "read null\n");
216 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
217 &read_from_log,
218 cs);
219 return;
220 }*/
221 /*else {
222 cs->task =
223 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
224 cs->fh,
225 &read_from_log,
226 cs);
227
228
229 }*/
230}
231
232
233static enum GNUNET_GenericReturnValue
234will_the_other_node_connect_via_udp (
235 struct CheckState *cs,
236 const struct GNUNET_TESTING_NetjailNode *node)
237// struct GNUNET_TESTING_NodeConnection *connection)
238{
239 // struct GNUNET_TESTING_NetjailTopology *topology = cs->topology;
240 // unsigned int node_n = connection->node_n;
241 // unsigned int namespace_n = connection->namespace_n;
242 // struct GNUNET_HashCode hc;
243 // struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
244 // struct GNUNET_HashCode hc_namespace;
245 /*struct GNUNET_ShortHashCode *key_namespace = GNUNET_new (struct
246 GNUNET_ShortHashCode);*/
247 // struct GNUNET_TESTING_NetjailNode *node;
248 struct GNUNET_TESTING_NodeConnection *pos_connection;
249 struct GNUNET_TESTING_AddressPrefix *pos_prefix;
250 // struct GNUNET_TESTING_NetjailNamespace *namespace;
251 // struct GNUNET_CONTAINER_MultiShortmap *map;
252
253 /* if (0 == connection->namespace_n) */
254 /* { */
255 /* map = topology->map_globals; */
256 /* } */
257 /* else */
258 /* { */
259 /* GNUNET_CRYPTO_hash (&namespace_n, sizeof(namespace_n), &hc_namespace); */
260 /* memcpy (key_namespace, */
261 /* &hc_namespace, */
262 /* sizeof (*key_namespace)); */
263 /* if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains ( */
264 /* topology->map_namespaces, */
265 /* key_namespace)) */
266 /* { */
267 /* namespace = GNUNET_CONTAINER_multishortmap_get (topology->map_namespaces, */
268 /* key_namespace); */
269 /* map = namespace->nodes; */
270 /* } */
271 /* else */
272 /* GNUNET_assert (0); */
273 /* } */
274
275 /* GNUNET_CRYPTO_hash (&node_n, sizeof(node_n), &hc); */
276 /* memcpy (key, */
277 /* &hc, */
278 /* sizeof (*key)); */
279 /* if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains ( */
280 /* map, */
281 /* key)) */
282 /* { */
283 /* node = GNUNET_CONTAINER_multishortmap_get (cs->topology->map_globals, */
284 /* key); */
285 /* for (pos_connection = node->node_connections_head; NULL != pos_connection; */
286 /* pos_connection = pos_connection->next) */
287 /* { */
288 /* if ((node->namespace_n == pos_connection->namespace_n) && */
289 /* (node->node_n == pos_connection->node_n) ) */
290 /* { */
291 /* for (pos_prefix = pos_connection->address_prefixes_head; NULL != */
292 /* pos_prefix; */
293 /* pos_prefix = */
294 /* pos_prefix->next) */
295 /* { */
296 /* if (0 == strcmp (UDP, pos_prefix->address_prefix)) */
297 /* { */
298 /* return GNUNET_YES; */
299 /* } */
300 /* } */
301 /* } */
302 /* } */
303 /* } */
304
305 for (pos_connection = node->node_connections_head; NULL != pos_connection;
306 pos_connection = pos_connection->next)
307 {
308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
309 "connect via udp %u %u %u %u\n",
310 node->namespace_n,
311 cs->namespace_n,
312 node->node_n,
313 cs->node_n);
314 if ((pos_connection->namespace_n == cs->namespace_n) &&
315 (pos_connection->node_n == cs->node_n) )
316 {
317 for (pos_prefix = pos_connection->address_prefixes_head; NULL !=
318 pos_prefix;
319 pos_prefix =
320 pos_prefix->next)
321 {
322 if (0 == strcmp (UDP, pos_prefix->address_prefix))
323 {
324 return GNUNET_YES;
325 }
326 }
327 }
328 }
329
330 return GNUNET_NO;
331}
332
333static void
334add_search_string (struct CheckState *cs, const struct
335 GNUNET_TESTING_NetjailNode *node)
336{
337 unsigned int num;
338 struct GNUNET_PeerIdentity *peer;
339 struct GNUNET_PeerIdentity *us;
340 char *buf;
341 char *part_one = "Delivering backchannel message from ";
342 char *part_two = " to ";
343 char *part_three = " of type 1460 to udp";
344 char *peer_id;
345 char *us_id;
346
347 if (0 == node->namespace_n)
348 num = node->node_n;
349 else
350 num = (node->namespace_n - 1) * cs->topology->nodes_m + node->node_n
351 + cs->topology->nodes_x;
352
353 // num = GNUNET_TESTING_calculate_num (pos_connection, cs->topology);
354 peer = GNUNET_TESTING_get_pub_key (num, cs->tl_system);
355 LOG (GNUNET_ERROR_TYPE_DEBUG,
356 "peer: %s num %u\n",
357 GNUNET_i2s (peer),
358 num);
359 us = GNUNET_TESTING_get_pub_key (cs->num, cs->tl_system);
360 LOG (GNUNET_ERROR_TYPE_DEBUG,
361 "us: %s cs->num %d\n",
362 GNUNET_i2s (us),
363 cs->num);
364
365 GNUNET_asprintf (&peer_id,
366 "%s",
367 GNUNET_i2s (peer));
368 GNUNET_asprintf (&us_id,
369 "%s",
370 GNUNET_i2s (us));
371
372 if (0 < GNUNET_asprintf (&buf,
373 "%s%s%s%s%s",
374 part_one,
375 us_id,
376 part_two,
377 peer_id,
378 part_three))
379 {
380 GNUNET_array_append (cs->search_string,
381 cs->con_num,
382 buf);
383 /*LOG (GNUNET_ERROR_TYPE_DEBUG,
384 "con_num: %u search: %s %p\n",
385 cs->con_num,
386 cs->search_string[cs->con_num - 1],
387 cs->search_string);*/
388 }
389 else
390 GNUNET_assert (0);
391}
392
393
394/**
395 * The run method of this cmd will connect to peers.
396 *
397 */
398static void
399backchannel_check_run (void *cls,
400 struct GNUNET_TESTING_Interpreter *is)
401{
402 struct CheckState *cs = cls;
403 // char *buf;
404 // char *part_one = "Delivering backchannel message from ";
405 // char *part_two = " of type 1460 to udp";
406 const struct GNUNET_TESTING_Command *system_cmd;
407 const struct GNUNET_TESTING_System *tl_system;
408 const struct GNUNET_TESTING_Command *peer1_cmd;
409 const struct GNUNET_TRANSPORT_ApplicationHandle *ah;
410 // struct GNUNET_PeerIdentity *peer;
411 // uint32_t num;
412 // struct GNUNET_TESTING_NodeConnection *pos_connection;
413 // unsigned int con_num = 0;
414 struct GNUNET_CONTAINER_MultiShortmapIterator *node_it;
415 struct GNUNET_CONTAINER_MultiShortmapIterator *namespace_it;
416 struct GNUNET_ShortHashCode node_key;
417 struct GNUNET_ShortHashCode namespace_key;
418 const struct GNUNET_TESTING_NetjailNode *node;
419 const struct GNUNET_TESTING_NetjailNamespace *namespace;
420
421 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
422 cs->start_peer_label);
423 GNUNET_TRANSPORT_get_trait_application_handle (peer1_cmd,
424 &ah);
425
426 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
427 cs->create_label);
428 GNUNET_TESTING_get_trait_test_system (system_cmd,
429 &tl_system);
430
431 cs->tl_system = tl_system;
432
433 cs->node_connections_head = GNUNET_TESTING_get_connections (cs->num,
434 cs->topology);
435
436 LOG (GNUNET_ERROR_TYPE_DEBUG,
437 "check run\n");
438
439
440 node_it = GNUNET_CONTAINER_multishortmap_iterator_create (
441 cs->topology->map_globals);
442
443 while (GNUNET_YES == GNUNET_CONTAINER_multishortmap_iterator_next (node_it,
444 &node_key,
445 (const
446 void**) &
447 node))
448 {
449 LOG (GNUNET_ERROR_TYPE_DEBUG,
450 "namespace_n %u node_n %u\n",
451 node->namespace_n,
452 node->node_n);
453 if (GNUNET_YES == will_the_other_node_connect_via_udp (cs, node))
454 {
455 add_search_string (cs, node);
456 }
457 }
458 namespace_it = GNUNET_CONTAINER_multishortmap_iterator_create (
459 cs->topology->map_namespaces);
460 while (GNUNET_YES == GNUNET_CONTAINER_multishortmap_iterator_next (
461 namespace_it,
462 &namespace_key,
463 (const
464 void**) &namespace))
465 {
466 LOG (GNUNET_ERROR_TYPE_DEBUG,
467 "namespace_n %u\n",
468 node->namespace_n);
469 node_it = GNUNET_CONTAINER_multishortmap_iterator_create (
470 namespace->nodes);
471 while (GNUNET_YES == GNUNET_CONTAINER_multishortmap_iterator_next (node_it,
472 &node_key,
473 (const
474 void**)
475 &node))
476 {
477 LOG (GNUNET_ERROR_TYPE_DEBUG,
478 "namespace_n %u node_n %u\n",
479 node->namespace_n,
480 node->node_n);
481 if (GNUNET_YES == will_the_other_node_connect_via_udp (cs, node))
482 {
483 add_search_string (cs, node);
484 }
485 }
486 }
487 /* for (pos_connection = cs->node_connections_head; NULL != pos_connection; */
488 /* pos_connection = pos_connection->next) */
489 /* { */
490
491 /* if (GNUNET_YES == will_the_other_node_connect_via_udp (cs, node)) */
492 /* { */
493 /* num = GNUNET_TESTING_calculate_num (pos_connection, cs->topology); */
494 /* peer = GNUNET_TESTING_get_pub_key (num, tl_system); */
495 /* LOG (GNUNET_ERROR_TYPE_DEBUG, */
496 /* "peer: %s\n", */
497 /* GNUNET_i2s (peer)); */
498
499 /* if (0 < GNUNET_asprintf (&buf, */
500 /* "%s%s%s", */
501 /* part_one, */
502 /* GNUNET_i2s (peer), */
503 /* part_two)) */
504 /* { */
505 /* GNUNET_array_append (cs->search_string, */
506 /* con_num, */
507 /* buf); */
508 /* /\*LOG (GNUNET_ERROR_TYPE_DEBUG, */
509 /* "con_num: %u search: %s %p\n", */
510 /* con_num, */
511 /* cs->search_string[con_num - 1], */
512 /* cs->search_string);*\/ */
513 /* } */
514 /* else */
515 /* GNUNET_assert (0); */
516 /* } */
517
518
519 /* } */
520 // cs->con_num = con_num;
521 if (0 != cs->con_num)
522 {
523 cs->task =
524 GNUNET_SCHEDULER_add_now (&read_from_log,
525 cs);
526 }
527 else
528 GNUNET_TESTING_async_finish (&cs->ac);
529
530}
531
532
533/**
534 * Trait function of this cmd does nothing.
535 *
536 */
537static int
538backchannel_check_traits (void *cls,
539 const void **ret,
540 const char *trait,
541 unsigned int index)
542{
543 return GNUNET_OK;
544}
545
546
547/**
548 * The cleanup function of this cmd frees resources the cmd allocated.
549 *
550 */
551static void
552backchannel_check_cleanup (void *cls)
553{
554 struct ConnectPeersState *cs = cls;
555
556 GNUNET_free (cs);
557}
558
559
560/**
561 * Create command.
562 *
563 * @param label name for command.
564 * @param start_peer_label Label of the cmd to start a peer.
565 * @param create_label Label of the cmd to create the testing system.
566 * @param num Number globally identifying the node.
567 * @param node_n The number of the node in a network namespace.
568 * @param namespace_n The number of the network namespace.
569 * @param The topology for the test setup.
570 * @return command.
571 */
572struct GNUNET_TESTING_Command
573GNUNET_TRANSPORT_cmd_backchannel_check (const char *label,
574 const char *start_peer_label,
575 const char *create_label,
576 uint32_t num,
577 unsigned int node_n,
578 unsigned int namespace_n,
579 struct GNUNET_TESTING_NetjailTopology *
580 topology)
581{
582 struct CheckState *cs;
583
584 cs = GNUNET_new (struct CheckState);
585 cs->start_peer_label = start_peer_label;
586 cs->num = num;
587 cs->create_label = create_label;
588 cs->topology = topology;
589 cs->node_n = node_n;
590 cs->namespace_n = namespace_n;
591
592 struct GNUNET_TESTING_Command cmd = {
593 .cls = cs,
594 .label = label,
595 .run = &backchannel_check_run,
596 .ac = &cs->ac,
597 .cleanup = &backchannel_check_cleanup,
598 .traits = &backchannel_check_traits
599 };
600
601 return cmd;
602}
diff --git a/src/transport/transport_api_cmd_connecting_peers.c b/src/transport/transport_api_cmd_connecting_peers.c
deleted file mode 100644
index 8aba290c3..000000000
--- a/src/transport/transport_api_cmd_connecting_peers.c
+++ /dev/null
@@ -1,265 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_start_peer.c
23 * @brief cmd to start a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testing_netjail_lib.h"
30#include "gnunet_transport_application_service.h"
31#include "gnunet_hello_lib.h"
32#include "gnunet_transport_service.h"
33#include "transport-testing-cmds.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40/**
41 * The run method of this cmd will connect to peers.
42 *
43 */
44static void
45connect_peers_run (void *cls,
46 struct GNUNET_TESTING_Interpreter *is)
47{
48 struct ConnectPeersState *cps = cls;
49 const struct GNUNET_TESTING_Command *system_cmd;
50 const struct GNUNET_TESTING_System *tl_system;
51
52
53 const struct GNUNET_TESTING_Command *peer1_cmd;
54 const struct GNUNET_TRANSPORT_ApplicationHandle *ah;
55 struct GNUNET_PeerIdentity *peer;
56 char *addr;
57 char *addr_and_port;
58 enum GNUNET_NetworkType nt = 0;
59 uint32_t num;
60 struct GNUNET_TESTING_NodeConnection *pos_connection;
61 struct GNUNET_TESTING_AddressPrefix *pos_prefix;
62 unsigned int con_num = 0;
63 const enum GNUNET_GenericReturnValue *broadcast;
64 char *port;
65
66 cps->is = is;
67 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
68 cps->start_peer_label);
69 GNUNET_TRANSPORT_get_trait_application_handle (peer1_cmd,
70 &ah);
71 GNUNET_TRANSPORT_get_trait_broadcast (peer1_cmd,
72 &broadcast);
73
74 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
75 cps->create_label);
76 GNUNET_TESTING_get_trait_test_system (system_cmd,
77 &tl_system);
78
79 cps->tl_system = tl_system;
80
81 LOG (GNUNET_ERROR_TYPE_DEBUG,
82 "cps->num: %u \n",
83 cps->num);
84
85 cps->node_connections_head = GNUNET_TESTING_get_connections (cps->num,
86 cps->topology);
87
88 for (pos_connection = cps->node_connections_head; NULL != pos_connection;
89 pos_connection = pos_connection->next)
90 {
91 con_num++;
92 num = GNUNET_TESTING_calculate_num (pos_connection, cps->topology);
93 for (pos_prefix = pos_connection->address_prefixes_head; NULL != pos_prefix;
94 pos_prefix =
95 pos_prefix->next)
96 {
97 addr = GNUNET_TESTING_get_address (pos_connection,
98 pos_prefix->address_prefix);
99 if (NULL != addr)
100 {
101 if (0 == GNUNET_memcmp (pos_prefix->address_prefix, "udp"))
102 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
103 "validating memcmp\n");
104 if (GNUNET_YES == *broadcast)
105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
106 "validating broadcast\n");
107 if ((0 == GNUNET_memcmp (pos_prefix->address_prefix, "udp")) &&
108 (GNUNET_YES == *broadcast) )
109 GNUNET_asprintf (&addr_and_port,
110 "%s:2086",
111 addr);
112 else
113 GNUNET_asprintf (&addr_and_port,
114 "%s:60002",
115 addr);
116 peer = GNUNET_TESTING_get_pub_key (num, tl_system);
117 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
118 "validating peer number %u with identity %s and address %s %u %s\n",
119 num,
120 GNUNET_i2s (peer),
121 addr_and_port,
122 *broadcast,
123 pos_prefix->address_prefix);
124 GNUNET_TRANSPORT_application_validate ((struct
125 GNUNET_TRANSPORT_ApplicationHandle
126 *) ah,
127 peer,
128 nt,
129 addr_and_port);
130 GNUNET_free (peer);
131 GNUNET_free (addr);
132 GNUNET_free (addr_and_port);
133 }
134 }
135 }
136 cps->con_num = con_num;
137}
138
139
140/**
141 * Callback from start peer cmd for signaling a peer got connected.
142 *
143 */
144static void *
145notify_connect (struct GNUNET_TESTING_Interpreter *is,
146 const struct GNUNET_PeerIdentity *peer)
147{
148 const struct GNUNET_TESTING_Command *cmd;
149 struct ConnectPeersState *cps;
150 struct GNUNET_PeerIdentity *peer_connection;
151 struct GNUNET_TESTING_NodeConnection *pos_connection;
152 unsigned int num;
153 unsigned int con_num;
154 void *ret = NULL;
155
156 cmd = GNUNET_TESTING_interpreter_lookup_command_all (is,
157 "connect-peers");
158 cps = cmd->cls;
159 con_num = cps->con_num_notified;
160 for (pos_connection = cps->node_connections_head; NULL != pos_connection;
161 pos_connection = pos_connection->next)
162 {
163 num = GNUNET_TESTING_calculate_num (pos_connection, cps->topology);
164 peer_connection = GNUNET_TESTING_get_pub_key (num, cps->tl_system);
165 if (0 == GNUNET_memcmp (peer,
166 peer_connection))
167 cps->con_num_notified++;
168 GNUNET_free (peer_connection);
169 }
170 if (cps->con_num == con_num)
171 cps->additional_connects_notified++;
172
173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
174 "con_num: %u add: %u num_notified: %u add_notified: %u\n",
175 cps->con_num,
176 cps->additional_connects,
177 cps->con_num_notified,
178 cps->additional_connects_notified);
179 if (cps->con_num + cps->additional_connects == cps->con_num_notified
180 + cps->additional_connects_notified)
181 {
182 GNUNET_TESTING_async_finish (&cps->ac);
183 }
184 return ret;
185}
186
187
188/**
189 * The cleanup function of this cmd frees resources the cmd allocated.
190 *
191 */
192static void
193connect_peers_cleanup (void *cls)
194{
195 struct ConnectPeersState *cps = cls;
196
197 GNUNET_free (cps);
198}
199
200
201/**
202 * This function prepares an array with traits.
203 *
204 */
205enum GNUNET_GenericReturnValue
206connect_peers_traits (void *cls,
207 const void **ret,
208 const char *trait,
209 unsigned int index)
210{
211 struct ConnectPeersState *cps = cls;
212 struct GNUNET_TESTING_Trait traits[] = {
213 GNUNET_TRANSPORT_make_trait_connect_peer_state ((const void *) cps),
214 GNUNET_TESTING_trait_end ()
215 };
216 return GNUNET_TESTING_get_trait (traits,
217 ret,
218 trait,
219 index);
220}
221
222
223/**
224 * Create command
225 *
226 * @param label name for command
227 * @param start_peer_label Label of the cmd to start a peer.
228 * @param create_peer_label Label of the cmd which started the test system.
229 * @param num Number globally identifying the node.
230 * @param The topology for the test setup.
231 * @param additional_connects Number of additional connects this cmd will wait for not triggered by this cmd.
232 * @return command.
233 */
234struct GNUNET_TESTING_Command
235GNUNET_TRANSPORT_cmd_connect_peers (const char *label,
236 const char *start_peer_label,
237 const char *create_label,
238 uint32_t num,
239 struct GNUNET_TESTING_NetjailTopology *
240 topology,
241 unsigned int additional_connects)
242{
243 struct ConnectPeersState *cps;
244
245 cps = GNUNET_new (struct ConnectPeersState);
246 cps->start_peer_label = start_peer_label;
247 cps->num = num;
248 cps->create_label = create_label;
249 cps->topology = topology;
250 cps->notify_connect = notify_connect;
251 cps->additional_connects = additional_connects;
252
253 {
254 struct GNUNET_TESTING_Command cmd = {
255 .cls = cps,
256 .label = label,
257 .run = &connect_peers_run,
258 .ac = &cps->ac,
259 .cleanup = &connect_peers_cleanup,
260 .traits = &connect_peers_traits
261 };
262
263 return cmd;
264 }
265}
diff --git a/src/transport/transport_api_cmd_send_simple.c b/src/transport/transport_api_cmd_send_simple.c
deleted file mode 100644
index ade0cc914..000000000
--- a/src/transport/transport_api_cmd_send_simple.c
+++ /dev/null
@@ -1,212 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_start_peer.c
23 * @brief cmd to start a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testing_netjail_lib.h"
30#include "transport-testing2.h"
31#include "transport-testing-cmds.h"
32
33/**
34 * Generic logging shortcut
35 */
36#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
37
38/**
39 * Struct to hold information for callbacks.
40 *
41 */
42struct SendSimpleState
43{
44 /**
45 * Number globally identifying the node.
46 *
47 */
48 uint32_t num;
49
50 /**
51 * Label of the cmd to start a peer.
52 *
53 */
54 const char *start_peer_label;
55
56 /**
57 * Label of the cmd which started the test system.
58 *
59 */
60 const char *create_label;
61
62 /**
63 * The topology we get the connected nodes from.
64 */
65 struct GNUNET_TESTING_NetjailTopology *topology;
66};
67
68
69/**
70 * The cleanup function of this cmd frees resources the cmd allocated.
71 *
72 */
73static void
74send_simple_cleanup (void *cls)
75{
76 struct SendSimpleState *sss = cls;
77
78 GNUNET_free (sss);
79}
80
81
82static int
83send_simple_cb (void *cls,
84 const struct GNUNET_ShortHashCode *key,
85 void *value)
86{
87 struct SendSimpleState *sss = cls;
88 struct GNUNET_MQ_Handle *mq = value;
89 struct GNUNET_MQ_Envelope *env;
90 struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
91
92 LOG (GNUNET_ERROR_TYPE_DEBUG,
93 "Sending simple test message\n");
94
95 env = GNUNET_MQ_msg_extra (test,
96 1000 - sizeof(*test),
97 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE);
98 test->num = htonl (sss->num);
99 memset (&test[1],
100 sss->num,
101 1000 - sizeof(*test));
102 GNUNET_MQ_send (mq,
103 env);
104 return GNUNET_OK;
105}
106
107
108/**
109 * The run method of this cmd will send a simple message to the connected peers.
110 *
111 */
112static void
113send_simple_run (void *cls,
114 struct GNUNET_TESTING_Interpreter *is)
115{
116 struct SendSimpleState *sss = cls;
117 const struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
118 const struct GNUNET_TESTING_Command *peer1_cmd;
119 // struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
120 struct GNUNET_HashCode hc;
121 struct GNUNET_TESTING_NodeConnection *node_connections_head;
122 struct GNUNET_PeerIdentity *peer;
123 struct GNUNET_CRYPTO_EddsaPublicKey public_key;
124 uint32_t num;
125 struct GNUNET_TESTING_NodeConnection *pos_connection;
126 const struct GNUNET_TESTING_Command *system_cmd;
127 const struct GNUNET_TESTING_System *tl_system;
128
129 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
130 sss->start_peer_label);
131 GNUNET_TRANSPORT_get_trait_connected_peers_map (peer1_cmd,
132 &connected_peers_map);
133
134 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
135 sss->create_label);
136 GNUNET_TESTING_get_trait_test_system (system_cmd,
137 &tl_system);
138
139 node_connections_head = GNUNET_TESTING_get_connections (sss->num,
140 sss->topology);
141
142 GNUNET_CONTAINER_multishortmap_iterate (
143 (struct GNUNET_CONTAINER_MultiShortmap *)
144 connected_peers_map, send_simple_cb,
145 sss);
146 /*for (int i = 0; i < 1; i++)
147 {
148 for (pos_connection = node_connections_head; NULL != pos_connection;
149 pos_connection = pos_connection->next)
150 {
151 num = GNUNET_TESTING_calculate_num (pos_connection, sss->topology);
152 peer = GNUNET_TESTING_get_pub_key (num, tl_system);
153 public_key = peer->public_key;
154 GNUNET_CRYPTO_hash (&public_key, sizeof(public_key), &hc);
155
156 memcpy (key,
157 &hc,
158 sizeof (*key));
159 mq = GNUNET_CONTAINER_multishortmap_get (connected_peers_map,
160 key);
161 env = GNUNET_MQ_msg_extra (test,
162 1000 - sizeof(*test),
163 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE);
164 test->num = htonl (sss->num);
165 memset (&test[1],
166 sss->num,
167 1000 - sizeof(*test));
168 GNUNET_MQ_send (mq,
169 env);
170 }
171 }*/
172
173 // GNUNET_free (key);
174
175}
176
177
178/**
179 * Create command.
180 *
181 * @param label name for command.
182 * @param start_peer_label Label of the cmd to start a peer.
183 * @param start_peer_label Label of the cmd which started the test system.
184 * @param num Number globally identifying the node.
185 * @param The topology for the test setup.
186 * @return command.
187 */
188struct GNUNET_TESTING_Command
189GNUNET_TRANSPORT_cmd_send_simple (const char *label,
190 const char *start_peer_label,
191 const char *create_label,
192 uint32_t num,
193 struct GNUNET_TESTING_NetjailTopology *
194 topology)
195{
196 struct SendSimpleState *sss;
197
198 sss = GNUNET_new (struct SendSimpleState);
199 sss->num = num;
200 sss->start_peer_label = start_peer_label;
201 sss->create_label = create_label;
202 sss->topology = topology;
203
204 struct GNUNET_TESTING_Command cmd = {
205 .cls = sss,
206 .label = label,
207 .run = &send_simple_run,
208 .cleanup = &send_simple_cleanup
209 };
210
211 return cmd;
212}
diff --git a/src/transport/transport_api_cmd_start_peer.c b/src/transport/transport_api_cmd_start_peer.c
deleted file mode 100644
index 7448eff5a..000000000
--- a/src/transport/transport_api_cmd_start_peer.c
+++ /dev/null
@@ -1,491 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_start_peer.c
23 * @brief cmd to start a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testing_netjail_lib.h"
30#include "gnunet_peerstore_service.h"
31#include "gnunet_transport_core_service.h"
32#include "gnunet_transport_application_service.h"
33#include "transport-testing-cmds.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40
41static void
42retrieve_hello (void *cls);
43
44
45/**
46 * Callback delivering the hello of this peer from peerstore.
47 *
48 */
49static void
50hello_iter_cb (void *cb_cls,
51 const struct GNUNET_PEERSTORE_Record *record,
52 const char *emsg)
53{
54 struct StartPeerState *sps = cb_cls;
55 if (NULL == record)
56 {
57 sps->pic = NULL;
58 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
59 return;
60 }
61 // Check record type et al?
62 sps->hello_size = record->value_size;
63 sps->hello = GNUNET_malloc (sps->hello_size);
64 memcpy (sps->hello, record->value, sps->hello_size);
65 sps->hello[sps->hello_size - 1] = '\0';
66
67 GNUNET_PEERSTORE_iterate_cancel (sps->pic);
68 sps->pic = NULL;
69 GNUNET_TESTING_async_finish (&sps->ac);
70}
71
72
73/**
74 * Function to start the retrieval task to retrieve the hello of this peer
75 * from the peerstore.
76 *
77 */
78static void
79retrieve_hello (void *cls)
80{
81 struct StartPeerState *sps = cls;
82 sps->rh_task = NULL;
83 sps->pic = GNUNET_PEERSTORE_iterate (sps->ph,
84 "transport",
85 &sps->id,
86 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
87 hello_iter_cb,
88 sps);
89
90}
91
92
93/**
94 * Disconnect callback for the connection to the core service.
95 *
96 */
97static void
98notify_disconnect (void *cls,
99 const struct GNUNET_PeerIdentity *peer,
100 void *handler_cls)
101{
102 struct StartPeerState *sps = cls;
103
104 LOG (GNUNET_ERROR_TYPE_DEBUG,
105 "Peer %s disconnected from peer %u (`%s')\n",
106 GNUNET_i2s (peer),
107 sps->no,
108 GNUNET_i2s (&sps->id));
109
110}
111
112
113/**
114 * Connect callback for the connection to the core service.
115 *
116 */
117static void *
118notify_connect (void *cls,
119 const struct GNUNET_PeerIdentity *peer,
120 struct GNUNET_MQ_Handle *mq)
121{
122 struct StartPeerState *sps = cls;
123 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
124 struct GNUNET_HashCode hc;
125 struct GNUNET_CRYPTO_EddsaPublicKey public_key = peer->public_key;
126
127 void *ret = (struct GNUNET_PeerIdentity *) peer;
128
129 LOG (GNUNET_ERROR_TYPE_DEBUG,
130 "This Peer %s \n",
131 GNUNET_i2s (&sps->id));
132 LOG (GNUNET_ERROR_TYPE_DEBUG,
133 "Peer %s connected to peer number %u\n",
134 GNUNET_i2s (peer),
135 sps->no);
136
137 GNUNET_CRYPTO_hash (&public_key, sizeof(public_key), &hc);
138
139
140 memcpy (key,
141 &hc,
142 sizeof (*key));
143 GNUNET_CONTAINER_multishortmap_put (sps->connected_peers_map,
144 key,
145 mq,
146 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
147
148 GNUNET_free (key);
149
150 sps->notify_connect (sps->ac.is,
151 peer);
152
153 return ret;
154}
155
156
157/**
158 * The run method of this cmd will start all services of a peer to test the transport service.
159 *
160 */
161static void
162start_peer_run (void *cls,
163 struct GNUNET_TESTING_Interpreter *is)
164{
165 struct StartPeerState *sps = cls;
166 char *emsg = NULL;
167 struct GNUNET_PeerIdentity dummy;
168 const struct GNUNET_TESTING_Command *system_cmd;
169 const struct GNUNET_TESTING_System *tl_system;
170 char *home;
171 char *transport_unix_path;
172 char *tcp_communicator_unix_path;
173 char *udp_communicator_unix_path;
174 char *bindto;
175 char *bindto_udp;
176
177 if (GNUNET_NO == GNUNET_DISK_file_test (sps->cfgname))
178 {
179 LOG (GNUNET_ERROR_TYPE_ERROR,
180 "File not found: `%s'\n",
181 sps->cfgname);
182 GNUNET_TESTING_interpreter_fail (is);
183 return;
184 }
185
186
187 sps->cfg = GNUNET_CONFIGURATION_create ();
188 GNUNET_assert (GNUNET_OK ==
189 GNUNET_CONFIGURATION_load (sps->cfg, sps->cfgname));
190
191 GNUNET_asprintf (&home,
192 "$GNUNET_TMP/test-transport/api-tcp-p%u",
193 sps->no);
194
195 GNUNET_asprintf (&transport_unix_path,
196 "$GNUNET_RUNTIME_DIR/tng-p%u.sock",
197 sps->no);
198
199 GNUNET_asprintf (&tcp_communicator_unix_path,
200 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
201 sps->no);
202
203 GNUNET_asprintf (&udp_communicator_unix_path,
204 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
205 sps->no);
206
207 GNUNET_asprintf (&bindto,
208 "%s:60002",
209 sps->node_ip);
210
211 GNUNET_asprintf (&bindto_udp,
212 "2086");
213
214 LOG (GNUNET_ERROR_TYPE_DEBUG,
215 "node_ip %s\n",
216 bindto);
217
218 LOG (GNUNET_ERROR_TYPE_DEBUG,
219 "bind_udp %s\n",
220 GNUNET_YES == sps->broadcast ?
221 bindto_udp : bindto);
222
223 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "PATHS", "GNUNET_TEST_HOME",
224 home);
225 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "transport", "UNIXPATH",
226 transport_unix_path);
227 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
228 "BINDTO",
229 bindto);
230 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-udp",
231 "BINDTO",
232 GNUNET_YES == sps->broadcast ?
233 bindto_udp : bindto);
234 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
235 "UNIXPATH",
236 tcp_communicator_unix_path);
237 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-udp",
238 "UNIXPATH",
239 udp_communicator_unix_path);
240
241 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
242 sps->system_label);
243 GNUNET_TESTING_get_trait_test_system (system_cmd,
244 &tl_system);
245
246 sps->tl_system = tl_system;
247
248 LOG (GNUNET_ERROR_TYPE_DEBUG,
249 "Creating testing library with key number %u\n",
250 sps->no);
251
252 if (GNUNET_SYSERR ==
253 GNUNET_TESTING_configuration_create ((struct
254 GNUNET_TESTING_System *) tl_system,
255 sps->cfg))
256 {
257 LOG (GNUNET_ERROR_TYPE_DEBUG,
258 "Testing library failed to create unique configuration based on `%s'\n",
259 sps->cfgname);
260 GNUNET_CONFIGURATION_destroy (sps->cfg);
261 GNUNET_TESTING_interpreter_fail (is);
262 return;
263 }
264
265 sps->peer = GNUNET_TESTING_peer_configure ((struct
266 GNUNET_TESTING_System *) sps->
267 tl_system,
268 sps->cfg,
269 sps->no,
270 NULL,
271 &emsg);
272 if (NULL == sps->peer)
273 {
274 LOG (GNUNET_ERROR_TYPE_ERROR,
275 "Testing library failed to create unique configuration based on `%s': `%s' with key number %u\n",
276 sps->cfgname,
277 emsg,
278 sps->no);
279 GNUNET_free (emsg);
280 GNUNET_TESTING_interpreter_fail (is);
281 return;
282 }
283
284 if (GNUNET_OK != GNUNET_TESTING_peer_start (sps->peer))
285 {
286 LOG (GNUNET_ERROR_TYPE_ERROR,
287 "Testing library failed to create unique configuration based on `%s'\n",
288 sps->cfgname);
289 GNUNET_free (emsg);
290 GNUNET_TESTING_interpreter_fail (is);
291 return;
292 }
293
294 memset (&dummy,
295 '\0',
296 sizeof(dummy));
297
298 GNUNET_TESTING_peer_get_identity (sps->peer,
299 &sps->id);
300
301 if (0 == memcmp (&dummy,
302 &sps->id,
303 sizeof(struct GNUNET_PeerIdentity)))
304 {
305 LOG (GNUNET_ERROR_TYPE_ERROR,
306 "Testing library failed to obtain peer identity for peer %u\n",
307 sps->no);
308 GNUNET_free (emsg);
309 GNUNET_TESTING_interpreter_fail (is);
310 return;
311 }
312 LOG (GNUNET_ERROR_TYPE_DEBUG,
313 "Peer %u configured with identity `%s'\n",
314 sps->no,
315 GNUNET_i2s_full (&sps->id));
316
317 sps->th = GNUNET_TRANSPORT_core_connect (sps->cfg,
318 NULL,
319 sps->handlers,
320 sps,
321 &notify_connect,
322 &notify_disconnect);
323 if (NULL == sps->th)
324 {
325 LOG (GNUNET_ERROR_TYPE_ERROR,
326 "Failed to connect to transport service for peer `%s': `%s'\n",
327 sps->cfgname,
328 emsg);
329 GNUNET_free (emsg);
330 GNUNET_TESTING_interpreter_fail (is);
331 return;
332 }
333
334 sps->ph = GNUNET_PEERSTORE_connect (sps->cfg);
335 if (NULL == sps->th)
336 {
337 LOG (GNUNET_ERROR_TYPE_ERROR,
338 "Failed to connect to peerstore service for peer `%s': `%s'\n",
339 sps->cfgname,
340 emsg);
341 GNUNET_free (emsg);
342 GNUNET_TESTING_interpreter_fail (is);
343 return;
344 }
345
346 sps->ah = GNUNET_TRANSPORT_application_init (sps->cfg);
347 if (NULL == sps->ah)
348 {
349 LOG (GNUNET_ERROR_TYPE_ERROR,
350 "Failed to initialize the TRANSPORT application suggestion client handle for peer `%s': `%s'\n",
351 sps->cfgname,
352 emsg);
353 GNUNET_free (emsg);
354 GNUNET_TESTING_interpreter_fail (is);
355 return;
356 }
357 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
358 GNUNET_free (home);
359 GNUNET_free (transport_unix_path);
360 GNUNET_free (tcp_communicator_unix_path);
361 GNUNET_free (udp_communicator_unix_path);
362 GNUNET_free (bindto);
363 GNUNET_free (bindto_udp);
364}
365
366
367/**
368 * The cleanup function of this cmd frees resources the cmd allocated.
369 *
370 */
371static void
372start_peer_cleanup (void *cls)
373{
374 struct StartPeerState *sps = cls;
375
376 if (NULL != sps->handlers)
377 {
378 GNUNET_free (sps->handlers);
379 sps->handlers = NULL;
380 }
381 if (NULL != sps->cfg)
382 {
383 GNUNET_CONFIGURATION_destroy (sps->cfg);
384 sps->cfg = NULL;
385 }
386 GNUNET_free (sps->hello);
387 GNUNET_free (sps->connected_peers_map);
388 GNUNET_free (sps);
389}
390
391
392/**
393 * This function prepares an array with traits.
394 *
395 */
396static int
397start_peer_traits (void *cls,
398 const void **ret,
399 const char *trait,
400 unsigned int index)
401{
402 struct StartPeerState *sps = cls;
403 struct GNUNET_TRANSPORT_ApplicationHandle *ah = sps->ah;
404 struct GNUNET_PeerIdentity *id = &sps->id;
405 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
406 sps->connected_peers_map;
407 char *hello = sps->hello;
408 size_t hello_size = sps->hello_size;
409
410
411 struct GNUNET_TESTING_Trait traits[] = {
412 GNUNET_TRANSPORT_make_trait_application_handle ((const void *) ah),
413 GNUNET_TRANSPORT_make_trait_peer_id ((const void *) id),
414 GNUNET_TRANSPORT_make_trait_connected_peers_map ((const
415 void *)
416 connected_peers_map),
417 GNUNET_TRANSPORT_make_trait_hello ((const void *) hello),
418 GNUNET_TRANSPORT_make_trait_hello_size ((const void *) hello_size),
419 GNUNET_TRANSPORT_make_trait_state ((const void *) sps),
420 GNUNET_TRANSPORT_make_trait_broadcast ((const void *) &sps->broadcast),
421 GNUNET_TESTING_trait_end ()
422 };
423
424 return GNUNET_TESTING_get_trait (traits,
425 ret,
426 trait,
427 index);
428}
429
430
431/**
432 * Create command.
433 *
434 * @param label name for command.
435 * @param system_label Label of the cmd to setup a test environment.
436 * @param m The number of the local node of the actual network namespace.
437 * @param n The number of the actual namespace.
438 * @param local_m Number of local nodes in each namespace.
439 * @param handlers Handler for messages received by this peer.
440 * @param cfgname Configuration file name for this peer.
441 * @param notify_connect Method which will be called, when a peer connects.
442 * @param broadcast Flag indicating, if broadcast should be switched on.
443 * @return command.
444 */
445struct GNUNET_TESTING_Command
446GNUNET_TRANSPORT_cmd_start_peer (const char *label,
447 const char *system_label,
448 uint32_t no,
449 char *node_ip,
450 struct GNUNET_MQ_MessageHandler *handlers,
451 const char *cfgname,
452 GNUNET_TRANSPORT_notify_connect_cb
453 notify_connect,
454 unsigned int broadcast)
455{
456 struct StartPeerState *sps;
457 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
458 GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO);
459 unsigned int i;
460
461 sps = GNUNET_new (struct StartPeerState);
462 sps->no = no;
463 sps->system_label = system_label;
464 sps->connected_peers_map = connected_peers_map;
465 sps->cfgname = cfgname;
466 sps->node_ip = node_ip;
467 sps->notify_connect = notify_connect;
468 sps->broadcast = broadcast;
469
470 if (NULL != handlers)
471 {
472 for (i = 0; NULL != handlers[i].cb; i++)
473 ;
474 sps->handlers = GNUNET_new_array (i + 1,
475 struct GNUNET_MQ_MessageHandler);
476 GNUNET_memcpy (sps->handlers,
477 handlers,
478 i * sizeof(struct GNUNET_MQ_MessageHandler));
479 }
480
481 struct GNUNET_TESTING_Command cmd = {
482 .cls = sps,
483 .label = label,
484 .run = &start_peer_run,
485 .ac = &sps->ac,
486 .cleanup = &start_peer_cleanup,
487 .traits = &start_peer_traits
488 };
489
490 return cmd;
491}
diff --git a/src/transport/transport_api_cmd_stop_peer.c b/src/transport/transport_api_cmd_stop_peer.c
deleted file mode 100644
index 4ca730add..000000000
--- a/src/transport/transport_api_cmd_stop_peer.c
+++ /dev/null
@@ -1,156 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_stop_peer.c
23 * @brief cmd to stop a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_testing_netjail_lib.h"
30#include "gnunet_peerstore_service.h"
31#include "gnunet_transport_core_service.h"
32#include "gnunet_transport_application_service.h"
33#include "transport-testing-cmds.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40
41/**
42 * Struct to hold information for callbacks.
43 *
44 */
45struct StopPeerState
46{
47 // Label of the cmd to start the peer.
48 const char *start_label;
49};
50
51
52/**
53 * The run method of this cmd will stop all services of a peer which were used to test the transport service.
54 *
55 */
56static void
57stop_peer_run (void *cls,
58 struct GNUNET_TESTING_Interpreter *is)
59{
60 struct StopPeerState *stop_ps = cls;
61 const struct StartPeerState *sps;
62 const struct GNUNET_TESTING_Command *start_cmd;
63
64 start_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
65 stop_ps->start_label);
66 GNUNET_TRANSPORT_get_trait_state (start_cmd,
67 &sps);
68
69 if (NULL != sps->pic)
70 {
71 GNUNET_PEERSTORE_iterate_cancel (sps->pic);
72 }
73 if (NULL != sps->th)
74 {
75 GNUNET_TRANSPORT_core_disconnect (sps->th);
76 }
77 if (NULL != sps->ah)
78 {
79 GNUNET_TRANSPORT_application_done (sps->ah);
80 }
81 if (NULL != sps->ph)
82 {
83 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
84 "Disconnecting from PEERSTORE service\n");
85 GNUNET_PEERSTORE_disconnect (sps->ph, GNUNET_NO);
86 }
87 if (NULL != sps->peer)
88 {
89 if (GNUNET_OK !=
90 GNUNET_TESTING_peer_stop (sps->peer))
91 {
92 LOG (GNUNET_ERROR_TYPE_ERROR,
93 "Testing lib failed to stop peer %u (`%s')\n",
94 sps->no,
95 GNUNET_i2s (&sps->id));
96 }
97 GNUNET_TESTING_peer_destroy (sps->peer);
98 }
99 if (NULL != sps->rh_task)
100 GNUNET_SCHEDULER_cancel (sps->rh_task);
101}
102
103
104/**
105 * The cleanup function of this cmd frees resources the cmd allocated.
106 *
107 */
108static void
109stop_peer_cleanup (void *cls)
110{
111 struct StopPeerState *sps = cls;
112
113 GNUNET_free (sps);
114}
115
116
117/**
118 * Trait function of this cmd does nothing.
119 *
120 */
121static int
122stop_peer_traits (void *cls,
123 const void **ret,
124 const char *trait,
125 unsigned int index)
126{
127 return GNUNET_OK;
128}
129
130
131/**
132 * Create command.
133 *
134 * @param label name for command.
135 * @param start_label Label of the cmd to start the peer.
136 * @return command.
137 */
138struct GNUNET_TESTING_Command
139GNUNET_TRANSPORT_cmd_stop_peer (const char *label,
140 const char *start_label)
141{
142 struct StopPeerState *sps;
143
144 sps = GNUNET_new (struct StopPeerState);
145 sps->start_label = start_label;
146 {
147 struct GNUNET_TESTING_Command cmd = {
148 .cls = sps,
149 .label = label,
150 .run = &stop_peer_run,
151 .cleanup = &stop_peer_cleanup,
152 .traits = &stop_peer_traits
153 };
154 return cmd;
155 }
156}
diff --git a/src/transport/transport_api_core.c b/src/transport/transport_api_core.c
deleted file mode 100644
index 0ffaeb444..000000000
--- a/src/transport/transport_api_core.c
+++ /dev/null
@@ -1,968 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_core.c
23 * @brief library to access the transport service for message exchange
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_protocols.h"
32#include "gnunet_transport_service.h"
33#include "transport.h"
34
35#define LOG(kind, ...) GNUNET_log_from (kind, "transport-api-core", __VA_ARGS__)
36
37/**
38 * If we could not send any payload to a peer for this amount of
39 * time, we print a warning.
40 */
41#define UNREADY_WARN_TIME GNUNET_TIME_UNIT_MINUTES
42
43/**
44 * How large to start with for the hashmap of neighbours.
45 */
46#define STARTING_NEIGHBOURS_SIZE 16
47
48
49/**
50 * Entry in hash table of all of our current (connected) neighbours.
51 */
52struct Neighbour
53{
54 /**
55 * Overall transport handle.
56 */
57 struct GNUNET_TRANSPORT_CoreHandle *h;
58
59 /**
60 * Active message queue for the peer.
61 */
62 struct GNUNET_MQ_Handle *mq;
63
64 /**
65 * Envelope with the message we are currently transmitting (or NULL).
66 */
67 struct GNUNET_MQ_Envelope *env;
68
69 /**
70 * Closure for @e mq handlers.
71 */
72 void *handlers_cls;
73
74 /**
75 * Identity of this neighbour.
76 */
77 struct GNUNET_PeerIdentity id;
78
79 /**
80 * Outbound bandwidh tracker.
81 */
82 struct GNUNET_BANDWIDTH_Tracker out_tracker;
83
84 /**
85 * Entry in our readiness heap (which is sorted by @e next_ready
86 * value). NULL if there is no pending transmission request for
87 * this neighbour or if we're waiting for @e is_ready to become
88 * true AFTER the @e out_tracker suggested that this peer's quota
89 * has been satisfied (so once @e is_ready goes to #GNUNET_YES,
90 * we should immediately go back into the heap).
91 */
92 struct GNUNET_CONTAINER_HeapNode *hn;
93
94 /**
95 * Task to trigger MQ when we have enough bandwidth for the
96 * next transmission.
97 */
98 struct GNUNET_SCHEDULER_Task *timeout_task;
99
100 /**
101 * Sending consumed more bytes on wire than payload was announced
102 * This overhead is added to the delay of next sending operation
103 */
104 unsigned long long traffic_overhead;
105
106 /**
107 * Is this peer currently ready to receive a message?
108 */
109 int is_ready;
110
111 /**
112 * Size of the message in @e env.
113 */
114 uint16_t env_size;
115};
116
117
118/**
119 * Handle for the transport service (includes all of the
120 * state for the transport service).
121 */
122struct GNUNET_TRANSPORT_CoreHandle
123{
124 /**
125 * Closure for the callbacks.
126 */
127 void *cls;
128
129 /**
130 * Functions to call for received data (template for
131 * new message queues).
132 */
133 struct GNUNET_MQ_MessageHandler *handlers;
134
135 /**
136 * function to call on connect events
137 */
138 GNUNET_TRANSPORT_NotifyConnect nc_cb;
139
140 /**
141 * function to call on disconnect events
142 */
143 GNUNET_TRANSPORT_NotifyDisconnect nd_cb;
144
145 /**
146 * function to call on excess bandwidth events
147 */
148 GNUNET_TRANSPORT_NotifyExcessBandwidth neb_cb;
149
150 /**
151 * My client connection to the transport service.
152 */
153 struct GNUNET_MQ_Handle *mq;
154
155 /**
156 * My configuration.
157 */
158 const struct GNUNET_CONFIGURATION_Handle *cfg;
159
160 /**
161 * Hash map of the current connected neighbours of this peer.
162 * Maps peer identities to `struct Neighbour` entries.
163 */
164 struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
165
166 /**
167 * Peer identity as assumed by this process, or all zeros.
168 */
169 struct GNUNET_PeerIdentity self;
170
171 /**
172 * ID of the task trying to reconnect to the service.
173 */
174 struct GNUNET_SCHEDULER_Task *reconnect_task;
175
176 /**
177 * Delay until we try to reconnect.
178 */
179 struct GNUNET_TIME_Relative reconnect_delay;
180
181 /**
182 * Internal counter to check how many more receive OK messages this
183 * CORE service is allowed to send in total. Just to detect easy
184 * cases of protocol violations by the CORE implementation.
185 * NOTE: we may want to make this stronger by counting per peer
186 * instead of globally.
187 */
188 unsigned int rom_pending;
189
190 /**
191 * Should we check that @e self matches what the service thinks?
192 * (if #GNUNET_NO, then @e self is all zeros!).
193 */
194 int check_self;
195};
196
197
198/**
199 * Function that will schedule the job that will try
200 * to connect us again to the client.
201 *
202 * @param h transport service to reconnect
203 */
204static void
205disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h);
206
207
208/**
209 * Get the neighbour list entry for the given peer
210 *
211 * @param h our context
212 * @param peer peer to look up
213 * @return NULL if no such peer entry exists
214 */
215static struct Neighbour *
216neighbour_find (struct GNUNET_TRANSPORT_CoreHandle *h,
217 const struct GNUNET_PeerIdentity *peer)
218{
219 return GNUNET_CONTAINER_multipeermap_get (h->neighbours, peer);
220}
221
222
223/**
224 * Function called by the bandwidth tracker if we have excess
225 * bandwidth.
226 *
227 * @param cls the `struct Neighbour` that has excess bandwidth
228 */
229static void
230notify_excess_cb (void *cls)
231{
232 struct Neighbour *n = cls;
233 struct GNUNET_TRANSPORT_CoreHandle *h = n->h;
234
235 LOG (GNUNET_ERROR_TYPE_DEBUG,
236 "Notifying CORE that more bandwidth is available for %s\n",
237 GNUNET_i2s (&n->id));
238
239 if (NULL != h->neb_cb)
240 h->neb_cb (h->cls, &n->id, n->handlers_cls);
241}
242
243
244/**
245 * Iterator over hash map entries, for deleting state of a neighbour.
246 *
247 * @param cls the `struct GNUNET_TRANSPORT_CoreHandle *`
248 * @param key peer identity
249 * @param value value in the hash map, the neighbour entry to delete
250 * @return #GNUNET_YES if we should continue to
251 * iterate,
252 * #GNUNET_NO if not.
253 */
254static int
255neighbour_delete (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
256{
257 struct GNUNET_TRANSPORT_CoreHandle *handle = cls;
258 struct Neighbour *n = value;
259
260 LOG (GNUNET_ERROR_TYPE_DEBUG,
261 "Dropping entry for neighbour `%s'.\n",
262 GNUNET_i2s (key));
263 GNUNET_BANDWIDTH_tracker_notification_stop (&n->out_tracker);
264 if (NULL != handle->nd_cb)
265 handle->nd_cb (handle->cls, &n->id, n->handlers_cls);
266 if (NULL != n->timeout_task)
267 {
268 GNUNET_SCHEDULER_cancel (n->timeout_task);
269 n->timeout_task = NULL;
270 }
271 if (NULL != n->env)
272 {
273 GNUNET_MQ_send_cancel (n->env);
274 n->env = NULL;
275 }
276 GNUNET_MQ_destroy (n->mq);
277 GNUNET_assert (NULL == n->mq);
278 GNUNET_assert (
279 GNUNET_YES ==
280 GNUNET_CONTAINER_multipeermap_remove (handle->neighbours, key, n));
281 GNUNET_free (n);
282 return GNUNET_YES;
283}
284
285
286/**
287 * Generic error handler, called with the appropriate
288 * error code and the same closure specified at the creation of
289 * the message queue.
290 * Not every message queue implementation supports an error handler.
291 *
292 * @param cls closure with the `struct GNUNET_TRANSPORT_CoreHandle *`
293 * @param error error code
294 */
295static void
296mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
297{
298 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
299
300 LOG (GNUNET_ERROR_TYPE_ERROR,
301 "Error receiving from transport service (%d), disconnecting temporarily.\n",
302 error);
303 disconnect_and_schedule_reconnect (h);
304}
305
306
307/**
308 * Function we use for checking incoming HELLO messages.
309 *
310 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
311 * @param msg message received
312 * @return #GNUNET_OK if message is well-formed
313 */
314static int
315check_hello (void *cls, const struct GNUNET_MessageHeader *msg)
316{
317 struct GNUNET_PeerIdentity me;
318
319 if (GNUNET_OK !=
320 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) msg, &me))
321 {
322 GNUNET_break (0);
323 return GNUNET_SYSERR;
324 }
325 return GNUNET_OK;
326}
327
328
329/**
330 * Function we use for handling incoming HELLO messages.
331 *
332 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
333 * @param msg message received
334 */
335static void
336handle_hello (void *cls, const struct GNUNET_MessageHeader *msg)
337{
338 /* we do not care => FIXME: signal in options to NEVER send HELLOs! */
339}
340
341
342/**
343 * A message from the handler's message queue to a neighbour was
344 * transmitted. Now trigger (possibly delayed) notification of the
345 * neighbour's message queue that we are done and thus ready for
346 * the next message.
347 *
348 * @param cls the `struct Neighbour` where the message was sent
349 */
350static void
351notify_send_done_fin (void *cls)
352{
353 struct Neighbour *n = cls;
354
355 n->timeout_task = NULL;
356 n->is_ready = GNUNET_YES;
357 GNUNET_MQ_impl_send_continue (n->mq);
358}
359
360
361/**
362 * A message from the handler's message queue to a neighbour was
363 * transmitted. Now trigger (possibly delayed) notification of the
364 * neighbour's message queue that we are done and thus ready for
365 * the next message.
366 *
367 * @param cls the `struct Neighbour` where the message was sent
368 */
369static void
370notify_send_done (void *cls)
371{
372 struct Neighbour *n = cls;
373 struct GNUNET_TIME_Relative delay;
374
375 n->timeout_task = NULL;
376 if (NULL != n->env)
377 {
378 GNUNET_BANDWIDTH_tracker_consume (&n->out_tracker,
379 n->env_size + n->traffic_overhead);
380 n->env = NULL;
381 n->traffic_overhead = 0;
382 }
383 delay = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, 128);
384 if (0 == delay.rel_value_us)
385 {
386 n->is_ready = GNUNET_YES;
387 GNUNET_MQ_impl_send_continue (n->mq);
388 return;
389 }
390 GNUNET_MQ_impl_send_in_flight (n->mq);
391 /* cannot send even a small message without violating
392 quota, wait a before allowing MQ to send next message */
393 n->timeout_task =
394 GNUNET_SCHEDULER_add_delayed (delay, &notify_send_done_fin, n);
395}
396
397
398/**
399 * Implement sending functionality of a message queue.
400 * Called one message at a time. Should send the @a msg
401 * to the transport service and then notify the queue
402 * once we are ready for the next one.
403 *
404 * @param mq the message queue
405 * @param msg the message to send
406 * @param impl_state state of the implementation
407 */
408static void
409mq_send_impl (struct GNUNET_MQ_Handle *mq,
410 const struct GNUNET_MessageHeader *msg,
411 void *impl_state)
412{
413 struct Neighbour *n = impl_state;
414 struct GNUNET_TRANSPORT_CoreHandle *h = n->h;
415 struct OutboundMessage *obm;
416 uint16_t msize;
417
418 GNUNET_assert (GNUNET_YES == n->is_ready);
419 msize = ntohs (msg->size);
420 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(*obm))
421 {
422 GNUNET_break (0);
423 GNUNET_MQ_impl_send_continue (mq);
424 return;
425 }
426 GNUNET_assert (NULL == n->env);
427 n->env =
428 GNUNET_MQ_msg_nested_mh (obm, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, msg);
429 {
430 struct GNUNET_MQ_Envelope *env;
431
432 env = GNUNET_MQ_get_current_envelope (mq);
433 obm->priority = htonl ((uint32_t) GNUNET_MQ_env_get_options (env));
434 }
435 obm->timeout = GNUNET_TIME_relative_hton (
436 GNUNET_TIME_UNIT_MINUTES); /* FIXME: to be removed */
437 obm->peer = n->id;
438 GNUNET_assert (NULL == n->timeout_task);
439 n->is_ready = GNUNET_NO;
440 n->env_size = ntohs (msg->size);
441 GNUNET_MQ_notify_sent (n->env, &notify_send_done, n);
442 GNUNET_MQ_send (h->mq, n->env);
443 LOG (GNUNET_ERROR_TYPE_DEBUG,
444 "Queued message of type %u for neighbour `%s'.\n",
445 ntohs (msg->type),
446 GNUNET_i2s (&n->id));
447}
448
449
450/**
451 * Handle destruction of a message queue. Implementations must not
452 * free @a mq, but should take care of @a impl_state.
453 *
454 * @param mq the message queue to destroy
455 * @param impl_state state of the implementation
456 */
457static void
458mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
459{
460 struct Neighbour *n = impl_state;
461
462 GNUNET_assert (mq == n->mq);
463 n->mq = NULL;
464}
465
466
467/**
468 * Implementation function that cancels the currently sent message.
469 * Should basically undo whatever #mq_send_impl() did.
470 *
471 * @param mq message queue
472 * @param impl_state state specific to the implementation
473 */
474static void
475mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
476{
477 struct Neighbour *n = impl_state;
478
479 GNUNET_assert (GNUNET_NO == n->is_ready);
480 if (NULL != n->env)
481 {
482 GNUNET_MQ_send_cancel (n->env);
483 n->env = NULL;
484 }
485
486 n->is_ready = GNUNET_YES;
487}
488
489
490/**
491 * We had an error processing a message we forwarded from a peer to
492 * the CORE service. We should just complain about it but otherwise
493 * continue processing.
494 *
495 * @param cls closure
496 * @param error error code
497 */
498static void
499peer_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
500{
501 /* struct Neighbour *n = cls; */
502
503 GNUNET_break_op (0);
504}
505
506
507/**
508 * The outbound quota has changed in a way that may require
509 * us to reset the timeout. Update the timeout.
510 *
511 * @param cls the `struct Neighbour` for which the timeout changed
512 */
513static void
514outbound_bw_tracker_update (void *cls)
515{
516 struct Neighbour *n = cls;
517 struct GNUNET_TIME_Relative delay;
518
519 if (NULL == n->timeout_task)
520 return;
521 delay = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, 128);
522 GNUNET_SCHEDULER_cancel (n->timeout_task);
523 n->timeout_task = GNUNET_SCHEDULER_add_delayed (delay, &notify_send_done, n);
524}
525
526
527/**
528 * Function we use for handling incoming connect messages.
529 *
530 * @param cls closure, a `struct GNUNET_TRANSPORT_Handle *`
531 * @param cim message received
532 */
533static void
534handle_connect (void *cls, const struct ConnectInfoMessage *cim)
535{
536 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
537 struct Neighbour *n;
538
539 LOG (GNUNET_ERROR_TYPE_DEBUG,
540 "Receiving CONNECT message for `%s' with quota %u\n",
541 GNUNET_i2s (&cim->id),
542 ntohl (cim->quota_out.value__));
543 n = neighbour_find (h, &cim->id);
544 if (NULL != n)
545 {
546 GNUNET_break (0); /* FIXME: this assertion seems to fail sometimes!? */
547 disconnect_and_schedule_reconnect (h);
548 return;
549 }
550 n = GNUNET_new (struct Neighbour);
551 n->id = cim->id;
552 n->h = h;
553 n->is_ready = GNUNET_YES;
554 n->traffic_overhead = 0;
555 GNUNET_BANDWIDTH_tracker_init2 (&n->out_tracker,
556 &outbound_bw_tracker_update,
557 n,
558 GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
559 MAX_BANDWIDTH_CARRY_S,
560 &notify_excess_cb,
561 n);
562 GNUNET_assert (GNUNET_OK ==
563 GNUNET_CONTAINER_multipeermap_put (
564 h->neighbours,
565 &n->id,
566 n,
567 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
568
569 GNUNET_BANDWIDTH_tracker_update_quota (&n->out_tracker, cim->quota_out);
570 n->mq = GNUNET_MQ_queue_for_callbacks (&mq_send_impl,
571 &mq_destroy_impl,
572 &mq_cancel_impl,
573 n,
574 h->handlers,
575 &peer_mq_error_handler,
576 n);
577 if (NULL != h->nc_cb)
578 {
579 n->handlers_cls = h->nc_cb (h->cls, &n->id, n->mq);
580 GNUNET_MQ_set_handlers_closure (n->mq, n->handlers_cls);
581 }
582}
583
584
585/**
586 * Function we use for handling incoming disconnect messages.
587 *
588 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
589 * @param dim message received
590 */
591static void
592handle_disconnect (void *cls, const struct DisconnectInfoMessage *dim)
593{
594 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
595 struct Neighbour *n;
596
597 GNUNET_break (ntohl (dim->reserved) == 0);
598 LOG (GNUNET_ERROR_TYPE_DEBUG,
599 "Receiving DISCONNECT message for `%s'.\n",
600 GNUNET_i2s (&dim->peer));
601 n = neighbour_find (h, &dim->peer);
602 if (NULL == n)
603 {
604 GNUNET_break (0);
605 disconnect_and_schedule_reconnect (h);
606 return;
607 }
608 GNUNET_assert (GNUNET_YES == neighbour_delete (h, &dim->peer, n));
609}
610
611
612/**
613 * Function we use for handling incoming send-ok messages.
614 *
615 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
616 * @param okm message received
617 */
618static void
619handle_send_ok (void *cls, const struct SendOkMessage *okm)
620{
621 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
622 struct Neighbour *n;
623 uint32_t bytes_msg;
624 uint32_t bytes_physical;
625 uint16_t success = ntohs (okm->success);
626
627 bytes_msg = ntohs (okm->bytes_msg);
628 bytes_physical = ntohl (okm->bytes_physical);
629 LOG (GNUNET_ERROR_TYPE_DEBUG,
630 "Receiving SEND_OK message, transmission to %s %s.\n",
631 GNUNET_i2s (&okm->peer),
632 success == GNUNET_OK ? "succeeded" : "failed");
633 n = neighbour_find (h, &okm->peer);
634 if (NULL == n)
635 {
636 /* We should never get a 'SEND_OK' for a peer that we are not
637 connected to */
638 GNUNET_break (0);
639 disconnect_and_schedule_reconnect (h);
640 return;
641 }
642 if (bytes_physical > bytes_msg)
643 {
644 LOG (GNUNET_ERROR_TYPE_DEBUG,
645 "Overhead for %u byte message was %u\n",
646 bytes_msg,
647 bytes_physical - bytes_msg);
648 n->traffic_overhead += bytes_physical - bytes_msg;
649 }
650}
651
652
653/**
654 * Function we use for checking incoming "inbound" messages.
655 *
656 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
657 * @param im message received
658 */
659static int
660check_recv (void *cls, const struct InboundMessage *im)
661{
662 const struct GNUNET_MessageHeader *imm;
663 uint16_t size;
664
665 size = ntohs (im->header.size) - sizeof(*im);
666 if (size < sizeof(struct GNUNET_MessageHeader))
667 {
668 GNUNET_break (0);
669 return GNUNET_SYSERR;
670 }
671 imm = (const struct GNUNET_MessageHeader *) &im[1];
672 if (ntohs (imm->size) != size)
673 {
674 GNUNET_break (0);
675 return GNUNET_SYSERR;
676 }
677 return GNUNET_OK;
678}
679
680
681/**
682 * Function we use for handling incoming messages.
683 *
684 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
685 * @param im message received
686 */
687static void
688handle_recv (void *cls, const struct InboundMessage *im)
689{
690 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
691 const struct GNUNET_MessageHeader *imm =
692 (const struct GNUNET_MessageHeader *) &im[1];
693 struct Neighbour *n;
694
695 LOG (GNUNET_ERROR_TYPE_DEBUG,
696 "Received message of type %u with %u bytes from `%s'.\n",
697 (unsigned int) ntohs (imm->type),
698 (unsigned int) ntohs (imm->size),
699 GNUNET_i2s (&im->peer));
700 n = neighbour_find (h, &im->peer);
701 if (NULL == n)
702 {
703 GNUNET_break (0);
704 disconnect_and_schedule_reconnect (h);
705 return;
706 }
707 h->rom_pending++;
708 GNUNET_MQ_inject_message (n->mq, imm);
709}
710
711
712/**
713 * Function we use for handling incoming set quota messages.
714 *
715 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
716 * @param msg message received
717 */
718static void
719handle_set_quota (void *cls, const struct QuotaSetMessage *qm)
720{
721 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
722 struct Neighbour *n;
723
724 LOG (GNUNET_ERROR_TYPE_DEBUG,
725 "Receiving SET_QUOTA message for `%s' with quota %u\n",
726 GNUNET_i2s (&qm->peer),
727 ntohl (qm->quota.value__));
728 n = neighbour_find (h, &qm->peer);
729 if (NULL == n)
730 {
731 GNUNET_break (
732 0); /* FIXME: julius reports this assertion fails sometimes? */
733 disconnect_and_schedule_reconnect (h);
734 return;
735 }
736 GNUNET_BANDWIDTH_tracker_update_quota (&n->out_tracker, qm->quota);
737}
738
739
740/**
741 * Try again to connect to transport service.
742 *
743 * @param cls the handle to the transport service
744 */
745static void
746reconnect (void *cls)
747{
748 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
749 struct GNUNET_MQ_MessageHandler handlers[] =
750 { GNUNET_MQ_hd_var_size (hello,
751 GNUNET_MESSAGE_TYPE_HELLO,
752 struct GNUNET_MessageHeader,
753 h),
754 GNUNET_MQ_hd_fixed_size (connect,
755 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT,
756 struct ConnectInfoMessage,
757 h),
758 GNUNET_MQ_hd_fixed_size (disconnect,
759 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT,
760 struct DisconnectInfoMessage,
761 h),
762 GNUNET_MQ_hd_fixed_size (send_ok,
763 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK,
764 struct SendOkMessage,
765 h),
766 GNUNET_MQ_hd_var_size (recv,
767 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV,
768 struct InboundMessage,
769 h),
770 GNUNET_MQ_hd_fixed_size (set_quota,
771 GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA,
772 struct QuotaSetMessage,
773 h),
774 GNUNET_MQ_handler_end () };
775 struct GNUNET_MQ_Envelope *env;
776 struct StartMessage *s;
777 uint32_t options;
778
779 h->reconnect_task = NULL;
780 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n");
781 GNUNET_assert (NULL == h->mq);
782 h->mq =
783 GNUNET_CLIENT_connect (h->cfg, "transport", handlers, &mq_error_handler, h);
784 if (NULL == h->mq)
785 return;
786 env = GNUNET_MQ_msg (s, GNUNET_MESSAGE_TYPE_TRANSPORT_START);
787 options = 0;
788 if (h->check_self)
789 options |= 1;
790 if (NULL != h->handlers)
791 options |= 2;
792 s->options = htonl (options);
793 s->self = h->self;
794 GNUNET_MQ_send (h->mq, env);
795}
796
797
798/**
799 * Function that will schedule the job that will try
800 * to connect us again to the client.
801 *
802 * @param h transport service to reconnect
803 */
804static void
805disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h)
806{
807 GNUNET_assert (NULL == h->reconnect_task);
808 /* Forget about all neighbours that we used to be connected to */
809 GNUNET_CONTAINER_multipeermap_iterate (h->neighbours, &neighbour_delete, h);
810 if (NULL != h->mq)
811 {
812 GNUNET_MQ_destroy (h->mq);
813 h->mq = NULL;
814 }
815 LOG (GNUNET_ERROR_TYPE_DEBUG,
816 "Scheduling task to reconnect to transport service in %s.\n",
817 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
818 h->reconnect_task =
819 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
820 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
821}
822
823
824/**
825 * Checks if a given peer is connected to us and get the message queue.
826 *
827 * @param handle connection to transport service
828 * @param peer the peer to check
829 * @return NULL if disconnected, otherwise message queue for @a peer
830 */
831struct GNUNET_MQ_Handle *
832GNUNET_TRANSPORT_core_get_mq (struct GNUNET_TRANSPORT_CoreHandle *handle,
833 const struct GNUNET_PeerIdentity *peer)
834{
835 struct Neighbour *n;
836
837 n = neighbour_find (handle, peer);
838 if (NULL == n)
839 return NULL;
840 return n->mq;
841}
842
843
844/**
845 * Connect to the transport service. Note that the connection may
846 * complete (or fail) asynchronously.
847 *
848 * @param cfg configuration to use
849 * @param self our own identity (API should check that it matches
850 * the identity found by transport), or NULL (no check)
851 * @param cls closure for the callbacks
852 * @param rec receive function to call
853 * @param nc function to call on connect events
854 * @param nd function to call on disconnect events
855 * @param neb function to call if we have excess bandwidth to a peer
856 * @return NULL on error
857 */
858struct GNUNET_TRANSPORT_CoreHandle *
859GNUNET_TRANSPORT_core_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
860 const struct GNUNET_PeerIdentity *self,
861 const struct GNUNET_MQ_MessageHandler *handlers,
862 void *cls,
863 GNUNET_TRANSPORT_NotifyConnect nc,
864 GNUNET_TRANSPORT_NotifyDisconnect nd,
865 GNUNET_TRANSPORT_NotifyExcessBandwidth neb)
866{
867 struct GNUNET_TRANSPORT_CoreHandle *h;
868 unsigned int i;
869
870 h = GNUNET_new (struct GNUNET_TRANSPORT_CoreHandle);
871 if (NULL != self)
872 {
873 h->self = *self;
874 h->check_self = GNUNET_YES;
875 }
876 h->cfg = cfg;
877 h->cls = cls;
878 h->nc_cb = nc;
879 h->nd_cb = nd;
880 h->neb_cb = neb;
881 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
882 if (NULL != handlers)
883 {
884 for (i = 0; NULL != handlers[i].cb; i++)
885 ;
886 h->handlers = GNUNET_new_array (i + 1, struct GNUNET_MQ_MessageHandler);
887 GNUNET_memcpy (h->handlers,
888 handlers,
889 i * sizeof(struct GNUNET_MQ_MessageHandler));
890 }
891 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service\n");
892 reconnect (h);
893 if (NULL == h->mq)
894 {
895 GNUNET_free (h->handlers);
896 GNUNET_free (h);
897 return NULL;
898 }
899 h->neighbours =
900 GNUNET_CONTAINER_multipeermap_create (STARTING_NEIGHBOURS_SIZE, GNUNET_YES);
901 return h;
902}
903
904
905/**
906 * Disconnect from the transport service.
907 *
908 * @param handle handle to the service as returned from
909 * #GNUNET_TRANSPORT_core_connect()
910 */
911void
912GNUNET_TRANSPORT_core_disconnect (struct GNUNET_TRANSPORT_CoreHandle *handle)
913{
914 LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n");
915 /* this disconnects all neighbours... */
916 if (NULL == handle->reconnect_task)
917 disconnect_and_schedule_reconnect (handle);
918 /* and now we stop trying to connect again... */
919 if (NULL != handle->reconnect_task)
920 {
921 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
922 handle->reconnect_task = NULL;
923 }
924 GNUNET_CONTAINER_multipeermap_destroy (handle->neighbours);
925 handle->neighbours = NULL;
926 GNUNET_free (handle->handlers);
927 handle->handlers = NULL;
928 GNUNET_free (handle);
929}
930
931
932/**
933 * Notification from the CORE service to the TRANSPORT service
934 * that the CORE service has finished processing a message from
935 * TRANSPORT (via the @code{handlers} of #GNUNET_TRANSPORT_core_connect())
936 * and that it is thus now OK for TRANSPORT to send more messages
937 * for @a pid.
938 *
939 * Used to provide flow control, this is our equivalent to
940 * #GNUNET_SERVICE_client_continue() of an ordinary service.
941 *
942 * Note that due to the use of a window, TRANSPORT may send multiple
943 * messages destined for the same peer even without an intermediate
944 * call to this function. However, CORE must still call this function
945 * once per message received, as otherwise eventually the window will
946 * be full and TRANSPORT will stop providing messages to CORE for @a
947 * pid.
948 *
949 * @param ch core handle
950 * @param pid which peer was the message from that was fully processed by CORE
951 */
952void
953GNUNET_TRANSPORT_core_receive_continue (struct GNUNET_TRANSPORT_CoreHandle *ch,
954 const struct GNUNET_PeerIdentity *pid)
955{
956 struct RecvOkMessage *rom;
957 struct GNUNET_MQ_Envelope *env;
958
959 GNUNET_assert (ch->rom_pending > 0);
960 ch->rom_pending--;
961 env = GNUNET_MQ_msg (rom, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK);
962 rom->increase_window_delta = htonl (1);
963 rom->peer = *pid;
964 GNUNET_MQ_send (ch->mq, env);
965}
966
967
968/* end of transport_api_core.c */
diff --git a/src/transport/transport_api_hello_get.c b/src/transport/transport_api_hello_get.c
deleted file mode 100644
index f8bcc5f07..000000000
--- a/src/transport/transport_api_hello_get.c
+++ /dev/null
@@ -1,274 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_hello_get.c
23 * @brief library to obtain our HELLO from our transport service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_protocols.h"
32#include "gnunet_transport_hello_service.h"
33#include "transport.h"
34
35
36/**
37 * Functions to call with this peer's HELLO.
38 */
39struct GNUNET_TRANSPORT_HelloGetHandle
40{
41 /**
42 * Our configuration.
43 */
44 const struct GNUNET_CONFIGURATION_Handle *cfg;
45
46 /**
47 * Transport handle.
48 */
49 struct GNUNET_MQ_Handle *mq;
50
51 /**
52 * Callback to call once we got our HELLO.
53 */
54 GNUNET_TRANSPORT_HelloUpdateCallback rec;
55
56 /**
57 * Closure for @e rec.
58 */
59 void *rec_cls;
60
61 /**
62 * Task for calling the HelloUpdateCallback when we already have a HELLO
63 */
64 struct GNUNET_SCHEDULER_Task *notify_task;
65
66 /**
67 * ID of the task trying to reconnect to the service.
68 */
69 struct GNUNET_SCHEDULER_Task *reconnect_task;
70
71 /**
72 * Delay until we try to reconnect.
73 */
74 struct GNUNET_TIME_Relative reconnect_delay;
75
76 /**
77 * Type of HELLOs client cares about.
78 */
79 enum GNUNET_TRANSPORT_AddressClass ac;
80};
81
82
83/**
84 * Function we use for checking incoming HELLO messages.
85 *
86 * @param cls closure, a `struct GNUNET_TRANSPORT_Handle *`
87 * @param msg message received
88 * @return #GNUNET_OK if message is well-formed
89 */
90static int
91check_hello (void *cls,
92 const struct GNUNET_MessageHeader *msg)
93{
94 struct GNUNET_PeerIdentity me;
95
96 if (GNUNET_OK !=
97 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) msg,
98 &me))
99 {
100 GNUNET_break (0);
101 return GNUNET_SYSERR;
102 }
103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
104 "Receiving (my own) HELLO message (%u bytes), I am `%s'.\n",
105 (unsigned int) ntohs (msg->size),
106 GNUNET_i2s (&me));
107 return GNUNET_OK;
108}
109
110
111/**
112 * Function we use for handling incoming HELLO messages.
113 *
114 * @param cls closure, a `struct GNUNET_TRANSPORT_HelloGetHandle *`
115 * @param msg message received
116 */
117static void
118handle_hello (void *cls,
119 const struct GNUNET_MessageHeader *msg)
120{
121 struct GNUNET_TRANSPORT_HelloGetHandle *ghh = cls;
122
123 ghh->rec (ghh->rec_cls,
124 msg);
125}
126
127
128/**
129 * Function that will schedule the job that will try
130 * to connect us again to the client.
131 *
132 * @param ghh transport service to reconnect
133 */
134static void
135schedule_reconnect (struct GNUNET_TRANSPORT_HelloGetHandle *ghh);
136
137
138/**
139 * Generic error handler, called with the appropriate
140 * error code and the same closure specified at the creation of
141 * the message queue.
142 * Not every message queue implementation supports an error handler.
143 *
144 * @param cls closure with the `struct GNUNET_TRANSPORT_Handle *`
145 * @param error error code
146 */
147static void
148mq_error_handler (void *cls,
149 enum GNUNET_MQ_Error error)
150{
151 struct GNUNET_TRANSPORT_HelloGetHandle *ghh = cls;
152
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "Error receiving from transport service, disconnecting temporarily.\n");
155 GNUNET_MQ_destroy (ghh->mq);
156 ghh->mq = NULL;
157 schedule_reconnect (ghh);
158}
159
160
161/**
162 * Try again to connect to transport service.
163 *
164 * @param cls the handle to the transport service
165 */
166static void
167reconnect (void *cls)
168{
169 struct GNUNET_TRANSPORT_HelloGetHandle *ghh = cls;
170 struct GNUNET_MQ_MessageHandler handlers[] = {
171 GNUNET_MQ_hd_var_size (hello,
172 GNUNET_MESSAGE_TYPE_HELLO,
173 struct GNUNET_MessageHeader,
174 ghh),
175 GNUNET_MQ_handler_end ()
176 };
177 struct GNUNET_MQ_Envelope *env;
178 struct StartMessage *s;
179
180 ghh->reconnect_task = NULL;
181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
182 "Connecting to transport service.\n");
183 GNUNET_assert (NULL == ghh->mq);
184 ghh->mq = GNUNET_CLIENT_connect (ghh->cfg,
185 "transport",
186 handlers,
187 &mq_error_handler,
188 ghh);
189 if (NULL == ghh->mq)
190 return;
191 env = GNUNET_MQ_msg (s,
192 GNUNET_MESSAGE_TYPE_TRANSPORT_START);
193 s->options = htonl (0);
194 GNUNET_MQ_send (ghh->mq,
195 env);
196}
197
198
199/**
200 * Function that will schedule the job that will try
201 * to connect us again to the client.
202 *
203 * @param ghh transport service to reconnect
204 */
205static void
206schedule_reconnect (struct GNUNET_TRANSPORT_HelloGetHandle *ghh)
207{
208 ghh->reconnect_task =
209 GNUNET_SCHEDULER_add_delayed (ghh->reconnect_delay,
210 &reconnect,
211 ghh);
212 ghh->reconnect_delay = GNUNET_TIME_STD_BACKOFF (ghh->reconnect_delay);
213}
214
215
216/**
217 * Obtain the HELLO message for this peer. The callback given in this function
218 * is never called synchronously.
219 *
220 * @param cfg configuration
221 * @param ac which network type should the addresses from the HELLO belong to?
222 * @param rec function to call with the HELLO, sender will be our peer
223 * identity; message and sender will be NULL on timeout
224 * (handshake with transport service pending/failed).
225 * cost estimate will be 0.
226 * @param rec_cls closure for @a rec
227 * @return handle to cancel the operation
228 */
229struct GNUNET_TRANSPORT_HelloGetHandle *
230GNUNET_TRANSPORT_hello_get (const struct GNUNET_CONFIGURATION_Handle *cfg,
231 enum GNUNET_TRANSPORT_AddressClass ac,
232 GNUNET_TRANSPORT_HelloUpdateCallback rec,
233 void *rec_cls)
234{
235 struct GNUNET_TRANSPORT_HelloGetHandle *ghh;
236
237 ghh = GNUNET_new (struct GNUNET_TRANSPORT_HelloGetHandle);
238 ghh->rec = rec;
239 ghh->rec_cls = rec_cls;
240 ghh->cfg = cfg;
241 ghh->ac = ac;
242 reconnect (ghh);
243 if (NULL == ghh->mq)
244 {
245 GNUNET_free (ghh);
246 return NULL;
247 }
248 return ghh;
249}
250
251
252/**
253 * Stop receiving updates about changes to our HELLO message.
254 *
255 * @param ghh handle to cancel
256 */
257void
258GNUNET_TRANSPORT_hello_get_cancel (struct GNUNET_TRANSPORT_HelloGetHandle *ghh)
259{
260 if (NULL != ghh->reconnect_task)
261 {
262 GNUNET_SCHEDULER_cancel (ghh->reconnect_task);
263 ghh->reconnect_task = NULL;
264 }
265 if (NULL != ghh->mq)
266 {
267 GNUNET_MQ_destroy (ghh->mq);
268 ghh->mq = NULL;
269 }
270 GNUNET_free (ghh);
271}
272
273
274/* end of transport_api_hello_get.c */
diff --git a/src/transport/transport_api_manipulation.c b/src/transport/transport_api_manipulation.c
deleted file mode 100644
index 4f4ccc4a0..000000000
--- a/src/transport/transport_api_manipulation.c
+++ /dev/null
@@ -1,249 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_manipulation.c
23 * @brief library to access the low-level P2P IO service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_constants.h"
29#include "gnunet_arm_service.h"
30#include "gnunet_hello_lib.h"
31#include "gnunet_protocols.h"
32#include "gnunet_transport_service.h"
33#include "transport.h"
34
35#define LOG(kind, ...) GNUNET_log_from (kind, "transport-api", __VA_ARGS__)
36
37
38/**
39 * Handle for the transport service (includes all of the
40 * state for the transport service).
41 */
42struct GNUNET_TRANSPORT_ManipulationHandle
43{
44 /**
45 * My client connection to the transport service.
46 */
47 struct GNUNET_MQ_Handle *mq;
48
49 /**
50 * My configuration.
51 */
52 const struct GNUNET_CONFIGURATION_Handle *cfg;
53
54 /**
55 * ID of the task trying to reconnect to the service.
56 */
57 struct GNUNET_SCHEDULER_Task *reconnect_task;
58
59 /**
60 * Delay until we try to reconnect.
61 */
62 struct GNUNET_TIME_Relative reconnect_delay;
63
64 /**
65 * Reconnect in progress
66 */
67 int reconnecting;
68};
69
70
71/**
72 * Function that will schedule the job that will try
73 * to connect us again to the client.
74 *
75 * @param h transport service to reconnect
76 */
77static void
78disconnect_and_schedule_reconnect (struct
79 GNUNET_TRANSPORT_ManipulationHandle *h);
80
81
82/**
83 * Generic error handler, called with the appropriate
84 * error code and the same closure specified at the creation of
85 * the message queue.
86 * Not every message queue implementation supports an error handler.
87 *
88 * @param cls closure with the `struct GNUNET_TRANSPORT_ManipulationHandle *`
89 * @param error error code
90 */
91static void
92mq_error_handler (void *cls,
93 enum GNUNET_MQ_Error error)
94{
95 struct GNUNET_TRANSPORT_ManipulationHandle *h = cls;
96
97 LOG (GNUNET_ERROR_TYPE_DEBUG,
98 "Error receiving from transport service, disconnecting temporarily.\n");
99 h->reconnecting = GNUNET_YES;
100 disconnect_and_schedule_reconnect (h);
101}
102
103
104/**
105 * Try again to connect to transport service.
106 *
107 * @param cls the handle to the transport service
108 */
109static void
110reconnect (void *cls)
111{
112 struct GNUNET_TRANSPORT_ManipulationHandle *h = cls;
113 struct GNUNET_MQ_MessageHandler handlers[] = {
114 GNUNET_MQ_handler_end ()
115 };
116 struct GNUNET_MQ_Envelope *env;
117 struct StartMessage *s;
118
119 h->reconnect_task = NULL;
120 LOG (GNUNET_ERROR_TYPE_DEBUG,
121 "Connecting to transport service.\n");
122 GNUNET_assert (NULL == h->mq);
123 h->reconnecting = GNUNET_NO;
124 h->mq = GNUNET_CLIENT_connect (h->cfg,
125 "transport",
126 handlers,
127 &mq_error_handler,
128 h);
129 if (NULL == h->mq)
130 return;
131 env = GNUNET_MQ_msg (s,
132 GNUNET_MESSAGE_TYPE_TRANSPORT_START);
133 GNUNET_MQ_send (h->mq,
134 env);
135}
136
137
138/**
139 * Function that will schedule the job that will try
140 * to connect us again to the client.
141 *
142 * @param h transport service to reconnect
143 */
144static void
145disconnect_and_schedule_reconnect (struct
146 GNUNET_TRANSPORT_ManipulationHandle *h)
147{
148 GNUNET_assert (NULL == h->reconnect_task);
149 if (NULL != h->mq)
150 {
151 GNUNET_MQ_destroy (h->mq);
152 h->mq = NULL;
153 }
154 h->reconnect_task =
155 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay,
156 &reconnect,
157 h);
158 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
159}
160
161
162/**
163 * Set transport metrics for a peer and a direction.
164 *
165 * @param handle transport handle
166 * @param peer the peer to set the metric for
167 * @param prop the performance metrics to set
168 * @param delay_in inbound delay to introduce
169 * @param delay_out outbound delay to introduce
170 *
171 * Note: Delay restrictions in receiving direction will be enforced
172 * with one message delay.
173 */
174void
175GNUNET_TRANSPORT_manipulation_set (struct
176 GNUNET_TRANSPORT_ManipulationHandle *handle,
177 const struct GNUNET_PeerIdentity *peer,
178 const struct GNUNET_ATS_Properties *prop,
179 struct GNUNET_TIME_Relative delay_in,
180 struct GNUNET_TIME_Relative delay_out)
181{
182 struct GNUNET_MQ_Envelope *env;
183 struct TrafficMetricMessage *msg;
184
185 if (NULL == handle->mq)
186 return;
187 env = GNUNET_MQ_msg (msg,
188 GNUNET_MESSAGE_TYPE_TRANSPORT_TRAFFIC_METRIC);
189 msg->reserved = htonl (0);
190 msg->peer = *peer;
191 GNUNET_ATS_properties_hton (&msg->properties,
192 prop);
193 msg->delay_in = GNUNET_TIME_relative_hton (delay_in);
194 msg->delay_out = GNUNET_TIME_relative_hton (delay_out);
195 GNUNET_MQ_send (handle->mq,
196 env);
197}
198
199
200/**
201 * Connect to the transport service. Note that the connection may
202 * complete (or fail) asynchronously.
203 *
204 * @param cfg configuration to use
205 * @return NULL on error
206 */
207struct GNUNET_TRANSPORT_ManipulationHandle *
208GNUNET_TRANSPORT_manipulation_connect (const struct
209 GNUNET_CONFIGURATION_Handle *cfg)
210{
211 struct GNUNET_TRANSPORT_ManipulationHandle *h;
212
213 h = GNUNET_new (struct GNUNET_TRANSPORT_ManipulationHandle);
214 h->cfg = cfg;
215 LOG (GNUNET_ERROR_TYPE_DEBUG,
216 "Connecting to transport service.\n");
217 reconnect (h);
218 if (NULL == h->mq)
219 {
220 GNUNET_free (h);
221 return NULL;
222 }
223 return h;
224}
225
226
227/**
228 * Disconnect from the transport service.
229 *
230 * @param handle handle to the service as returned from #GNUNET_TRANSPORT_manipulation_connect()
231 */
232void
233GNUNET_TRANSPORT_manipulation_disconnect (struct
234 GNUNET_TRANSPORT_ManipulationHandle *
235 handle)
236{
237 if (NULL == handle->reconnect_task)
238 disconnect_and_schedule_reconnect (handle);
239 /* and now we stop trying to connect again... */
240 if (NULL != handle->reconnect_task)
241 {
242 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
243 handle->reconnect_task = NULL;
244 }
245 GNUNET_free (handle);
246}
247
248
249/* end of transport_api_manipulation.c */
diff --git a/src/transport/transport_api_monitor_peers.c b/src/transport/transport_api_monitor_peers.c
deleted file mode 100644
index 2f0f07f23..000000000
--- a/src/transport/transport_api_monitor_peers.c
+++ /dev/null
@@ -1,469 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_monitor_peers.c
23 * @brief montoring api for transport peer status
24 *
25 * This api provides the ability to query the transport service about
26 * the connection status of a specific or all peers.
27 *
28 * Calls back with information about peer(s) including address used, state and
29 * state timeout for peer requests.
30 */
31#include "platform.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_arm_service.h"
34#include "gnunet_hello_lib.h"
35#include "gnunet_protocols.h"
36#include "gnunet_transport_service.h"
37#include "transport.h"
38
39/**
40 * Context for iterating validation entries.
41 */
42struct GNUNET_TRANSPORT_PeerMonitoringContext
43{
44 /**
45 * Function to call with the binary address.
46 */
47 GNUNET_TRANSPORT_PeerIterateCallback cb;
48
49 /**
50 * Closure for @e cb.
51 */
52 void *cb_cls;
53
54 /**
55 * Connection to the service.
56 */
57 struct GNUNET_MQ_Handle *mq;
58
59 /**
60 * Configuration we use.
61 */
62 const struct GNUNET_CONFIGURATION_Handle *cfg;
63
64 /**
65 * Backoff for reconnect.
66 */
67 struct GNUNET_TIME_Relative backoff;
68
69 /**
70 * Task ID for reconnect.
71 */
72 struct GNUNET_SCHEDULER_Task *reconnect_task;
73
74 /**
75 * Identity of the peer to monitor.
76 */
77 struct GNUNET_PeerIdentity peer;
78
79 /**
80 * Was this a one-shot request?
81 */
82 int one_shot;
83};
84
85
86/**
87 * Check if a state is defined as connected
88 *
89 * @param state the state value
90 * @return #GNUNET_YES or #GNUNET_NO
91 */
92int
93GNUNET_TRANSPORT_is_connected (enum GNUNET_TRANSPORT_PeerState state)
94{
95 switch (state)
96 {
97 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
98 case GNUNET_TRANSPORT_PS_INIT_ATS:
99 case GNUNET_TRANSPORT_PS_SYN_SENT:
100 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
101 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
102 return GNUNET_NO;
103
104 case GNUNET_TRANSPORT_PS_CONNECTED:
105 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
106 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
107 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
108 return GNUNET_YES;
109
110 case GNUNET_TRANSPORT_PS_DISCONNECT:
111 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
112 return GNUNET_NO;
113
114 default:
115 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
116 "Unhandled state `%s'\n",
117 GNUNET_TRANSPORT_ps2s (state));
118 GNUNET_break (0);
119 break;
120 }
121 return GNUNET_SYSERR;
122}
123
124
125/**
126 * Convert peer state to human-readable string.
127 *
128 * @param state the state value
129 * @return corresponding string
130 */
131const char *
132GNUNET_TRANSPORT_ps2s (enum GNUNET_TRANSPORT_PeerState state)
133{
134 switch (state)
135 {
136 case GNUNET_TRANSPORT_PS_NOT_CONNECTED:
137 return "S_NOT_CONNECTED";
138
139 case GNUNET_TRANSPORT_PS_INIT_ATS:
140 return "S_INIT_ATS";
141
142 case GNUNET_TRANSPORT_PS_SYN_SENT:
143 return "S_SYN_SENT";
144
145 case GNUNET_TRANSPORT_PS_SYN_RECV_ATS:
146 return "S_SYN_RECV_ATS";
147
148 case GNUNET_TRANSPORT_PS_SYN_RECV_ACK:
149 return "S_SYN_RECV_ACK";
150
151 case GNUNET_TRANSPORT_PS_CONNECTED:
152 return "S_CONNECTED";
153
154 case GNUNET_TRANSPORT_PS_RECONNECT_ATS:
155 return "S_RECONNECT_ATS";
156
157 case GNUNET_TRANSPORT_PS_RECONNECT_SENT:
158 return "S_RECONNECT_SENT";
159
160 case GNUNET_TRANSPORT_PS_SWITCH_SYN_SENT:
161 return "S_SWITCH_SYN_SENT";
162
163 case GNUNET_TRANSPORT_PS_DISCONNECT:
164 return "S_DISCONNECT";
165
166 case GNUNET_TRANSPORT_PS_DISCONNECT_FINISHED:
167 return "S_DISCONNECT_FINISHED";
168
169 default:
170 GNUNET_break (0);
171 return "UNDEFINED";
172 }
173}
174
175
176/**
177 * Task run to re-establish the connection.
178 *
179 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
180 */
181static void
182do_peer_connect (void *cls);
183
184
185/**
186 * Cut the existing connection and reconnect.
187 *
188 * @param pal_ctx our context
189 */
190static void
191reconnect_peer_ctx (struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx)
192{
193 GNUNET_assert (GNUNET_NO == pal_ctx->one_shot);
194 GNUNET_MQ_destroy (pal_ctx->mq);
195 pal_ctx->mq = NULL;
196 pal_ctx->cb (pal_ctx->cb_cls,
197 NULL,
198 NULL,
199 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
200 GNUNET_TIME_UNIT_ZERO_ABS);
201 pal_ctx->backoff = GNUNET_TIME_STD_BACKOFF (pal_ctx->backoff);
202 pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff,
203 &do_peer_connect,
204 pal_ctx);
205}
206
207
208/**
209 * Function called with responses from the service.
210 *
211 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
212 * @param msg message from service
213 */
214static void
215handle_response_end (void *cls,
216 const struct GNUNET_MessageHeader *msg)
217{
218 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
219
220 if (pal_ctx->one_shot)
221 {
222 /* iteration finished */
223 pal_ctx->cb (pal_ctx->cb_cls,
224 NULL,
225 NULL,
226 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
227 GNUNET_TIME_UNIT_ZERO_ABS);
228 GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
229 return;
230 }
231 /* not quite what we expected, reconnect */
232 GNUNET_break (0);
233 reconnect_peer_ctx (pal_ctx);
234}
235
236
237/**
238 * Function called to check responses from the service.
239 *
240 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
241 * @param pir_msg message with the human-readable address
242 * @return #GNUNET_OK if @a pir_msg is well-formed
243 */
244static int
245check_response (void *cls,
246 const struct PeerIterateResponseMessage *pir_msg)
247{
248 uint16_t size = ntohs (pir_msg->header.size) - sizeof(*pir_msg);
249 size_t alen = ntohl (pir_msg->addrlen);
250 size_t tlen = ntohl (pir_msg->pluginlen);
251 const char *addr;
252 const char *transport_name;
253
254 if (size != tlen + alen)
255 {
256 GNUNET_break (0);
257 return GNUNET_SYSERR;
258 }
259 if ((0 == tlen) && (0 == alen))
260 return GNUNET_OK;
261 if (0 == tlen)
262 {
263 GNUNET_break (0); /* This must not happen: address without plugin */
264 return GNUNET_SYSERR;
265 }
266 addr = (const char *) &pir_msg[1];
267 transport_name = &addr[alen];
268 if (transport_name[tlen - 1] != '\0')
269 {
270 GNUNET_break (0);
271 return GNUNET_SYSERR;
272 }
273 return GNUNET_OK;
274}
275
276
277/**
278 * Function called with responses from the service.
279 *
280 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
281 * @param msg message with the human-readable address
282 */
283static void
284handle_response (void *cls,
285 const struct PeerIterateResponseMessage *pir_msg)
286{
287 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
288 struct GNUNET_HELLO_Address *address;
289 size_t alen = ntohl (pir_msg->addrlen);
290 size_t tlen = ntohl (pir_msg->pluginlen);
291 const char *addr;
292 const char *transport_name;
293
294 if ((0 == tlen) &&
295 (0 == alen))
296 {
297 /* No address available */
298 pal_ctx->cb (pal_ctx->cb_cls,
299 &pir_msg->peer,
300 NULL,
301 ntohl (pir_msg->state),
302 GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
303 return;
304 }
305 addr = (const char *) &pir_msg[1];
306 transport_name = &addr[alen];
307
308 /* notify client */
309 address = GNUNET_HELLO_address_allocate (&pir_msg->peer,
310 transport_name,
311 addr,
312 alen,
313 ntohl (pir_msg->local_address_info));
314 pal_ctx->cb (pal_ctx->cb_cls,
315 &pir_msg->peer,
316 address,
317 ntohl (pir_msg->state),
318 GNUNET_TIME_absolute_ntoh (pir_msg->state_timeout));
319 GNUNET_HELLO_address_free (address);
320}
321
322
323/**
324 * Generic error handler, called with the appropriate error code and
325 * the same closure specified at the creation of the message queue.
326 * Not every message queue implementation supports an error handler.
327 *
328 * @param cls closure with the `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
329 * @param error error code
330 */
331static void
332mq_error_handler (void *cls,
333 enum GNUNET_MQ_Error error)
334{
335 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
336
337 if (pal_ctx->one_shot)
338 {
339 /* Disconnect */
340 pal_ctx->cb (pal_ctx->cb_cls,
341 NULL,
342 NULL,
343 GNUNET_TRANSPORT_PS_NOT_CONNECTED,
344 GNUNET_TIME_UNIT_ZERO_ABS);
345 GNUNET_TRANSPORT_monitor_peers_cancel (pal_ctx);
346 return;
347 }
348 reconnect_peer_ctx (pal_ctx);
349}
350
351
352/**
353 * Task run to re-establish the connection.
354 *
355 * @param cls our `struct GNUNET_TRANSPORT_PeerMonitoringContext *`
356 */
357static void
358do_peer_connect (void *cls)
359{
360 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx = cls;
361 struct GNUNET_MQ_MessageHandler handlers[] = {
362 GNUNET_MQ_hd_var_size (response,
363 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE,
364 struct PeerIterateResponseMessage,
365 pal_ctx),
366 GNUNET_MQ_hd_fixed_size (response_end,
367 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_RESPONSE_END,
368 struct GNUNET_MessageHeader,
369 pal_ctx),
370 GNUNET_MQ_handler_end ()
371 };
372 struct PeerMonitorMessage *msg;
373 struct GNUNET_MQ_Envelope *env;
374
375 pal_ctx->reconnect_task = NULL;
376 pal_ctx->mq = GNUNET_CLIENT_connect (pal_ctx->cfg,
377 "transport",
378 handlers,
379 &mq_error_handler,
380 pal_ctx);
381 if (NULL == pal_ctx->mq)
382 return;
383 env = GNUNET_MQ_msg (msg,
384 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PEER_REQUEST);
385 msg->one_shot = htonl (pal_ctx->one_shot);
386 msg->peer = pal_ctx->peer;
387 GNUNET_MQ_send (pal_ctx->mq,
388 env);
389}
390
391
392/**
393 * Return information about a specific peer or all peers currently known to
394 * transport service once or in monitoring mode. To obtain information about
395 * a specific peer, a peer identity can be passed. To obtain information about
396 * all peers currently known to transport service, NULL can be passed as peer
397 * identity.
398 *
399 * For each peer, the callback is called with information about the address used
400 * to communicate with this peer, the state this peer is currently in and the
401 * the current timeout for this state.
402 *
403 * Upon completion, the 'GNUNET_TRANSPORT_PeerIterateCallback' is called one
404 * more time with 'NULL'. After this, the operation must no longer be
405 * explicitly canceled.
406 *
407 * The #GNUNET_TRANSPORT_monitor_peers_cancel call MUST not be called in the
408 * the peer_callback!
409 *
410 * @param cfg configuration to use
411 * @param peer a specific peer identity to obtain information for,
412 * NULL for all peers
413 * @param one_shot #GNUNET_YES to return the current state and then end (with NULL+NULL),
414 * #GNUNET_NO to monitor peers continuously
415 * @param peer_callback function to call with the results
416 * @param peer_callback_cls closure for @a peer_address_callback
417 */
418struct GNUNET_TRANSPORT_PeerMonitoringContext *
419GNUNET_TRANSPORT_monitor_peers (const struct GNUNET_CONFIGURATION_Handle *cfg,
420 const struct GNUNET_PeerIdentity *peer,
421 int one_shot,
422 GNUNET_TRANSPORT_PeerIterateCallback
423 peer_callback,
424 void *peer_callback_cls)
425{
426 struct GNUNET_TRANSPORT_PeerMonitoringContext *pal_ctx
427 = GNUNET_new (struct GNUNET_TRANSPORT_PeerMonitoringContext);
428
429 pal_ctx->cb = peer_callback;
430 pal_ctx->cb_cls = peer_callback_cls;
431 pal_ctx->cfg = cfg;
432 if (NULL != peer)
433 pal_ctx->peer = *peer;
434 pal_ctx->one_shot = one_shot;
435 do_peer_connect (pal_ctx);
436 if (NULL == pal_ctx->mq)
437 {
438 GNUNET_free (pal_ctx);
439 return NULL;
440 }
441 return pal_ctx;
442}
443
444
445/**
446 * Cancel request to monitor peers
447 *
448 * @param pic handle for the request to cancel
449 */
450void
451GNUNET_TRANSPORT_monitor_peers_cancel (struct
452 GNUNET_TRANSPORT_PeerMonitoringContext *
453 pic)
454{
455 if (NULL != pic->mq)
456 {
457 GNUNET_MQ_destroy (pic->mq);
458 pic->mq = NULL;
459 }
460 if (NULL != pic->reconnect_task)
461 {
462 GNUNET_SCHEDULER_cancel (pic->reconnect_task);
463 pic->reconnect_task = NULL;
464 }
465 GNUNET_free (pic);
466}
467
468
469/* end of transport_api_monitor_peers.c */
diff --git a/src/transport/transport_api_monitor_plugins.c b/src/transport/transport_api_monitor_plugins.c
deleted file mode 100644
index d8eddddaa..000000000
--- a/src/transport/transport_api_monitor_plugins.c
+++ /dev/null
@@ -1,463 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2014, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_monitor_plugins.c
23 * @brief montoring api for transport plugin session status
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_arm_service.h"
29#include "gnunet_hello_lib.h"
30#include "gnunet_protocols.h"
31#include "gnunet_transport_service.h"
32#include "transport.h"
33
34
35/**
36 * Handle for a plugin session state monitor.
37 */
38struct GNUNET_TRANSPORT_PluginMonitor
39{
40 /**
41 * Connection to the service.
42 */
43 struct GNUNET_MQ_Handle *mq;
44
45 /**
46 * Our configuration.
47 */
48 const struct GNUNET_CONFIGURATION_Handle *cfg;
49
50 /**
51 * Callback to call.
52 */
53 GNUNET_TRANSPORT_SessionMonitorCallback cb;
54
55 /**
56 * Closure for @e cb
57 */
58 void *cb_cls;
59
60 /**
61 * Map of session_ids (reduced to 32-bits) to
62 * `struct GNUNET_TRANSPORT_PluginSession` objects.
63 */
64 struct GNUNET_CONTAINER_MultiHashMap32 *sessions;
65
66 /**
67 * Backoff for reconnect.
68 */
69 struct GNUNET_TIME_Relative backoff;
70
71 /**
72 * Task ID for reconnect.
73 */
74 struct GNUNET_SCHEDULER_Task *reconnect_task;
75};
76
77
78/**
79 * Abstract representation of a plugin's session.
80 * Corresponds to the `struct GNUNET_ATS_Session` within the TRANSPORT service.
81 */
82struct GNUNET_TRANSPORT_PluginSession
83{
84 /**
85 * Unique session identifier.
86 */
87 uint64_t session_id;
88
89 /**
90 * Location for the client to store "data".
91 */
92 void *client_ctx;
93};
94
95
96/**
97 * Task run to re-establish the connection.
98 *
99 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor *`
100 */
101static void
102do_plugin_connect (void *cls);
103
104
105/**
106 * Free the session entry and notify the callback about its demise.
107 *
108 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor`
109 * @param key key of the session in the map
110 * @param value the session to free
111 * @return #GNUNET_OK (continue to iterate)
112 */
113static int
114free_entry (void *cls,
115 uint32_t key,
116 void *value)
117{
118 struct GNUNET_TRANSPORT_PluginMonitor *pm = cls;
119 struct GNUNET_TRANSPORT_PluginSession *ps = value;
120
121 pm->cb (pm->cb_cls,
122 ps,
123 &ps->client_ctx,
124 NULL);
125 GNUNET_break (GNUNET_YES ==
126 GNUNET_CONTAINER_multihashmap32_remove (pm->sessions,
127 key,
128 ps));
129 GNUNET_break (NULL == ps->client_ctx);
130 GNUNET_free (ps);
131 return GNUNET_OK;
132}
133
134
135/**
136 * Cut the existing connection and reconnect.
137 *
138 * @param pm our context
139 */
140static void
141reconnect_plugin_ctx (struct GNUNET_TRANSPORT_PluginMonitor *pm)
142{
143 GNUNET_MQ_destroy (pm->mq);
144 pm->mq = NULL;
145 GNUNET_CONTAINER_multihashmap32_iterate (pm->sessions,
146 &free_entry,
147 pm);
148 pm->backoff = GNUNET_TIME_STD_BACKOFF (pm->backoff);
149 pm->reconnect_task = GNUNET_SCHEDULER_add_delayed (pm->backoff,
150 &do_plugin_connect,
151 pm);
152}
153
154
155/**
156 * Convert 64-bit session ID to 32-bit index for hash map.
157 *
158 * @param id 64-bit session ID
159 * @return 32-bit hash map index
160 */
161static uint32_t
162wrap_id (uint64_t id)
163{
164 return ((uint32_t) id) ^ ((uint32_t) (id >> 32));
165}
166
167
168/**
169 * Context for #locate_by_id().
170 */
171struct SearchContext
172{
173 /**
174 * Result.
175 */
176 struct GNUNET_TRANSPORT_PluginSession *ps;
177
178 /**
179 * ID to locate.
180 */
181 uint64_t session_id;
182};
183
184
185/**
186 * Locate a session entry.
187 *
188 * @param cls our `struct SearchContext`
189 * @param key key of the session in the map
190 * @param value a session
191 * @return #GNUNET_OK (continue to iterate), or #GNUNET_SYSERR (match found)
192 */
193static int
194locate_by_id (void *cls,
195 uint32_t key,
196 void *value)
197{
198 struct SearchContext *sc = cls;
199 struct GNUNET_TRANSPORT_PluginSession *ps = value;
200
201 if (sc->session_id == ps->session_id)
202 {
203 sc->ps = ps;
204 return GNUNET_SYSERR;
205 }
206 return GNUNET_OK;
207}
208
209
210/**
211 * Function called with responses from the service.
212 *
213 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor *`
214 * @paramm tpmm message with event data
215 * @return #GNUNET_Ok if message is well-formed
216 */
217static int
218check_event (void *cls,
219 const struct TransportPluginMonitorMessage *tpmm)
220{
221 const char *pname;
222 size_t pname_len;
223 size_t paddr_len;
224
225 pname = (const char *) &tpmm[1];
226 pname_len = ntohs (tpmm->plugin_name_len);
227 paddr_len = ntohs (tpmm->plugin_address_len);
228 if ((pname_len
229 + paddr_len
230 + sizeof(struct TransportPluginMonitorMessage) != ntohs (
231 tpmm->header.size)) ||
232 ((0 != pname_len) &&
233 ('\0' != pname[pname_len - 1])))
234 {
235 GNUNET_break (0);
236 return GNUNET_SYSERR;
237 }
238 return GNUNET_OK;
239}
240
241
242/**
243 * Function called with responses from the service.
244 *
245 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor *`
246 * @paramm tpmm message with event data
247 */
248static void
249handle_event (void *cls,
250 const struct TransportPluginMonitorMessage *tpmm)
251{
252 struct GNUNET_TRANSPORT_PluginMonitor *pm = cls;
253 struct GNUNET_TRANSPORT_PluginSession *ps;
254 const char *pname;
255 const void *paddr;
256 enum GNUNET_TRANSPORT_SessionState ss;
257 size_t pname_len;
258 size_t paddr_len;
259 struct GNUNET_TRANSPORT_SessionInfo info;
260 struct GNUNET_HELLO_Address addr;
261 struct SearchContext rv;
262
263 pname = (const char *) &tpmm[1];
264 pname_len = ntohs (tpmm->plugin_name_len);
265 paddr_len = ntohs (tpmm->plugin_address_len);
266 paddr = &pname[pname_len];
267 ps = NULL;
268 ss = (enum GNUNET_TRANSPORT_SessionState) ntohs (tpmm->session_state);
269 if (GNUNET_TRANSPORT_SS_INIT == ss)
270 {
271 ps = GNUNET_new (struct GNUNET_TRANSPORT_PluginSession);
272 ps->session_id = tpmm->session_id;
273 (void) GNUNET_CONTAINER_multihashmap32_put (pm->sessions,
274 wrap_id (tpmm->session_id),
275 ps,
276 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
277 }
278 else
279 {
280 rv.session_id = tpmm->session_id;
281 rv.ps = NULL;
282 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (pm->sessions,
283 wrap_id (
284 tpmm->session_id),
285 &locate_by_id,
286 &rv);
287 ps = rv.ps;
288 if (NULL == ps)
289 {
290 GNUNET_break (0);
291 reconnect_plugin_ctx (pm);
292 return;
293 }
294 }
295 info.state = ss;
296 info.is_inbound = (int16_t) ntohs (tpmm->is_inbound);
297 info.num_msg_pending = ntohl (tpmm->msgs_pending);
298 info.num_bytes_pending = ntohl (tpmm->bytes_pending);
299 info.receive_delay = GNUNET_TIME_absolute_ntoh (tpmm->delay);
300 info.session_timeout = GNUNET_TIME_absolute_ntoh (tpmm->timeout);
301 info.address = &addr;
302 addr.peer = tpmm->peer;
303 addr.address = (0 == paddr_len) ? NULL : paddr;
304 addr.address_length = paddr_len;
305 addr.transport_name = (0 == pname_len) ? NULL : pname;
306 addr.local_info = GNUNET_HELLO_ADDRESS_INFO_NONE;
307 pm->cb (pm->cb_cls,
308 ps,
309 &ps->client_ctx,
310 &info);
311
312 if (GNUNET_TRANSPORT_SS_DONE == ss)
313 {
314 GNUNET_break (NULL == ps->client_ctx);
315 GNUNET_assert (GNUNET_YES ==
316 GNUNET_CONTAINER_multihashmap32_remove (pm->sessions,
317 wrap_id (
318 tpmm->session_id),
319 ps));
320 GNUNET_free (ps);
321 }
322}
323
324
325/**
326 * Function called with sync responses from the service.
327 *
328 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor *`
329 * @param msg message from the service
330 */
331static void
332handle_sync (void *cls,
333 const struct GNUNET_MessageHeader *msg)
334{
335 struct GNUNET_TRANSPORT_PluginMonitor *pm = cls;
336
337 /* we are in sync, notify callback */
338 pm->cb (pm->cb_cls,
339 NULL,
340 NULL,
341 NULL);
342}
343
344
345/**
346 * Generic error handler, called with the appropriate
347 * error code and the same closure specified at the creation of
348 * the message queue.
349 * Not every message queue implementation supports an error handler.
350 *
351 * @param cls closure with the `struct GNUNET_NSE_Handle *`
352 * @param error error code
353 */
354static void
355mq_error_handler (void *cls,
356 enum GNUNET_MQ_Error error)
357{
358 struct GNUNET_TRANSPORT_PluginMonitor *pm = cls;
359
360 reconnect_plugin_ctx (pm);
361}
362
363
364/**
365 * Task run to re-establish the connection.
366 *
367 * @param cls our `struct GNUNET_TRANSPORT_PluginMonitor *`
368 */
369static void
370do_plugin_connect (void *cls)
371{
372 struct GNUNET_TRANSPORT_PluginMonitor *pm = cls;
373 struct GNUNET_MQ_MessageHandler handlers[] = {
374 GNUNET_MQ_hd_var_size (event,
375 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_EVENT,
376 struct TransportPluginMonitorMessage,
377 pm),
378 GNUNET_MQ_hd_fixed_size (sync,
379 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_SYNC,
380 struct GNUNET_MessageHeader,
381 pm),
382 GNUNET_MQ_handler_end ()
383 };
384 struct GNUNET_MessageHeader *msg;
385 struct GNUNET_MQ_Envelope *env;
386
387 pm->reconnect_task = NULL;
388 pm->mq = GNUNET_CLIENT_connect (pm->cfg,
389 "transport",
390 handlers,
391 &mq_error_handler,
392 pm);
393 if (NULL == pm->mq)
394 return;
395 env = GNUNET_MQ_msg (msg,
396 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_PLUGIN_START);
397 GNUNET_MQ_send (pm->mq,
398 env);
399}
400
401
402/**
403 * Install a plugin session state monitor callback. The callback
404 * will be notified whenever the session changes.
405 *
406 * @param cfg configuration to use
407 * @param cb callback to invoke on events
408 * @param cb_cls closure for @a cb
409 * @return NULL on error, otherwise handle for cancellation
410 */
411struct GNUNET_TRANSPORT_PluginMonitor *
412GNUNET_TRANSPORT_monitor_plugins (const struct GNUNET_CONFIGURATION_Handle *cfg,
413 GNUNET_TRANSPORT_SessionMonitorCallback cb,
414 void *cb_cls)
415{
416 struct GNUNET_TRANSPORT_PluginMonitor *pm;
417
418 pm = GNUNET_new (struct GNUNET_TRANSPORT_PluginMonitor);
419 pm->cb = cb;
420 pm->cb_cls = cb_cls;
421 pm->cfg = cfg;
422 do_plugin_connect (pm);
423 if (NULL == pm->mq)
424 {
425 GNUNET_free (pm);
426 return NULL;
427 }
428 pm->sessions = GNUNET_CONTAINER_multihashmap32_create (128);
429 return pm;
430}
431
432
433/**
434 * Cancel monitoring the plugin session state. The callback will
435 * be called once for each session that is up with the information
436 * #GNUNET_TRANSPORT_SS_FINI (even though the session may stay up;
437 * this is just to enable client-side cleanup).
438 *
439 * @param pm handle of the request that is to be cancelled
440 */
441void
442GNUNET_TRANSPORT_monitor_plugins_cancel (struct
443 GNUNET_TRANSPORT_PluginMonitor *pm)
444{
445 if (NULL != pm->mq)
446 {
447 GNUNET_MQ_destroy (pm->mq);
448 pm->mq = NULL;
449 }
450 if (NULL != pm->reconnect_task)
451 {
452 GNUNET_SCHEDULER_cancel (pm->reconnect_task);
453 pm->reconnect_task = NULL;
454 }
455 GNUNET_CONTAINER_multihashmap32_iterate (pm->sessions,
456 &free_entry,
457 pm);
458 GNUNET_CONTAINER_multihashmap32_destroy (pm->sessions);
459 GNUNET_free (pm);
460}
461
462
463/* end of transport_api_monitor_plugins.c */
diff --git a/src/transport/transport_api_offer_hello.c b/src/transport/transport_api_offer_hello.c
deleted file mode 100644
index eb342f57c..000000000
--- a/src/transport/transport_api_offer_hello.c
+++ /dev/null
@@ -1,142 +0,0 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2009-2013, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/transport_api_offer_hello.c
23 * @brief library to offer HELLOs to transport service
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_hello_lib.h"
29#include "gnunet_protocols.h"
30#include "gnunet_transport_service.h"
31
32
33/**
34 * Entry in linked list for all offer-HELLO requests.
35 */
36struct GNUNET_TRANSPORT_OfferHelloHandle
37{
38 /**
39 * Transport service handle we use for transmission.
40 */
41 struct GNUNET_MQ_Handle *mq;
42
43 /**
44 * Function to call once we are done.
45 */
46 GNUNET_SCHEDULER_TaskCallback cont;
47
48 /**
49 * Closure for @e cont
50 */
51 void *cls;
52};
53
54
55/**
56 * Done sending HELLO message to the service, notify application.
57 *
58 * @param cls the handle for the operation
59 */
60static void
61finished_hello (void *cls)
62{
63 struct GNUNET_TRANSPORT_OfferHelloHandle *ohh = cls;
64
65 if (NULL != ohh->cont)
66 ohh->cont (ohh->cls);
67 GNUNET_TRANSPORT_offer_hello_cancel (ohh);
68}
69
70
71/**
72 * Offer the transport service the HELLO of another peer. Note that
73 * the transport service may just ignore this message if the HELLO is
74 * malformed or useless due to our local configuration.
75 *
76 * @param cfg configuration
77 * @param hello the hello message
78 * @param cont continuation to call when HELLO has been sent,
79 * tc reason #GNUNET_SCHEDULER_REASON_TIMEOUT for fail
80 * tc reasong #GNUNET_SCHEDULER_REASON_READ_READY for success
81 * @param cont_cls closure for @a cont
82 * @return a `struct GNUNET_TRANSPORT_OfferHelloHandle` handle or NULL on failure,
83 * in case of failure @a cont will not be called
84 *
85 */
86struct GNUNET_TRANSPORT_OfferHelloHandle *
87GNUNET_TRANSPORT_offer_hello (const struct GNUNET_CONFIGURATION_Handle *cfg,
88 const struct GNUNET_MessageHeader *hello,
89 GNUNET_SCHEDULER_TaskCallback cont,
90 void *cont_cls)
91{
92 struct GNUNET_TRANSPORT_OfferHelloHandle *ohh
93 = GNUNET_new (struct GNUNET_TRANSPORT_OfferHelloHandle);
94 struct GNUNET_MQ_Envelope *env;
95 struct GNUNET_PeerIdentity peer;
96
97 if (GNUNET_OK !=
98 GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hello,
99 &peer))
100 {
101 GNUNET_break (0);
102 GNUNET_free (ohh);
103 return NULL;
104 }
105 ohh->mq = GNUNET_CLIENT_connect (cfg,
106 "transport",
107 NULL,
108 NULL,
109 ohh);
110 if (NULL == ohh->mq)
111 {
112 GNUNET_free (ohh);
113 return NULL;
114 }
115 ohh->cont = cont;
116 ohh->cls = cont_cls;
117 GNUNET_break (ntohs (hello->type) == GNUNET_MESSAGE_TYPE_HELLO);
118 env = GNUNET_MQ_msg_copy (hello);
119 GNUNET_MQ_notify_sent (env,
120 &finished_hello,
121 ohh);
122 GNUNET_MQ_send (ohh->mq,
123 env);
124 return ohh;
125}
126
127
128/**
129 * Cancel the request to transport to offer the HELLO message
130 *
131 * @param ohh the handle for the operation to cancel
132 */
133void
134GNUNET_TRANSPORT_offer_hello_cancel (struct
135 GNUNET_TRANSPORT_OfferHelloHandle *ohh)
136{
137 GNUNET_MQ_destroy (ohh->mq);
138 GNUNET_free (ohh);
139}
140
141
142/* end of transport_api_offer_hello.c */
diff --git a/src/transport/transport_api_traits.c b/src/transport/transport_api_traits.c
deleted file mode 100644
index 7e66cc3d1..000000000
--- a/src/transport/transport_api_traits.c
+++ /dev/null
@@ -1,32 +0,0 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file transport/test_transport_start_with_config.c
23 * @brief Generic program to start testcases in an configurable topology.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_testing_ng_lib.h"
28#include "gnunet_testing_netjail_lib.h"
29#include "transport-testing-cmds.h"
30#include "gnunet_util_lib.h"
31
32GNUNET_TRANSPORT_SIMPLE_TRAITS (GNUNET_TRANSPORT_MAKE_IMPL_SIMPLE_TRAIT)