aboutsummaryrefslogtreecommitdiff
path: root/src/service/transport
diff options
context:
space:
mode:
Diffstat (limited to 'src/service/transport')
-rw-r--r--src/service/transport/.gitignore94
-rw-r--r--src/service/transport/Makefile.am458
-rw-r--r--src/service/transport/NOTES46
-rwxr-xr-xsrc/service/transport/benchmark.sh13
-rw-r--r--src/service/transport/communicator.h138
-rw-r--r--src/service/transport/gnunet-communicator-quic.c1795
-rw-r--r--src/service/transport/gnunet-communicator-tcp.c4182
-rw-r--r--src/service/transport/gnunet-communicator-udp.c3665
-rw-r--r--src/service/transport/gnunet-communicator-unix.c1166
-rw-r--r--src/service/transport/gnunet-service-transport.c12664
-rw-r--r--src/service/transport/gnunet-service-transport.h234
-rw-r--r--src/service/transport/gnunet-transport-certificate-creation.in158
-rw-r--r--src/service/transport/gnunet-transport.c1437
-rw-r--r--src/service/transport/ieee80211_radiotap.h276
-rw-r--r--src/service/transport/meson.build501
-rw-r--r--src/service/transport/template_cfg_peer1.conf50
-rw-r--r--src/service/transport/template_cfg_peer2.conf58
-rw-r--r--src/service/transport/template_tng_cfg_peer1.conf34
-rw-r--r--src/service/transport/test_communicator_basic.c1266
-rw-r--r--src/service/transport/test_communicator_quic_basic_peer1.conf45
-rw-r--r--src/service/transport/test_communicator_quic_basic_peer2.conf45
-rw-r--r--src/service/transport/test_communicator_tcp_basic_peer1.conf48
-rw-r--r--src/service/transport/test_communicator_tcp_basic_peer2.conf44
-rw-r--r--src/service/transport/test_communicator_tcp_bidirect_peer1.conf48
-rw-r--r--src/service/transport/test_communicator_tcp_bidirect_peer2.conf44
-rw-r--r--src/service/transport/test_communicator_tcp_rekey_peer1.conf45
-rw-r--r--src/service/transport/test_communicator_tcp_rekey_peer2.conf45
-rw-r--r--src/service/transport/test_communicator_udp_backchannel_peer1.conf48
-rw-r--r--src/service/transport/test_communicator_udp_backchannel_peer2.conf48
-rw-r--r--src/service/transport/test_communicator_udp_basic_peer1.conf40
-rw-r--r--src/service/transport/test_communicator_udp_basic_peer2.conf39
-rw-r--r--src/service/transport/test_communicator_udp_rekey_peer1.conf53
-rw-r--r--src/service/transport/test_communicator_udp_rekey_peer2.conf52
-rw-r--r--src/service/transport/test_communicator_unix_basic_peer1.conf43
-rw-r--r--src/service/transport/test_communicator_unix_basic_peer2.conf43
-rwxr-xr-xsrc/service/transport/test_delay19
-rw-r--r--src/service/transport/test_plugin_hostkeybin0 -> 915 bytes
-rw-r--r--src/service/transport/test_plugin_hostkey.ecc1
-rw-r--r--src/service/transport/test_tng_defaults.conf14
-rw-r--r--src/service/transport/test_transport_address_switch.c433
-rw-r--r--src/service/transport/test_transport_address_switch_tcp_peer1.conf48
-rw-r--r--src/service/transport/test_transport_address_switch_tcp_peer2.conf48
-rw-r--r--src/service/transport/test_transport_address_switch_udp_peer1.conf48
-rw-r--r--src/service/transport/test_transport_address_switch_udp_peer2.conf48
-rw-r--r--src/service/transport/test_transport_api.c126
-rw-r--r--src/service/transport/test_transport_api2.c126
-rw-r--r--src/service/transport/test_transport_api2_tcp_node1.conf35
-rw-r--r--src/service/transport/test_transport_api2_tcp_node2.conf22
-rw-r--r--src/service/transport/test_transport_api2_tcp_peer1.conf23
-rw-r--r--src/service/transport/test_transport_api2_tcp_peer2.conf22
-rw-r--r--src/service/transport/test_transport_api2_tng_node.conf40
-rw-r--r--src/service/transport/test_transport_api_data.conf9
-rw-r--r--src/service/transport/test_transport_api_monitor_peers.c226
-rw-r--r--src/service/transport/test_transport_api_monitor_peers_peer1.conf4
-rw-r--r--src/service/transport/test_transport_api_monitor_peers_peer2.conf5
-rw-r--r--src/service/transport/test_transport_api_monitor_validation_peer1.conf6
-rw-r--r--src/service/transport/test_transport_api_monitor_validation_peer2.conf7
-rw-r--r--src/service/transport/test_transport_api_multi_peer1.conf7
-rw-r--r--src/service/transport/test_transport_api_multi_peer2.conf9
-rw-r--r--src/service/transport/test_transport_api_tcp_nat_peer1.conf34
-rw-r--r--src/service/transport/test_transport_api_tcp_nat_peer2.conf32
-rw-r--r--src/service/transport/test_transport_api_tcp_peer1.conf9
-rw-r--r--src/service/transport/test_transport_api_tcp_peer2.conf9
-rw-r--r--src/service/transport/test_transport_api_udp_nat_peer1.conf34
-rw-r--r--src/service/transport/test_transport_api_udp_nat_peer2.conf32
-rw-r--r--src/service/transport/test_transport_api_udp_peer1.conf17
-rw-r--r--src/service/transport/test_transport_api_udp_peer2.conf15
-rw-r--r--src/service/transport/test_transport_api_unix_peer1.conf10
-rw-r--r--src/service/transport/test_transport_api_unix_peer2.conf7
-rw-r--r--src/service/transport/test_transport_defaults.conf20
-rw-r--r--src/service/transport/test_transport_distance_vector_circle_topo.conf11
-rw-r--r--src/service/transport/test_transport_distance_vector_inverse_topo.conf13
-rw-r--r--src/service/transport/test_transport_distance_vector_topo.conf8
-rw-r--r--src/service/transport/test_transport_just_run_topo.conf6
-rwxr-xr-xsrc/service/transport/test_transport_nat_icmp_tcp.sh12
-rw-r--r--src/service/transport/test_transport_nat_icmp_tcp_topo.conf7
-rwxr-xr-xsrc/service/transport/test_transport_nat_upnp.sh12
-rw-r--r--src/service/transport/test_transport_nat_upnp_topo.conf7
-rw-r--r--src/service/transport/test_transport_plugin_cmd_just_run.c494
-rw-r--r--src/service/transport/test_transport_plugin_cmd_nat_upnp.c368
-rw-r--r--src/service/transport/test_transport_plugin_cmd_simple_send.c377
-rw-r--r--src/service/transport/test_transport_plugin_cmd_simple_send_broadcast.c399
-rw-r--r--src/service/transport/test_transport_plugin_cmd_simple_send_dv.c433
-rw-r--r--src/service/transport/test_transport_plugin_cmd_simple_send_performance.c480
-rw-r--r--src/service/transport/test_transport_plugin_cmd_udp_backchannel.c371
-rwxr-xr-xsrc/service/transport/test_transport_simple_send.sh11
-rwxr-xr-xsrc/service/transport/test_transport_simple_send_broadcast.sh11
-rw-r--r--src/service/transport/test_transport_simple_send_broadcast_topo.conf4
-rwxr-xr-xsrc/service/transport/test_transport_simple_send_dv_circle.sh11
-rwxr-xr-xsrc/service/transport/test_transport_simple_send_dv_inverse.sh12
-rwxr-xr-xsrc/service/transport/test_transport_simple_send_performance.sh11
-rw-r--r--src/service/transport/test_transport_simple_send_performance_topo.conf6
-rwxr-xr-xsrc/service/transport/test_transport_simple_send_string.sh21
-rw-r--r--src/service/transport/test_transport_simple_send_topo.conf6
-rwxr-xr-xsrc/service/transport/test_transport_start_testcase.sh12
-rw-r--r--src/service/transport/test_transport_start_with_config.c121
-rw-r--r--src/service/transport/test_transport_test_transport_address_switch_tcp_peer1.conf29
-rw-r--r--src/service/transport/test_transport_test_transport_address_switch_tcp_peer2.conf29
-rw-r--r--src/service/transport/test_transport_testing_startstop.c138
-rwxr-xr-xsrc/service/transport/test_transport_udp_backchannel.sh14
-rw-r--r--src/service/transport/test_transport_udp_backchannel_topo.conf7
-rw-r--r--src/service/transport/testing_api_cmd_start_peer.c296
-rw-r--r--src/service/transport/testing_api_cmd_stop_peer.c129
-rw-r--r--src/service/transport/transport-testing-cmds.h273
-rw-r--r--src/service/transport/transport-testing-communicator.c1251
-rw-r--r--src/service/transport/transport-testing-communicator.h370
-rw-r--r--src/service/transport/transport-testing-filenames2.c203
-rw-r--r--src/service/transport/transport-testing-loggers2.c81
-rw-r--r--src/service/transport/transport-testing-main2.c614
-rw-r--r--src/service/transport/transport-testing-send2.c241
-rw-r--r--src/service/transport/transport-testing2.c871
-rw-r--r--src/service/transport/transport-testing2.h940
-rw-r--r--src/service/transport/transport.conf.in32
-rw-r--r--src/service/transport/transport.h828
-rw-r--r--src/service/transport/transport_api2_application.c397
-rw-r--r--src/service/transport/transport_api2_communication.c1126
-rw-r--r--src/service/transport/transport_api2_core.c845
-rw-r--r--src/service/transport/transport_api2_monitor.c292
-rw-r--r--src/service/transport/transport_api_cmd_backchannel_check.c554
-rw-r--r--src/service/transport/transport_api_cmd_connecting_peers.c314
-rw-r--r--src/service/transport/transport_api_cmd_send_simple.c161
-rw-r--r--src/service/transport/transport_api_cmd_send_simple_performance.c219
-rw-r--r--src/service/transport/transport_api_cmd_start_peer.c484
-rw-r--r--src/service/transport/transport_api_cmd_stop_peer.c153
-rw-r--r--src/service/transport/transport_api_traits.c32
-rwxr-xr-xsrc/service/transport/upnp.sh22
126 files changed, 44679 insertions, 0 deletions
diff --git a/src/service/transport/.gitignore b/src/service/transport/.gitignore
new file mode 100644
index 000000000..163ffbd5d
--- /dev/null
+++ b/src/service/transport/.gitignore
@@ -0,0 +1,94 @@
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_basic-*
91test_communicator_rekey-*
92test_transport_start_with_config
93test_transport_api2_tcp
94gnunet-communicator-quic
diff --git a/src/service/transport/Makefile.am b/src/service/transport/Makefile.am
new file mode 100644
index 000000000..a78371f10
--- /dev/null
+++ b/src/service/transport/Makefile.am
@@ -0,0 +1,458 @@
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
13if USE_COVERAGE
14 AM_CFLAGS = --coverage -O0
15endif
16
17noinst_PROGRAMS = \
18 test_transport_start_with_config \
19 gnunet-communicator-udp
20
21TESTING_LIBS = \
22 libgnunettransporttesting2.la
23
24lib_LTLIBRARIES = \
25 libgnunettransportapplication.la \
26 libgnunettransportcore.la \
27 libgnunettransportcommunicator.la \
28 libgnunettransportmonitor.la \
29 $(TESTING_LIBS)
30
31libgnunettransporttesting2_la_SOURCES = \
32 transport_api_traits.c \
33 testing_api_cmd_stop_peer.c \
34 testing_api_cmd_start_peer.c \
35 transport_api_cmd_connecting_peers.c \
36 transport_api_cmd_backchannel_check.c \
37 transport_api_cmd_start_peer.c \
38 transport_api_cmd_stop_peer.c \
39 transport_api_cmd_send_simple.c \
40 transport_api_cmd_send_simple_performance.c \
41 transport-testing2.c transport-testing2.h \
42 transport-testing-cmds.h \
43 transport-testing-filenames2.c \
44 transport-testing-loggers2.c \
45 transport-testing-main2.c \
46 transport-testing-send2.c \
47 transport-testing-communicator.c transport-testing-communicator.h
48libgnunettransporttesting2_la_LIBADD = \
49 libgnunettransportapplication.la \
50 libgnunettransportcore.la \
51 $(top_builddir)/src/service/arm/libgnunetarm.la \
52 $(top_builddir)/src/lib/testing/libgnunettesting.la \
53 $(top_builddir)/src/lib/hello/libgnunethello.la \
54 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
55 $(top_builddir)/src/lib/util/libgnunetutil.la
56libgnunettransporttesting2_la_LDFLAGS = \
57 $(GN_LIBINTL) \
58 $(GN_LIB_LDFLAGS) \
59 -version-info 0:0:0
60
61libgnunettransportapplication_la_SOURCES = \
62 transport_api2_application.c
63libgnunettransportapplication_la_LIBADD = \
64 $(top_builddir)/src/lib/util/libgnunetutil.la \
65 $(LTLIBINTL)
66libgnunettransportapplication_la_LDFLAGS = \
67 $(GN_LIB_LDFLAGS) \
68 -version-info 0:0:0
69
70
71libgnunettransportcore_la_SOURCES = \
72 transport_api2_core.c
73libgnunettransportcore_la_LIBADD = \
74 $(top_builddir)/src/lib/util/libgnunetutil.la \
75 $(GN_LIBINTL)
76libgnunettransportcore_la_LDFLAGS = \
77 $(GN_LIB_LDFLAGS) \
78 -version-info 0:0:0
79
80libgnunettransportcommunicator_la_SOURCES = \
81 transport_api2_communication.c
82libgnunettransportcommunicator_la_LIBADD = \
83 $(top_builddir)/src/lib/util/libgnunetutil.la \
84 $(GN_LIBINTL)
85libgnunettransportcommunicator_la_LDFLAGS = \
86 $(GN_LIB_LDFLAGS) \
87 -version-info 0:0:0
88
89
90libgnunettransportmonitor_la_SOURCES = \
91 transport_api2_monitor.c
92libgnunettransportmonitor_la_LIBADD = \
93 $(top_builddir)/src/lib/util/libgnunetutil.la \
94 $(GN_LIBINTL)
95libgnunettransportmonitor_la_LDFLAGS = \
96 $(GN_LIB_LDFLAGS) \
97 -version-info 0:0:0
98
99
100libexec_PROGRAMS = \
101 gnunet-service-transport \
102 gnunet-communicator-unix \
103 gnunet-communicator-udp \
104 gnunet-communicator-tcp
105if HAVE_EXPERIMENTAL
106if HAVE_QUICHE
107libexec_PROGRAMS += \
108 gnunet-communicator-quic
109endif
110endif
111
112
113#bin_PROGRAMS = \
114# gnunet-transport
115
116bin_SCRIPTS = \
117 gnunet-transport-certificate-creation
118
119# See: https://www.gnu.org/software/automake/manual/html_node/Scripts.html#Scripts
120do_subst = sed -e 's,[@]pkgdatadir[@],$(pkgdatadir),g'
121
122
123gnunet-transport-certificate-creation: gnunet-transport-certificate-creation.in Makefile
124 $(AWK) -v bdir="$(bindir)" -v py="$(PYTHON)" -v awkay="$(AWK_BINARY)" -v pfx="$(prefix)" -v prl="$(PERL)" -v sysconfdirectory="$(sysconfdir)" -v pkgdatadirectory="$(pkgdatadir)" -f $(top_srcdir)/scripts/dosubst.awk < $(srcdir)/gnunet-transport-certificate-creation.in > gnunet-transport-certificate-creation
125 @chmod +x gnunet-transport-certificate-creation
126
127
128
129
130gnunet_communicator_unix_SOURCES = \
131 gnunet-communicator-unix.c
132gnunet_communicator_unix_LDADD = \
133 libgnunettransportcommunicator.la \
134 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
135 $(top_builddir)/src/lib/util/libgnunetutil.la
136
137gnunet_communicator_tcp_SOURCES = \
138 gnunet-communicator-tcp.c
139gnunet_communicator_tcp_LDADD = \
140 libgnunettransportcommunicator.la \
141 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
142 $(top_builddir)/src/service/nat/libgnunetnatnew.la \
143 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
144 $(top_builddir)/src/lib/util/libgnunetutil.la \
145 $(LIBGCRYPT_LIBS)
146
147gnunet_communicator_udp_SOURCES = \
148 gnunet-communicator-udp.c
149gnunet_communicator_udp_LDADD = \
150 libgnunettransportapplication.la \
151 libgnunettransportcommunicator.la \
152 $(top_builddir)/src/service/nat/libgnunetnatnew.la \
153 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
154 $(top_builddir)/src/lib/util/libgnunetutil.la \
155 $(LIBGCRYPT_LIBS)
156
157if HAVE_EXPERIMENTAL
158if HAVE_QUICHE
159gnunet_communicator_quic_SOURCES = \
160 gnunet-communicator-quic.c
161gnunet_communicator_quic_LDADD = \
162 libgnunettransportapplication.la \
163 libgnunettransportcommunicator.la \
164 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
165 $(top_builddir)/src/service/nat/libgnunetnatnew.la \
166 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
167 $(top_builddir)/src/lib/util/libgnunetutil.la \
168 -lquiche \
169 $(LIBGCRYPT_LIBS)
170endif
171endif
172
173#gnunet_transport_SOURCES = \
174# gnunet-transport.c
175#gnunet_transport_LDADD = \
176# libgnunettransport.la \
177# $(top_builddir)/src/lib/hello/libgnunethello.la \
178# $(top_builddir)/src/lib/util/libgnunetutil.la \
179# $(GN_LIBINTL)
180
181gnunet_service_transport_SOURCES = \
182 gnunet-service-transport.c transport.h
183gnunet_service_transport_LDADD = \
184 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
185 $(top_builddir)/src/lib/hello/libgnunethello.la \
186 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
187 $(top_builddir)/src/service/nat/libgnunetnatnew.la \
188 $(top_builddir)/src/lib/util/libgnunetutil.la \
189 $(LIBGCRYPT_LIBS) \
190 $(GN_LIBINTL)
191
192plugin_LTLIBRARIES = \
193 libgnunet_test_transport_plugin_cmd_simple_send_performance.la \
194 libgnunet_test_transport_plugin_cmd_nat_upnp.la \
195 libgnunet_test_transport_plugin_cmd_simple_send.la \
196 libgnunet_test_transport_plugin_cmd_simple_send_broadcast.la \
197 libgnunet_test_transport_plugin_cmd_simple_send_dv.la \
198 libgnunet_test_transport_plugin_cmd_udp_backchannel.la
199
200libgnunet_test_transport_plugin_cmd_nat_upnp_la_SOURCES = \
201 test_transport_plugin_cmd_nat_upnp.c
202libgnunet_test_transport_plugin_cmd_nat_upnp_la_LIBADD = \
203 libgnunettransporttesting2.la \
204 libgnunettransportapplication.la \
205 libgnunettransportcore.la \
206 $(top_builddir)/src/lib/testing/libgnunettesting.la \
207 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
208 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
209 $(top_builddir)/src/lib/hello/libgnunethello.la \
210 $(top_builddir)/src/service/arm/libgnunetarm.la \
211 $(top_builddir)/src/lib/util/libgnunetutil.la \
212 $(LTLIBINTL)
213libgnunet_test_transport_plugin_cmd_nat_upnp_la_LDFLAGS = \
214 $(GN_PLUGIN_LDFLAGS)
215
216libgnunet_test_transport_plugin_cmd_udp_backchannel_la_SOURCES = \
217 test_transport_plugin_cmd_udp_backchannel.c
218libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LIBADD = \
219 libgnunettransporttesting2.la \
220 libgnunettransportapplication.la \
221 libgnunettransportcore.la \
222 $(top_builddir)/src/lib/testing/libgnunettesting.la \
223 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
224 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
225 $(top_builddir)/src/lib/hello/libgnunethello.la \
226 $(top_builddir)/src/service/arm/libgnunetarm.la \
227 $(top_builddir)/src/lib/util/libgnunetutil.la \
228 $(LTLIBINTL)
229libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LDFLAGS = \
230 $(GN_PLUGIN_LDFLAGS)
231
232libgnunet_test_transport_plugin_cmd_simple_send_la_SOURCES = \
233 test_transport_plugin_cmd_simple_send.c
234libgnunet_test_transport_plugin_cmd_simple_send_la_LIBADD = \
235 libgnunettransporttesting2.la \
236 libgnunettransportapplication.la \
237 libgnunettransportcore.la \
238 $(top_builddir)/src/lib/testing/libgnunettesting.la \
239 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
240 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
241 $(top_builddir)/src/lib/hello/libgnunethello.la \
242 $(top_builddir)/src/service/arm/libgnunetarm.la \
243 $(top_builddir)/src/lib/util/libgnunetutil.la \
244 $(LTLIBINTL)
245libgnunet_test_transport_plugin_cmd_simple_send_la_LDFLAGS = \
246 $(GN_PLUGIN_LDFLAGS)
247
248libgnunet_test_transport_plugin_cmd_simple_send_performance_la_SOURCES = \
249 test_transport_plugin_cmd_simple_send_performance.c
250libgnunet_test_transport_plugin_cmd_simple_send_performance_la_LIBADD = \
251 libgnunettransporttesting2.la \
252 libgnunettransportapplication.la \
253 libgnunettransportcore.la \
254 $(top_builddir)/src/lib/testing/libgnunettesting.la \
255 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
256 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
257 $(top_builddir)/src/lib/hello/libgnunethello.la \
258 $(top_builddir)/src/service/arm/libgnunetarm.la \
259 $(top_builddir)/src/lib/util/libgnunetutil.la \
260 $(LTLIBINTL)
261libgnunet_test_transport_plugin_cmd_simple_send_performance_la_LDFLAGS = \
262 $(GN_PLUGIN_LDFLAGS)
263
264libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_SOURCES = \
265 test_transport_plugin_cmd_simple_send_broadcast.c
266libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_LIBADD = \
267 libgnunettransporttesting2.la \
268 libgnunettransportapplication.la \
269 libgnunettransportcore.la \
270 $(top_builddir)/src/lib/testing/libgnunettesting.la \
271 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
272 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
273 $(top_builddir)/src/lib/hello/libgnunethello.la \
274 $(top_builddir)/src/service/arm/libgnunetarm.la \
275 $(top_builddir)/src/lib/util/libgnunetutil.la \
276 $(LTLIBINTL)
277libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_LDFLAGS = \
278 $(GN_PLUGIN_LDFLAGS)
279
280libgnunet_test_transport_plugin_cmd_simple_send_dv_la_SOURCES = \
281 test_transport_plugin_cmd_simple_send_dv.c
282libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LIBADD = \
283 libgnunettransporttesting2.la \
284 libgnunettransportapplication.la \
285 libgnunettransportcore.la \
286 $(top_builddir)/src/lib/testing/libgnunettesting.la \
287 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
288 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
289 $(top_builddir)/src/lib/hello/libgnunethello.la \
290 $(top_builddir)/src/service/arm/libgnunetarm.la \
291 $(top_builddir)/src/lib/util/libgnunetutil.la \
292 $(LTLIBINTL)
293libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LDFLAGS = \
294 $(GN_PLUGIN_LDFLAGS)
295
296check_PROGRAMS = \
297 test_communicator_basic-tcp \
298 test_communicator_basic-udp \
299 test_communicator_rekey-tcp \
300 test_communicator_bidirect-tcp \
301 test_communicator_rekey-udp \
302 test_communicator_backchannel-udp
303
304if HAVE_EXPERIMENTAL
305check_PROGRAMS += test_communicator_basic-quic \
306 test_communicator_basic-unix
307check_SCRIPTS= \
308 test_transport_start_testcase.sh \
309 test_transport_simple_send_performance.sh \
310 test_transport_nat_icmp_tcp.sh \
311 test_transport_nat_upnp.sh \
312 test_transport_simple_send_string.sh \
313 test_transport_simple_send.sh \
314 test_transport_simple_send_broadcast.sh \
315 test_transport_udp_backchannel.sh \
316 test_transport_simple_send_dv_circle.sh \
317 test_transport_simple_send_dv_inverse.sh
318endif
319
320if ENABLE_TEST_RUN
321AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
322TESTS = \
323 $(check_SCRIPTS) \
324 $(check_PROGRAMS)
325endif
326
327
328test_transport_start_with_config_SOURCES = \
329 test_transport_start_with_config.c
330test_transport_start_with_config_LDADD = \
331 $(top_builddir)/src/lib/testing/libgnunettesting.la \
332 $(top_builddir)/src/lib/util/libgnunetutil.la \
333 $(top_builddir)/src/lib/hello/libgnunethello.la \
334 libgnunettransportcore.la \
335 libgnunettransporttesting2.la
336
337test_communicator_basic_unix_SOURCES = \
338 test_communicator_basic.c
339test_communicator_basic_unix_LDADD = \
340 libgnunettransporttesting2.la \
341 $(top_builddir)/src/lib/testing/libgnunettesting.la \
342 $(top_builddir)/src/lib/util/libgnunetutil.la \
343 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
344
345test_communicator_basic_tcp_SOURCES = \
346 test_communicator_basic.c
347test_communicator_basic_tcp_LDADD = \
348 libgnunettransporttesting2.la \
349 $(top_builddir)/src/lib/testing/libgnunettesting.la \
350 $(top_builddir)/src/lib/util/libgnunetutil.la \
351 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
352
353test_communicator_basic_udp_SOURCES = \
354 test_communicator_basic.c
355test_communicator_basic_udp_LDADD = \
356 libgnunettransporttesting2.la \
357 $(top_builddir)/src/lib/testing/libgnunettesting.la \
358 $(top_builddir)/src/lib/util/libgnunetutil.la \
359 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
360
361test_communicator_basic_quic_SOURCES = \
362 test_communicator_basic.c
363test_communicator_basic_quic_LDADD = \
364 libgnunettransporttesting2.la \
365 $(top_builddir)/src/lib/testing/libgnunettesting.la \
366 $(top_builddir)/src/lib/util/libgnunetutil.la \
367 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
368
369test_communicator_rekey_tcp_SOURCES = \
370 test_communicator_basic.c
371test_communicator_rekey_tcp_LDADD = \
372 libgnunettransporttesting2.la \
373 $(top_builddir)/src/lib/testing/libgnunettesting.la \
374 $(top_builddir)/src/lib/util/libgnunetutil.la \
375 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
376
377test_communicator_rekey_udp_SOURCES = \
378 test_communicator_basic.c
379test_communicator_rekey_udp_LDADD = \
380 libgnunettransporttesting2.la \
381 $(top_builddir)/src/lib/testing/libgnunettesting.la \
382 $(top_builddir)/src/lib/util/libgnunetutil.la \
383 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
384
385test_communicator_backchannel_udp_SOURCES = \
386 test_communicator_basic.c
387test_communicator_backchannel_udp_LDADD = \
388 libgnunettransporttesting2.la \
389 $(top_builddir)/src/lib/testing/libgnunettesting.la \
390 $(top_builddir)/src/lib/util/libgnunetutil.la \
391 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
392
393test_communicator_bidirect_tcp_SOURCES = \
394 test_communicator_basic.c
395test_communicator_bidirect_tcp_LDADD = \
396 libgnunettransporttesting2.la \
397 $(top_builddir)/src/lib/testing/libgnunettesting.la \
398 $(top_builddir)/src/lib/util/libgnunetutil.la \
399 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
400
401test_transport_api2_tcp_SOURCES = \
402 test_transport_api2.c
403test_transport_api2_tcp_LDADD = \
404 $(top_builddir)/src/lib/hello/libgnunethello.la \
405 $(top_builddir)/src/lib/util/libgnunetutil.la \
406 libgnunettransporttesting2.la
407
408EXTRA_DIST = \
409test_transport_start_testcase.sh \
410test_transport_simple_send_performance.sh \
411test_transport_nat_icmp_tcp.sh \
412test_transport_nat_upnp.sh \
413test_transport_simple_send_string.sh \
414test_transport_simple_send.sh \
415test_transport_simple_send_broadcast.sh \
416test_transport_udp_backchannel.sh \
417test_transport_simple_send_dv_circle.sh \
418test_transport_simple_send_dv_inverse.sh \
419gnunet-transport-certificate-creation.in \
420test_plugin_hostkey \
421test_plugin_hostkey.ecc \
422test_delay \
423template_cfg_peer1.conf\
424template_cfg_peer2.conf\
425test_transport_api_data.conf\
426test_transport_api_multi_peer1.conf\
427test_transport_api_multi_peer2.conf\
428test_transport_api_tcp_nat_peer1.conf\
429test_transport_api_tcp_nat_peer2.conf\
430test_transport_api_tcp_peer1.conf\
431test_transport_api_tcp_peer2.conf\
432test_transport_api2_tcp_peer1.conf\
433test_transport_api2_tcp_peer2.conf\
434test_transport_api_udp_nat_peer1.conf\
435test_transport_api_udp_nat_peer2.conf\
436test_transport_api_udp_peer1.conf\
437test_transport_api_udp_peer2.conf\
438test_transport_api_unix_peer1.conf\
439test_transport_api_unix_peer2.conf\
440test_transport_api_monitor_peers_peer1.conf\
441test_transport_api_monitor_peers_peer2.conf\
442test_transport_api_monitor_validation_peer1.conf\
443test_transport_api_monitor_validation_peer2.conf\
444test_transport_defaults.conf\
445test_communicator_unix_basic_peer1.conf \
446test_communicator_unix_basic_peer2.conf \
447test_communicator_tcp_basic_peer1.conf \
448test_communicator_tcp_basic_peer2.conf \
449test_communicator_udp_basic_peer1.conf \
450test_communicator_udp_basic_peer2.conf \
451test_communicator_tcp_rekey_peer1.conf \
452test_communicator_tcp_rekey_peer2.conf \
453test_communicator_udp_rekey_peer1.conf \
454test_communicator_udp_rekey_peer2.conf \
455test_communicator_udp_backchannel_peer1.conf \
456test_communicator_udp_backchannel_peer2.conf \
457test_communicator_tcp_bidirect_peer1.conf \
458test_communicator_tcp_bidirect_peer2.conf
diff --git a/src/service/transport/NOTES b/src/service/transport/NOTES
new file mode 100644
index 000000000..41404e1f9
--- /dev/null
+++ b/src/service/transport/NOTES
@@ -0,0 +1,46 @@
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/service/transport/benchmark.sh b/src/service/transport/benchmark.sh
new file mode 100755
index 000000000..a29e6ec2d
--- /dev/null
+++ b/src/service/transport/benchmark.sh
@@ -0,0 +1,13 @@
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/service/transport/communicator.h b/src/service/transport/communicator.h
new file mode 100644
index 000000000..5ef43597d
--- /dev/null
+++ b/src/service/transport/communicator.h
@@ -0,0 +1,138 @@
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/service/transport/gnunet-communicator-quic.c b/src/service/transport/gnunet-communicator-quic.c
new file mode 100644
index 000000000..0a7e511eb
--- /dev/null
+++ b/src/service/transport/gnunet-communicator-quic.c
@@ -0,0 +1,1795 @@
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-quic.c
23 * @brief Transport plugin using QUIC.
24 * @author Marshall Stone
25 * @author Martin Schanzenbach
26 *
27 * TODO:
28 * - Automatically generate self-signed x509 certificates and load from config
29 * - Figure out MTU and how we have to handle fragmentation in Quiche.
30 * - Mandate timeouts
31 * - Setup stats handler properly
32 * - Doxygen documentation of methods
33 * - Refactor code shared with UDP and TCP communicator
34 * - Performance testing
35 * - Check for memory leaks with coverity/valgrind
36 */
37#include "gnunet_common.h"
38#include "gnunet_util_lib.h"
39#include "gnunet_core_service.h"
40#include "quiche.h"
41#include "platform.h"
42#include "gnunet_protocols.h"
43#include "gnunet_signatures.h"
44#include "gnunet_constants.h"
45#include "gnunet_statistics_service.h"
46#include "gnunet_transport_application_service.h"
47#include "gnunet_transport_communication_service.h"
48#include "gnunet_nat_service.h"
49#include "stdint.h"
50#include "inttypes.h"
51
52#define COMMUNICATOR_CONFIG_SECTION "communicator-quic"
53#define COMMUNICATOR_ADDRESS_PREFIX "quic"
54#define MAX_DATAGRAM_SIZE 1350
55
56
57/* FIXME: Review all static lengths/contents below. Maybe this can be done smarter */
58/* Currently equivalent to QUICHE_MAX_CONN_ID_LEN */
59#define LOCAL_CONN_ID_LEN 20
60#define MAX_TOKEN_LEN \
61 sizeof("quiche") - 1 \
62 + sizeof(struct sockaddr_storage) \
63 + QUICHE_MAX_CONN_ID_LEN
64#define CID_LEN sizeof(uint8_t) * QUICHE_MAX_CONN_ID_LEN
65#define TOKEN_LEN sizeof (uint8_t) * MAX_TOKEN_LEN
66
67
68/* FIXME: Why 4?
69 Generic, bidirectional, client-initiated quic stream id */
70#define STREAMID_BI 4
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/**
79 * Map of DCID (uint8_t) -> quic_conn for quickly retrieving connections to other peers.
80 */
81struct GNUNET_CONTAINER_MultiHashMap *conn_map;
82
83/**
84 * Map of sockaddr -> struct PeerAddress
85 */
86struct GNUNET_CONTAINER_MultiHashMap *addr_map;
87
88/**
89 * Handle to the config
90 */
91static const struct GNUNET_CONFIGURATION_Handle *cfg;
92
93/**
94 * FIXME undocumented
95 */
96static struct GNUNET_TIME_Relative rekey_interval;
97
98/**
99 * FIXME undocumented
100 */
101static struct GNUNET_NETWORK_Handle *udp_sock;
102
103/**
104 * FIXME undocumented
105 */
106static struct GNUNET_SCHEDULER_Task *read_task;
107
108/**
109 * FIXME undocumented
110 */
111static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
112
113/**
114 * FIXME undocumented
115 */
116static struct GNUNET_TRANSPORT_ApplicationHandle *ah;
117
118/**
119 * FIXME undocumented
120 */
121static int have_v6_socket;
122
123/**
124 * FIXME undocumented
125 */
126static uint16_t my_port;
127
128/**
129 * FIXME undocumented
130 */
131static unsigned long long rekey_max_bytes;
132
133/**
134 * FIXME undocumented
135 */
136static quiche_config *config = NULL;
137
138/**
139 * Our peer identity
140*/
141struct GNUNET_PeerIdentity my_identity;
142
143/**
144 * Our private key.
145 */
146static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
147
148/**
149 * Connection to NAT service.
150 */
151static struct GNUNET_NAT_Handle *nat;
152
153/**
154 * Information we track per peer we have recently been in contact with.
155 *
156 * (Since quiche handles crypto, handshakes, etc. we don't differentiate
157 * between SenderAddress and ReceiverAddress)
158 * FIXME: But we do a handshake as well. The flag in this struct seems to
159 * indicate this. Update comment!
160 */
161struct PeerAddress
162{
163 /**
164 * To whom are we talking to.
165 */
166 struct GNUNET_PeerIdentity target;
167
168 /**
169 * Flag to indicate whether we know the PeerIdentity (target) yet
170 */
171 int id_rcvd;
172
173 /**
174 * Flag to indicate whether we have sent OUR PeerIdentity to this peer
175 */
176 int id_sent;
177
178 /**
179 * Flag to indicate if we are the initiator of the connection
180 */
181 int is_receiver;
182
183 /**
184 * Address of the receiver in the human-readable format
185 * with the #COMMUNICATOR_ADDRESS_PREFIX.
186 */
187 char *foreign_addr;
188
189 /**
190 * Address of the other peer.
191 */
192 struct sockaddr *address;
193
194 /**
195 * Length of the address.
196 */
197 socklen_t address_len;
198
199 /**
200 * The QUIC connection associated with this peer
201 */
202 struct quic_conn *conn;
203
204 /**
205 * Default message queue we are providing for the #ch.
206 */
207 struct GNUNET_MQ_Handle *d_mq;
208
209 /**
210 * handle for default queue with the #ch.
211 */
212 struct GNUNET_TRANSPORT_QueueHandle *d_qh;
213
214 /**
215 * Timeout for this peer address.
216 */
217 struct GNUNET_TIME_Absolute timeout;
218
219 /**
220 * MTU we allowed transport for this peer's default queue.
221 * FIXME: MTU from quiche
222 */
223 size_t d_mtu;
224
225 /**
226 * Which network type does this queue use?
227 */
228 enum GNUNET_NetworkType nt;
229
230 /**
231 * receiver_destroy already called on receiver.
232 */
233 int peer_destroy_called;
234
235 /**
236 * FIXME implementation missing
237 * Entry in sender expiration heap.
238 */
239 // struct GNUNET_CONTAINER_HeapNode *hn;
240};
241
242// /**
243// * FIXME: Implementation missing
244// * Expiration heap for peers (contains `struct PeerAddress`)
245// */
246// static struct GNUNET_CONTAINER_Heap *peers_heap;
247
248/**
249 * ID of timeout task
250 */
251static struct GNUNET_SCHEDULER_Task *timeout_task;
252
253/**
254 * Network scanner to determine network types.
255 */
256static struct GNUNET_NT_InterfaceScanner *is;
257
258/**
259 * For logging statistics.
260 */
261static struct GNUNET_STATISTICS_Handle *stats;
262
263/**
264 * QUIC connection object. A connection has a unique SCID/DCID pair. Here we store our SCID
265 * (incoming packet DCID field == outgoing packet SCID field) for a given connection. This
266 * is hashed for each unique quic_conn.
267*/
268struct quic_conn
269{
270 uint8_t cid[LOCAL_CONN_ID_LEN];
271
272 quiche_conn *conn;
273};
274
275/**
276 * QUIC_header is used to store information received from an incoming QUIC packet
277*/
278struct QUIC_header
279{
280 uint8_t type;
281 uint32_t version;
282
283 uint8_t scid[QUICHE_MAX_CONN_ID_LEN];
284 size_t scid_len;
285
286 uint8_t dcid[QUICHE_MAX_CONN_ID_LEN];
287 size_t dcid_len;
288
289 uint8_t odcid[QUICHE_MAX_CONN_ID_LEN];
290 size_t odcid_len;
291
292 uint8_t token[MAX_TOKEN_LEN];
293 size_t token_len;
294};
295
296
297/**
298 * Given a PeerAddress, receive data from streams after doing connection logic.
299 * ASSUMES: connection is established to peer
300*/
301static void
302recv_from_streams (struct PeerAddress *peer)
303{
304 char stream_buf[UINT16_MAX];
305 size_t buf_size = UINT16_MAX;
306 char *buf_ptr = stream_buf;
307 struct GNUNET_MessageHeader *hdr;
308
309 uint64_t s = 0;
310 quiche_stream_iter *readable;
311 bool fin;
312 ssize_t recv_len;
313
314 readable = quiche_conn_readable (peer->conn->conn);
315 while (quiche_stream_iter_next (readable, &s))
316 {
317 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "stream %" PRIu64 " is readable\n",
318 s);
319 fin = false;
320 recv_len = quiche_conn_stream_recv (peer->conn->conn, s,
321 (uint8_t *) stream_buf, buf_size,
322 &fin);
323 if (recv_len < 0)
324 {
325 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
326 "error while receiving data from stream %" PRIu64 "\n", s);
327 break;
328 }
329 /**
330 * FIXME: Do not use implicit booleans. Use GNUNET_YES, GNUNET_NO, GNUNET_SYSERR
331 * and check for that.
332 *
333 * Initial packet should contain peerid if they are the initiator
334 */
335 if (! peer->is_receiver && GNUNET_NO == peer->id_rcvd)
336 {
337 if (recv_len < sizeof(struct GNUNET_PeerIdentity))
338 {
339 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
340 "message recv len of %zd less than length of peer identity\n",
341 recv_len);
342 return;
343 }
344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
345 "received peer identity\n");
346 struct GNUNET_PeerIdentity *pid = (struct
347 GNUNET_PeerIdentity *) stream_buf;
348 peer->target = *pid;
349 peer->id_rcvd = GNUNET_YES;
350 buf_ptr += sizeof(struct GNUNET_PeerIdentity);
351 recv_len -= sizeof(struct GNUNET_PeerIdentity);
352 }
353 /**
354 * Parse messages to pass to communicator
355 */
356 while (recv_len >= sizeof(struct GNUNET_MessageHeader))
357 {
358 hdr = (struct GNUNET_MessageHeader *) buf_ptr;
359 if (ntohs (hdr->size) > recv_len)
360 {
361 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
362 "message size stated (%d) is greater than length of rcvd data (%zd)!\n",
363 ntohs (hdr->size), recv_len);
364 return;
365 }
366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "passing %zd bytes to core\n",
367 recv_len);
368 GNUNET_TRANSPORT_communicator_receive (ch, &peer->target, hdr,
369 ADDRESS_VALIDITY_PERIOD, NULL,
370 NULL);
371 recv_len -= ntohs (hdr->size);
372 buf_ptr += ntohs (hdr->size);
373 }
374 /**
375 * Check for leftover bytes
376 */
377 if (0 != recv_len)
378 {
379 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
380 "message recv len of %zd less than length of message header\n",
381 recv_len);
382 }
383 /**
384 * FIXME: comment useless
385 * fin
386 */
387 if (fin)
388 {
389 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
390 "fin received, closing connection\n");
391 if (0 > quiche_conn_close (peer->conn->conn, true, 0, NULL, 0))
392 {
393 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
394 "quiche failed to close connection to peer\n");
395 }
396 }
397 }
398 quiche_stream_iter_free (readable);
399}
400
401
402/**
403 * FIXME: review token generation, assure tokens are generated properly. doxygen
404 */
405static void
406mint_token (const uint8_t *dcid, size_t dcid_len,
407 struct sockaddr_storage *addr, socklen_t addr_len,
408 uint8_t *token, size_t *token_len)
409{
410 GNUNET_memcpy (token, "quiche", sizeof("quiche") - 1);
411 GNUNET_memcpy (token + sizeof("quiche") - 1, addr, addr_len);
412 GNUNET_memcpy (token + sizeof("quiche") - 1 + addr_len, dcid, dcid_len);
413
414 *token_len = sizeof("quiche") - 1 + addr_len + dcid_len;
415}
416
417
418static enum GNUNET_GenericReturnValue
419validate_token (const uint8_t *token, size_t token_len,
420 struct sockaddr_storage *addr, socklen_t addr_len,
421 uint8_t *odcid, size_t *odcid_len)
422{
423 if ((token_len < sizeof("quiche") - 1) ||
424 memcmp (token, "quiche", sizeof("quiche") - 1))
425 {
426 return GNUNET_NO;
427 }
428
429 token += sizeof("quiche") - 1;
430 token_len -= sizeof("quiche") - 1;
431
432 if ((token_len < addr_len) || memcmp (token, addr, addr_len))
433 {
434 return GNUNET_NO;
435 }
436
437 token += addr_len;
438 token_len -= addr_len;
439
440 if (*odcid_len < token_len)
441 {
442 return GNUNET_NO;
443 }
444
445 memcpy (odcid, token, token_len);
446 *odcid_len = token_len;
447
448 return GNUNET_OK;
449}
450
451
452static struct quic_conn*
453create_conn (uint8_t *scid, size_t scid_len,
454 uint8_t *odcid, size_t odcid_len,
455 struct sockaddr *local_addr,
456 socklen_t local_addr_len,
457 struct sockaddr_storage *peer_addr,
458 socklen_t peer_addr_len)
459{
460 struct quic_conn *conn;
461 quiche_conn *q_conn;
462 conn = GNUNET_new (struct quic_conn);
463 if (scid_len != LOCAL_CONN_ID_LEN)
464 {
465 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
466 "error while creating connection, scid length too short: %zu\n",
467 scid_len);
468 return NULL;
469 }
470
471 GNUNET_memcpy (conn->cid, scid, LOCAL_CONN_ID_LEN);
472 q_conn = quiche_accept (conn->cid, LOCAL_CONN_ID_LEN,
473 odcid, odcid_len,
474 local_addr,
475 local_addr_len,
476 (struct sockaddr *) peer_addr,
477 peer_addr_len,
478 config);
479 if (NULL == q_conn)
480 {
481 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
482 "quiche failed to create connection after call to quiche_accept\n");
483 return NULL;
484 }
485 conn->conn = q_conn;
486 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "new quic connection created\n");
487 return conn;
488}
489
490
491static void
492flush_egress (struct quic_conn *conn)
493{
494 static uint8_t out[MAX_DATAGRAM_SIZE];
495 quiche_send_info send_info;
496
497 ssize_t written;
498 ssize_t sent;
499
500 while (1)
501 {
502 written = quiche_conn_send (conn->conn, out, sizeof(out), &send_info);
503 if (QUICHE_ERR_DONE == written)
504 {
505 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "done writing quic packets\n");
506 break;
507 }
508 if (0 > written)
509 {
510 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
511 "quiche failed to create packet. quiche error: %zd\n",
512 written);
513 return;
514 }
515 sent = GNUNET_NETWORK_socket_sendto (udp_sock, out, written,
516 (struct sockaddr *) &send_info.to,
517 send_info.to_len);
518 if (sent != written)
519 {
520 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
521 "quiche failed to send data to peer\n");
522 return;
523 }
524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent %zd bytes\n", sent);
525 }
526}
527
528
529/**
530 * Increment receiver timeout due to activity.
531 *
532 * @param receiver address for which the timeout should be rescheduled
533 */
534static void
535reschedule_peer_timeout (struct PeerAddress *peer)
536{
537 peer->timeout =
538 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
539 // GNUNET_CONTAINER_heap_update_cost (peer->hn,
540 // peer->timeout.abs_value_us);
541}
542
543
544/**
545 * Destroys a receiving state due to timeout or shutdown.
546 *
547 * @param receiver entity to close down
548 */
549static void
550peer_destroy (struct PeerAddress *peer)
551{
552 struct GNUNET_HashCode addr_key;
553
554 peer->peer_destroy_called = GNUNET_YES;
555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
556 "Disconnecting peer for peer `%s'\n",
557 GNUNET_i2s (&peer->target));
558 if (NULL != peer->d_qh)
559 {
560 GNUNET_TRANSPORT_communicator_mq_del (peer->d_qh);
561 peer->d_qh = NULL;
562 }
563 // GNUNET_assert (peer == GNUNET_CONTAINER_heap_remove_node (peer->hn));
564 /**
565 * Remove peer from hashmap
566 */
567 GNUNET_CRYPTO_hash (peer->address, peer->address_len, &addr_key);
568 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (addr_map, &addr_key,
569 peer))
570 {
571 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
572 "tried to remove non-existent peer from addr map\n");
573 return;
574 }
575 GNUNET_STATISTICS_set (stats,
576 "# peers active",
577 GNUNET_CONTAINER_multihashmap_size (addr_map),
578 GNUNET_NO);
579 quiche_conn_free (peer->conn->conn);
580 GNUNET_free (peer->address);
581 GNUNET_free (peer->foreign_addr);
582 GNUNET_free (peer->conn);
583 GNUNET_free (peer);
584}
585
586
587/**
588 * Iterator over all peers to clean up.
589 *
590 * @param cls NULL
591 * @param key peer->address
592 * @param value the peer to destroy
593 * @return #GNUNET_OK to continue to iterate
594 */
595static int
596get_peer_delete_it (void *cls,
597 const struct GNUNET_HashCode *key,
598 void *value)
599{
600 struct PeerAddress *peer = value;
601 (void) cls;
602 (void) key;
603 peer_destroy (peer);
604 return GNUNET_OK;
605}
606
607
608/**
609 * Signature of functions implementing the sending functionality of a
610 * message queue.
611 *
612 * @param mq the message queue
613 * @param msg the message to send
614 * @param impl_state our `struct PeerAddress`
615 */
616static void
617mq_send_d (struct GNUNET_MQ_Handle *mq,
618 const struct GNUNET_MessageHeader *msg,
619 void *impl_state)
620{
621 struct PeerAddress *peer = impl_state;
622 uint16_t msize = ntohs (msg->size);
623 ssize_t send_len;
624
625 if (NULL == peer->conn->conn)
626 {
627 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
628 "peer never established quic connection\n");
629 return;
630 }
631
632 GNUNET_assert (mq == peer->d_mq);
633 if (msize > peer->d_mtu)
634 {
635 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
636 "msize: %u, mtu: %lu\n",
637 msize,
638 peer->d_mtu);
639 GNUNET_break (0);
640 if (GNUNET_YES != peer->peer_destroy_called)
641 {
642 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
643 "peer destroy called, destroying peer\n");
644 peer_destroy (peer);
645 }
646 return;
647 }
648 reschedule_peer_timeout (peer);
649
650 send_len = quiche_conn_stream_send (peer->conn->conn, 4, (uint8_t *) msg,
651 msize, false);
652 if (send_len != msize)
653 {
654 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
655 "tried to send message and quiche returned %zd", send_len);
656 return;
657 }
658 flush_egress (peer->conn);
659 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
660 "sent a message of %zd bytes\n", send_len);
661 GNUNET_MQ_impl_send_continue (mq);
662}
663
664
665/**
666 * Signature of functions implementing the destruction of a message
667 * queue. Implementations must not free @a mq, but should take care
668 * of @a impl_state.
669 *
670 * @param mq the message queue to destroy
671 * @param impl_state our `struct PeerAddress`
672 */
673static void
674mq_destroy_d (struct GNUNET_MQ_Handle *mq, void *impl_state)
675{
676 struct PeerAddress *peer = impl_state;
677 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
678 "Default MQ destroyed\n");
679 if (mq == peer->d_mq)
680 {
681 peer->d_mq = NULL;
682 if (GNUNET_YES != peer->peer_destroy_called)
683 peer_destroy (peer);
684 }
685}
686
687
688/**
689 * Implementation function that cancels the currently sent message.
690 *
691 * @param mq message queue
692 * @param impl_state our `struct PeerAddress`
693 */
694static void
695mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
696{
697 /* Cancellation is impossible with QUIC; bail */
698 GNUNET_assert (0);
699}
700
701
702/**
703 * Generic error handler, called with the appropriate
704 * error code and the same closure specified at the creation of
705 * the message queue.
706 * Not every message queue implementation supports an error handler.
707 *
708 * @param cls our `struct ReceiverAddress`
709 * @param error error code
710 */
711static void
712mq_error (void *cls, enum GNUNET_MQ_Error error)
713{
714 struct PeerAddress *peer = cls;
715
716 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
717 "MQ error in queue to %s: %d\n",
718 GNUNET_i2s (&peer->target),
719 (int) error);
720 peer_destroy (peer);
721}
722
723
724/**
725 * Convert UDP bind specification to a `struct sockaddr *`
726 *
727 * @param bindto bind specification to convert
728 * @param[out] sock_len set to the length of the address
729 * @return converted bindto specification
730 */
731static struct sockaddr *
732udp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
733{
734 struct sockaddr *in;
735 unsigned int port;
736 char dummy[2];
737 char *colon;
738 char *cp;
739
740 if (1 == sscanf (bindto, "%u%1s", &port, dummy))
741 {
742 /* interpreting value as just a PORT number */
743 if (port > UINT16_MAX)
744 {
745 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
746 "BINDTO specification `%s' invalid: value too large for port\n",
747 bindto);
748 return NULL;
749 }
750 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
751 (GNUNET_YES ==
752 GNUNET_CONFIGURATION_get_value_yesno (cfg,
753 COMMUNICATOR_CONFIG_SECTION,
754 "DISABLE_V6")))
755 {
756 struct sockaddr_in *i4;
757
758 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
759 i4->sin_family = AF_INET;
760 i4->sin_port = htons ((uint16_t) port);
761 *sock_len = sizeof(struct sockaddr_in);
762 in = (struct sockaddr *) i4;
763 }
764 else
765 {
766 struct sockaddr_in6 *i6;
767
768 i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
769 i6->sin6_family = AF_INET6;
770 i6->sin6_port = htons ((uint16_t) port);
771 *sock_len = sizeof(struct sockaddr_in6);
772 in = (struct sockaddr *) i6;
773 }
774 return in;
775 }
776 cp = GNUNET_strdup (bindto);
777 colon = strrchr (cp, ':');
778 if (NULL != colon)
779 {
780 /* interpret value after colon as port */
781 *colon = '\0';
782 colon++;
783 if (1 == sscanf (colon, "%u%1s", &port, dummy))
784 {
785 /* interpreting value as just a PORT number */
786 if (port > UINT16_MAX)
787 {
788 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
789 "BINDTO specification `%s' invalid: value too large for port\n",
790 bindto);
791 GNUNET_free (cp);
792 return NULL;
793 }
794 }
795 else
796 {
797 GNUNET_log (
798 GNUNET_ERROR_TYPE_ERROR,
799 "BINDTO specification `%s' invalid: last ':' not followed by number\n",
800 bindto);
801 GNUNET_free (cp);
802 return NULL;
803 }
804 }
805 else
806 {
807 /* interpret missing port as 0, aka pick any free one */
808 port = 0;
809 }
810 {
811 /* try IPv4 */
812 struct sockaddr_in v4;
813
814 memset (&v4, 0, sizeof(v4));
815 if (1 == inet_pton (AF_INET, cp, &v4.sin_addr))
816 {
817 v4.sin_family = AF_INET;
818 v4.sin_port = htons ((uint16_t) port);
819#if HAVE_SOCKADDR_IN_SIN_LEN
820 v4.sin_len = sizeof(struct sockaddr_in);
821#endif
822 in = GNUNET_memdup (&v4, sizeof(struct sockaddr_in));
823 *sock_len = sizeof(struct sockaddr_in);
824 GNUNET_free (cp);
825 return in;
826 }
827 }
828 {
829 /* try IPv6 */
830 struct sockaddr_in6 v6;
831 const char *start;
832
833 memset (&v6, 0, sizeof(v6));
834 start = cp;
835 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
836 {
837 start++; /* skip over '[' */
838 cp[strlen (cp) - 1] = '\0'; /* eat ']' */
839 }
840 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
841 {
842 v6.sin6_family = AF_INET6;
843 v6.sin6_port = htons ((uint16_t) port);
844#if HAVE_SOCKADDR_IN_SIN_LEN
845 v6.sin6_len = sizeof(sizeof(struct sockaddr_in6));
846#endif
847 in = GNUNET_memdup (&v6, sizeof(v6));
848 *sock_len = sizeof(v6);
849 GNUNET_free (cp);
850 return in;
851 }
852 }
853 /* #5528 FIXME (feature!): maybe also try getnameinfo()? */
854 GNUNET_free (cp);
855 return NULL;
856}
857
858
859/**
860 * Setup the MQ for the @a peer. If a queue exists,
861 * the existing one is destroyed. Then the MTU is
862 * recalculated and a fresh queue is initialized.
863 *
864 * @param peer peer to setup MQ for
865 */
866static void
867setup_peer_mq (struct PeerAddress *peer)
868{
869 size_t base_mtu;
870
871 switch (peer->address->sa_family)
872 {
873 case AF_INET:
874 base_mtu = 1480 /* Ethernet MTU, 1500 - Ethernet header - VLAN tag */
875 - sizeof(struct GNUNET_TUN_IPv4Header) /* 20 */
876 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
877 break;
878
879 case AF_INET6:
880 base_mtu = 1280 /* Minimum MTU required by IPv6 */
881 - sizeof(struct GNUNET_TUN_IPv6Header) /* 40 */
882 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
883 break;
884
885 default:
886 GNUNET_assert (0);
887 break;
888 }
889 /* MTU == base_mtu */
890 peer->d_mtu = base_mtu;
891
892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
893 "Setting up MQs and QHs\n");
894 /* => Effective MTU for CORE will range from 1080 (IPv6 + KX) to
895 1404 (IPv4 + Box) bytes, depending on circumstances... */
896
897 if (NULL == peer->d_mq)
898 peer->d_mq = GNUNET_MQ_queue_for_callbacks (&mq_send_d,
899 &mq_destroy_d,
900 &mq_cancel,
901 peer,
902 NULL,
903 &mq_error,
904 peer);
905 peer->d_qh =
906 GNUNET_TRANSPORT_communicator_mq_add (ch,
907 &peer->target,
908 peer->foreign_addr,
909 1000,
910 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
911 0, /* Priority */
912 peer->nt,
913 GNUNET_TRANSPORT_CS_OUTBOUND,
914 peer->d_mq);
915}
916
917
918/**
919 * Taken from: UDP communicator
920 * Converts @a address to the address string format used by this
921 * communicator in HELLOs.
922 *
923 * @param address the address to convert, must be AF_INET or AF_INET6.
924 * @param address_len number of bytes in @a address
925 * @return string representation of @a address
926 */
927static char *
928sockaddr_to_udpaddr_string (const struct sockaddr *address,
929 socklen_t address_len)
930{
931 char *ret;
932
933 switch (address->sa_family)
934 {
935 case AF_INET:
936 GNUNET_asprintf (&ret,
937 "%s-%s",
938 COMMUNICATOR_ADDRESS_PREFIX,
939 GNUNET_a2s (address, address_len));
940 break;
941
942 case AF_INET6:
943 GNUNET_asprintf (&ret,
944 "%s-%s",
945 COMMUNICATOR_ADDRESS_PREFIX,
946 GNUNET_a2s (address, address_len));
947 break;
948
949 default:
950 GNUNET_assert (0);
951 }
952 return ret;
953}
954
955
956/**
957 * Function called when the transport service has received a
958 * backchannel message for this communicator (!) via a different return
959 * path. Should be an acknowledgement.
960 *
961 * @param cls closure, NULL
962 * @param sender which peer sent the notification
963 * @param msg payload
964 */
965static void
966notify_cb (void *cls,
967 const struct GNUNET_PeerIdentity *sender,
968 const struct GNUNET_MessageHeader *msg)
969{
970 // const struct UDPAck *ack;
971
972 // (void) cls;
973 // GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
974 // "Storing UDPAck received from backchannel from %s\n",
975 // GNUNET_i2s_full (sender));
976 // if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK) ||
977 // (ntohs (msg->size) != sizeof(struct UDPAck)))
978 // {
979 // GNUNET_break_op (0);
980 // return;
981 // }
982 // ack = (const struct UDPAck *) msg;
983 // GNUNET_CONTAINER_multipeermap_get_multiple (receivers,
984 // sender,
985 // &handle_ack,
986 // (void *) ack);
987}
988
989
990/**
991 * Task run to check #receiver_heap and #sender_heap for timeouts.
992 *
993 * @param cls unused, NULL
994 */
995static void
996check_timeouts (void *cls)
997{
998 // struct GNUNET_TIME_Relative st;
999 // struct GNUNET_TIME_Relative rt;
1000 // struct GNUNET_TIME_Relative delay;
1001 // struct ReceiverAddress *receiver;
1002 // struct SenderAddress *sender;
1003
1004 // (void) cls;
1005 // timeout_task = NULL;
1006 // rt = GNUNET_TIME_UNIT_FOREVER_REL;
1007 // while (NULL != (receiver = GNUNET_CONTAINER_heap_peek (receivers_heap)))
1008 // {
1009 // /* if (GNUNET_YES != receiver->receiver_destroy_called) */
1010 // /* { */
1011 // rt = GNUNET_TIME_absolute_get_remaining (receiver->timeout);
1012 // if (0 != rt.rel_value_us)
1013 // break;
1014 // GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1015 // "Receiver timed out\n");
1016 // receiver_destroy (receiver);
1017 // // }
1018 // }
1019 // st = GNUNET_TIME_UNIT_FOREVER_REL;
1020 // while (NULL != (sender = GNUNET_CONTAINER_heap_peek (senders_heap)))
1021 // {
1022 // if (GNUNET_YES != sender->sender_destroy_called)
1023 // {
1024 // st = GNUNET_TIME_absolute_get_remaining (sender->timeout);
1025 // if (0 != st.rel_value_us)
1026 // break;
1027 // sender_destroy (sender);
1028 // }
1029 // }
1030 // delay = GNUNET_TIME_relative_min (rt, st);
1031 // if (delay.rel_value_us < GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1032 // timeout_task = GNUNET_SCHEDULER_add_delayed (delay, &check_timeouts, NULL);
1033}
1034
1035
1036/**
1037 * Function called by the transport service to initialize a
1038 * message queue given address information about another peer.
1039 * If and when the communication channel is established, the
1040 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
1041 * to notify the service that the channel is now up. It is
1042 * the responsibility of the communicator to manage sane
1043 * retries and timeouts for any @a peer/@a address combination
1044 * provided by the transport service. Timeouts and retries
1045 * do not need to be signalled to the transport service.
1046 *
1047 * @param cls closure
1048 * @param peer identity of the other peer
1049 * @param address where to send the message, human-readable
1050 * communicator-specific format, 0-terminated, UTF-8
1051 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is
1052 * invalid
1053 */
1054static int
1055mq_init (void *cls, const struct GNUNET_PeerIdentity *peer_id, const
1056 char *address)
1057{
1058 struct PeerAddress *peer;
1059 const char *path;
1060 struct sockaddr *in;
1061 socklen_t in_len;
1062 struct GNUNET_HashCode addr_key;
1063 uint8_t scid[LOCAL_CONN_ID_LEN];
1064
1065 struct quic_conn *q_conn;
1066 char *bindto;
1067 socklen_t local_in_len;
1068 struct sockaddr *local_addr;
1069
1070 if (GNUNET_OK !=
1071 GNUNET_CONFIGURATION_get_value_string (cfg,
1072 COMMUNICATOR_CONFIG_SECTION,
1073 "BINDTO",
1074 &bindto))
1075 {
1076 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1077 COMMUNICATOR_CONFIG_SECTION,
1078 "BINDTO");
1079 return GNUNET_SYSERR;
1080 }
1081 local_addr = udp_address_to_sockaddr (bindto, &local_in_len);
1082
1083 if (0 != strncmp (address,
1084 COMMUNICATOR_ADDRESS_PREFIX "-",
1085 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
1086 {
1087 GNUNET_break_op (0);
1088 return GNUNET_SYSERR;
1089 }
1090 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
1091 in = udp_address_to_sockaddr (path, &in_len);
1092 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "mq_init in_len length before: %d\n",
1093 in_len);
1094 /**
1095 * If we already have a queue with this peer, ignore
1096 */
1097 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "address string in mq_init: %s\n",
1098 address);
1099 GNUNET_CRYPTO_hash (address, strlen (address), &addr_key);
1100 peer = GNUNET_CONTAINER_multihashmap_get (addr_map, &addr_key);
1101 if (NULL != peer)
1102 {
1103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1104 "ignoring transport service mq request, we already have an mq with this peer (address)\n");
1105 return GNUNET_SYSERR;
1106 }
1107 peer = GNUNET_new (struct PeerAddress);
1108 peer->address = in;
1109 peer->address_len = in_len;
1110 peer->target = *peer_id;
1111 peer->id_rcvd = GNUNET_YES;
1112 peer->is_receiver = GNUNET_YES;
1113 peer->nt = GNUNET_NT_scanner_get_type (is, in, in_len);
1114 peer->timeout =
1115 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1116 GNUNET_STATISTICS_set (stats,
1117 "# peers active",
1118 GNUNET_CONTAINER_multihashmap_size (addr_map),
1119 GNUNET_NO);
1120 peer->foreign_addr =
1121 sockaddr_to_udpaddr_string (peer->address, peer->address_len);
1122 /**
1123 * Insert peer into hashmap
1124 */
1125 GNUNET_CONTAINER_multihashmap_put (addr_map, &addr_key,
1126 peer,
1127 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY);
1128 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1129 "mq_init added new peer to the addr map\n");
1130 /**
1131 * Before setting up peer mq, initiate a quic connection to the target (perform handshake w/ quiche)
1132 */
1133 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, scid,
1134 LOCAL_CONN_ID_LEN);
1135 q_conn = GNUNET_new (struct quic_conn);
1136 GNUNET_memcpy (q_conn->cid, scid, LOCAL_CONN_ID_LEN);
1137 peer->conn = q_conn;
1138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1139 "attempting to perform QUIC handshake with peer\n");
1140 q_conn->conn = quiche_connect (peer->foreign_addr, scid, LOCAL_CONN_ID_LEN,
1141 local_addr,
1142 local_in_len, peer->address, peer->address_len,
1143 config);
1144 flush_egress (peer->conn);
1145 GNUNET_free (local_addr);
1146 return GNUNET_OK;
1147 /**
1148 * TODO: handle this
1149 */
1150 // if (NULL == timeout_task)
1151 // timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL);
1152}
1153
1154
1155static void
1156try_connection_reversal (void *cls,
1157 const struct sockaddr *addr,
1158 socklen_t addrlen)
1159{
1160 /* FIXME: support reversal: #5529 */
1161 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
1162 "No connection reversal implemented!");
1163}
1164
1165
1166/**
1167 * Signature of the callback passed to #GNUNET_NAT_register() for
1168 * a function to call whenever our set of 'valid' addresses changes.
1169 *
1170 * @param cls closure
1171 * @param app_ctx[in,out] location where the app can store stuff
1172 * on add and retrieve it on remove
1173 * @param add_remove #GNUNET_YES to add a new public IP address,
1174 * #GNUNET_NO to remove a previous (now invalid) one
1175 * @param ac address class the address belongs to
1176 * @param addr either the previous or the new public IP address
1177 * @param addrlen actual length of the @a addr
1178 */
1179static void
1180nat_address_cb (void *cls,
1181 void **app_ctx,
1182 int add_remove,
1183 enum GNUNET_NAT_AddressClass ac,
1184 const struct sockaddr *addr,
1185 socklen_t addrlen)
1186{
1187 char *my_addr;
1188 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
1189
1190 if (GNUNET_YES == add_remove)
1191 {
1192 enum GNUNET_NetworkType nt;
1193
1194 GNUNET_asprintf (&my_addr,
1195 "%s-%s",
1196 COMMUNICATOR_ADDRESS_PREFIX,
1197 GNUNET_a2s (addr, addrlen));
1198 nt = GNUNET_NT_scanner_get_type (is, addr, addrlen);
1199 ai =
1200 GNUNET_TRANSPORT_communicator_address_add (ch,
1201 my_addr,
1202 nt,
1203 GNUNET_TIME_UNIT_FOREVER_REL);
1204 GNUNET_free (my_addr);
1205 *app_ctx = ai;
1206 }
1207 else
1208 {
1209 ai = *app_ctx;
1210 GNUNET_TRANSPORT_communicator_address_remove (ai);
1211 *app_ctx = NULL;
1212 }
1213}
1214
1215
1216/**
1217 * Shutdown the QUIC communicator.
1218 *
1219 * @param cls NULL (always)
1220 */
1221static void
1222do_shutdown (void *cls)
1223{
1224 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1225 "do_shutdown\n");
1226 GNUNET_CONTAINER_multihashmap_iterate (addr_map, &get_peer_delete_it, NULL);
1227 GNUNET_CONTAINER_multihashmap_destroy (addr_map);
1228 quiche_config_free (config);
1229
1230 if (NULL != timeout_task)
1231 {
1232 GNUNET_SCHEDULER_cancel (timeout_task);
1233 timeout_task = NULL;
1234 }
1235 if (NULL != read_task)
1236 {
1237 GNUNET_SCHEDULER_cancel (read_task);
1238 read_task = NULL;
1239 }
1240 if (NULL != udp_sock)
1241 {
1242 GNUNET_break (GNUNET_OK ==
1243 GNUNET_NETWORK_socket_close (udp_sock));
1244 udp_sock = NULL;
1245 }
1246 if (NULL != ch)
1247 {
1248 GNUNET_TRANSPORT_communicator_disconnect (ch);
1249 ch = NULL;
1250 }
1251 if (NULL != ah)
1252 {
1253 GNUNET_TRANSPORT_application_done (ah);
1254 ah = NULL;
1255 }
1256 if (NULL != my_private_key)
1257 {
1258 GNUNET_free (my_private_key);
1259 my_private_key = NULL;
1260 }
1261 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1262 "do_shutdown finished\n");
1263}
1264
1265
1266static void
1267sock_read (void *cls)
1268{
1269 struct sockaddr_storage sa;
1270 struct sockaddr_in *addr_verify;
1271 socklen_t salen = sizeof(sa);
1272 uint8_t buf[UINT16_MAX];
1273 uint8_t out[MAX_DATAGRAM_SIZE];
1274 ssize_t rcvd;
1275
1276 ssize_t process_pkt;
1277 struct QUIC_header quic_header;
1278 uint8_t new_cid[LOCAL_CONN_ID_LEN];
1279
1280 struct PeerAddress *peer;
1281 struct GNUNET_HashCode addr_key;
1282
1283 (void) cls;
1284 quic_header.scid_len = sizeof(quic_header.scid);
1285 quic_header.dcid_len = sizeof(quic_header.dcid);
1286 quic_header.odcid_len = sizeof(quic_header.odcid);
1287 quic_header.token_len = sizeof(quic_header.token);
1288 /**
1289 * Get local_addr, in_len for quiche
1290 */
1291 char *bindto;
1292 socklen_t in_len;
1293 if (GNUNET_OK !=
1294 GNUNET_CONFIGURATION_get_value_string (cfg,
1295 COMMUNICATOR_CONFIG_SECTION,
1296 "BINDTO",
1297 &bindto))
1298 {
1299 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1300 COMMUNICATOR_CONFIG_SECTION,
1301 "BINDTO");
1302 return;
1303 }
1304 struct sockaddr *local_addr = udp_address_to_sockaddr (bindto, &in_len);
1305
1306 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1307 udp_sock,
1308 &sock_read,
1309 NULL);
1310 while (1)
1311 {
1312 rcvd = GNUNET_NETWORK_socket_recvfrom (udp_sock,
1313 buf,
1314 sizeof(buf),
1315 (struct sockaddr *) &sa,
1316 &salen);
1317 if (-1 == rcvd)
1318 {
1319 if (EAGAIN == errno)
1320 break; // We are done reading data
1321 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
1322 return;
1323 }
1324
1325 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1326 "Read %lu bytes\n", rcvd);
1327
1328 if (-1 == rcvd)
1329 {
1330 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
1331 return;
1332 }
1333 /**
1334 * FIXME: hashing address string vs ip/port. It is not ideal that
1335 * we hash the string, instead of the binary representation, but
1336 * for now it is certainly less code.
1337 * Note that simply hashing the sockaddr does NOT work because the
1338 * the struct is not portable.
1339 */
1340 const char *addr_string = sockaddr_to_udpaddr_string ((const struct
1341 sockaddr *) &sa,
1342 salen);
1343 GNUNET_CRYPTO_hash (addr_string, strlen (addr_string),
1344 &addr_key);
1345 GNUNET_free (addr_string);
1346 peer = GNUNET_CONTAINER_multihashmap_get (addr_map, &addr_key);
1347
1348 if (NULL == peer)
1349 {
1350 /**
1351 * Create new PeerAddress (receiver) with id_rcvd = false
1352 */
1353 peer = GNUNET_new (struct PeerAddress);
1354 peer->address = GNUNET_memdup (&sa, salen);
1355 peer->address_len = salen;
1356 peer->id_rcvd = GNUNET_NO;
1357 peer->id_sent = GNUNET_NO;
1358 peer->is_receiver = GNUNET_NO;
1359 peer->conn = NULL;
1360 peer->foreign_addr = sockaddr_to_udpaddr_string (peer->address,
1361 peer->address_len);
1362 /**
1363 * TODO: after connection established
1364 */
1365 // setup_peer_mq (peer);
1366 if (GNUNET_SYSERR == GNUNET_CONTAINER_multihashmap_put (addr_map,
1367 &addr_key,
1368 peer,
1369 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
1370 {
1371 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1372 "tried to add duplicate address into address map\n");
1373 return;
1374 }
1375 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1376 "sock_read added new peer to address map\n");
1377 }
1378
1379 /**
1380 * Parse QUIC info
1381 */
1382 int rc = quiche_header_info (buf, rcvd, LOCAL_CONN_ID_LEN,
1383 &quic_header.version,
1384 &quic_header.type, quic_header.scid,
1385 &quic_header.scid_len, quic_header.dcid,
1386 &quic_header.dcid_len,
1387 quic_header.token, &quic_header.token_len);
1388 if (0 > rc)
1389 {
1390 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1391 "failed to parse quic header: %d\n",
1392 rc);
1393 return;
1394 }
1395
1396 /**
1397 * New QUIC connection with peer
1398 */
1399 if (NULL == peer->conn)
1400 {
1401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1402 "attempting to create new connection\n");
1403 if (0 == quiche_version_is_supported (quic_header.version))
1404 {
1405 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1406 "quic version negotiation initiated\n");
1407 /**
1408 * FIXME variables are redeclared often. Refactor either
1409 * to declare variables once in the beginning or refactor into
1410 * method.
1411 *
1412 * Write a version negotiation packet to "out"
1413 */
1414 ssize_t written = quiche_negotiate_version (quic_header.scid,
1415 quic_header.scid_len,
1416 quic_header.dcid,
1417 quic_header.dcid_len,
1418 out, sizeof(out));
1419 if (0 > written)
1420 {
1421 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1422 "quiche failed to generate version negotiation packet\n");
1423 return;
1424 }
1425 ssize_t sent = GNUNET_NETWORK_socket_sendto (udp_sock,
1426 out,
1427 written,
1428 (struct sockaddr*) &sa,
1429 salen);
1430 if (sent != written)
1431 {
1432 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1433 "failed to send version negotiation packet to peer\n");
1434 return;
1435 }
1436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1437 "sent %zd bytes to peer during version negotiation\n",
1438 sent);
1439 return;
1440 }
1441
1442 if (0 == quic_header.token_len)
1443 {
1444 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "quic stateless retry\n");
1445 mint_token (quic_header.dcid, quic_header.dcid_len, &sa, salen,
1446 quic_header.token, &quic_header.token_len);
1447
1448 uint8_t new_cid[LOCAL_CONN_ID_LEN];
1449 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_STRONG, new_cid,
1450 LOCAL_CONN_ID_LEN);
1451
1452 ssize_t written = quiche_retry (quic_header.scid, quic_header.scid_len,
1453 quic_header.dcid, quic_header.dcid_len,
1454 new_cid, LOCAL_CONN_ID_LEN,
1455 quic_header.token,
1456 quic_header.token_len,
1457 quic_header.version, out, sizeof(out));
1458 if (0 > written)
1459 {
1460 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1461 "quiche failed to write retry packet\n");
1462 return;
1463 }
1464 ssize_t sent = GNUNET_NETWORK_socket_sendto (udp_sock,
1465 out,
1466 written,
1467 (struct sockaddr*) &sa,
1468 salen);
1469 if (written != sent)
1470 {
1471 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "failed to send retry packet\n");
1472 return;
1473 }
1474
1475 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "sent %zd bytes\n", sent);
1476 continue;
1477 }
1478
1479 if (GNUNET_OK != validate_token (quic_header.token, quic_header.token_len,
1480 &sa, salen,
1481 quic_header.odcid,
1482 &quic_header.odcid_len))
1483 {
1484 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1485 "invalid address validation token created\n");
1486 return;
1487 }
1488 peer->conn = create_conn (quic_header.dcid, quic_header.dcid_len,
1489 quic_header.odcid, quic_header.odcid_len,
1490 local_addr, in_len,
1491 &sa, salen);
1492 if (NULL == peer->conn)
1493 {
1494 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1495 "failed to create quic connection with peer\n");
1496 return;
1497 }
1498 } // null connection
1499
1500 quiche_recv_info recv_info = {
1501 (struct sockaddr *) &sa,
1502 salen,
1503
1504 local_addr,
1505 in_len,
1506 };
1507 /**
1508 * Send our PeerIdentity if the connection is established now
1509 */
1510 if (quiche_conn_is_established (peer->conn->conn) && ! peer->id_sent &&
1511 peer->is_receiver)
1512 {
1513 ssize_t send_len;
1514
1515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1516 "handshake established with peer, sending our peer id\n");
1517 send_len = quiche_conn_stream_send (peer->conn->conn, STREAMID_BI,
1518 (const uint8_t *) &my_identity,
1519 sizeof(my_identity),
1520 false);
1521 if (0 > send_len)
1522 {
1523 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1524 "failed to write peer identity packet. quiche error: %zd\n",
1525 send_len);
1526 return;
1527 }
1528 flush_egress (peer->conn);
1529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "peer identity sent to peer\n");
1530 peer->id_sent = GNUNET_YES;
1531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "setting up peer mq\n");
1532 setup_peer_mq (peer);
1533 /**
1534 * After this, we should be all good to send/recv data
1535 */
1536 }
1537 process_pkt = quiche_conn_recv (peer->conn->conn, buf, rcvd, &recv_info);
1538 if (0 > process_pkt)
1539 {
1540 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1541 "quiche failed to process received packet: %zd\n",
1542 process_pkt);
1543 return;
1544 }
1545 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1546 "quiche processed %zd bytes\n", process_pkt);
1547 // Check for data on all available streams if the connection is established
1548 if (GNUNET_YES == quiche_conn_is_established (peer->conn->conn))
1549 {
1550 recv_from_streams (peer);
1551 }
1552 /**
1553 * TODO: Should we use a list instead of hashmap?
1554 * Overhead for hashing function, O(1) retrieval vs O(n) iteration with n=30?
1555 *
1556 * TODO: Is iteration necessary as in the quiche server example?
1557 */
1558 quiche_stats stats;
1559 quiche_path_stats path_stats;
1560
1561 flush_egress (peer->conn);
1562
1563 if (quiche_conn_is_closed (peer->conn->conn))
1564 {
1565 quiche_conn_stats (peer->conn->conn, &stats);
1566 quiche_conn_path_stats (peer->conn->conn, 0, &path_stats);
1567
1568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1569 "connection closed. quiche stats: sent=%zu, recv=%zu\n",
1570 stats.sent, stats.recv);
1571 peer_destroy (peer);
1572 }
1573 }
1574 GNUNET_free (local_addr);
1575}
1576
1577
1578/**
1579 * Setup communicator and launch network interactions.
1580 *
1581 * @param cls NULL (always)
1582 * @param args remaining command-line arguments
1583 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
1584 * @param c configuration
1585 */
1586static void
1587run (void *cls,
1588 char *const *args,
1589 const char *cfgfile,
1590 const struct GNUNET_CONFIGURATION_Handle *c)
1591{
1592 char *bindto;
1593 struct sockaddr *in;
1594 socklen_t in_len;
1595 struct sockaddr_storage in_sto;
1596 socklen_t sto_len;
1597
1598 (void) cls;
1599 cfg = c;
1600
1601 if (GNUNET_OK !=
1602 GNUNET_CONFIGURATION_get_value_string (cfg,
1603 COMMUNICATOR_CONFIG_SECTION,
1604 "BINDTO",
1605 &bindto))
1606 {
1607 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1608 COMMUNICATOR_CONFIG_SECTION,
1609 "BINDTO");
1610 return;
1611 }
1612
1613 in = udp_address_to_sockaddr (bindto, &in_len);
1614
1615 if (NULL == in)
1616 {
1617 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1618 "Failed to setup UDP socket address with path `%s'\n",
1619 bindto);
1620 GNUNET_free (bindto);
1621 return;
1622 }
1623 udp_sock =
1624 GNUNET_NETWORK_socket_create (in->sa_family,
1625 SOCK_DGRAM,
1626 IPPROTO_UDP);
1627 if (NULL == udp_sock)
1628 {
1629 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1630 GNUNET_free (in);
1631 GNUNET_free (bindto);
1632 return;
1633 }
1634 if (AF_INET6 == in->sa_family)
1635 have_v6_socket = GNUNET_YES;
1636 if (GNUNET_OK !=
1637 GNUNET_NETWORK_socket_bind (udp_sock,
1638 in,
1639 in_len))
1640 {
1641 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
1642 "bind",
1643 bindto);
1644 GNUNET_NETWORK_socket_close (udp_sock);
1645 udp_sock = NULL;
1646 GNUNET_free (in);
1647 GNUNET_free (bindto);
1648 return;
1649 }
1650 sto_len = sizeof(in_sto);
1651 if (0 != getsockname (GNUNET_NETWORK_get_fd (udp_sock),
1652 (struct sockaddr *) &in_sto,
1653 &sto_len))
1654 {
1655 memcpy (&in_sto, in, in_len);
1656 sto_len = in_len;
1657 }
1658 GNUNET_free (in);
1659 GNUNET_free (bindto);
1660 in = (struct sockaddr *) &in_sto;
1661 in_len = sto_len;
1662 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1663 "transport",
1664 "Bound to `%s'\n",
1665 GNUNET_a2s ((const struct sockaddr *) &in_sto,
1666 sto_len));
1667 switch (in->sa_family)
1668 {
1669 case AF_INET:
1670 my_port = ntohs (((struct sockaddr_in *) in)->sin_port);
1671 break;
1672
1673 case AF_INET6:
1674 my_port = ntohs (((struct sockaddr_in6 *) in)->sin6_port);
1675 break;
1676
1677 default:
1678 GNUNET_break (0);
1679 my_port = 0;
1680 }
1681 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1682 /**
1683 * Setup QUICHE configuration
1684 */
1685 config = quiche_config_new (QUICHE_PROTOCOL_VERSION);
1686 quiche_config_verify_peer (config, false);
1687 /**
1688 * TODO: configure TLS cert
1689 */
1690 quiche_config_load_cert_chain_from_pem_file (config, "./cert.crt");
1691 quiche_config_load_priv_key_from_pem_file (config, "./cert.key");
1692 quiche_config_set_application_protos (config,
1693 (uint8_t *)
1694 "\x0ahq-interop\x05hq-29\x05hq-28\x05hq-27\x08http/0.9",
1695 38);
1696 quiche_config_set_max_idle_timeout (config, 5000);
1697 quiche_config_set_max_recv_udp_payload_size (config, 1200);
1698 quiche_config_set_max_send_udp_payload_size (config, 1200);
1699 quiche_config_set_initial_max_data (config, 10000000);
1700 quiche_config_set_initial_max_stream_data_bidi_local (config, 1000000);
1701 quiche_config_set_initial_max_stream_data_bidi_remote (config, 1000000);
1702 quiche_config_set_initial_max_stream_data_uni (config, 1000000);
1703 quiche_config_set_initial_max_streams_bidi (config, 100);
1704 quiche_config_set_initial_max_streams_uni (config, 100);
1705 quiche_config_set_cc_algorithm (config, QUICHE_CC_RENO);
1706 quiche_config_set_disable_active_migration (config, true);
1707 addr_map = GNUNET_CONTAINER_multihashmap_create (2, GNUNET_NO);
1708 /**
1709 * Get our public key for initial packet
1710 */
1711 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1712 if (NULL == my_private_key)
1713 {
1714 GNUNET_log (
1715 GNUNET_ERROR_TYPE_ERROR,
1716 _ (
1717 "Transport service is lacking key configuration settings. Exiting.\n"));
1718 GNUNET_SCHEDULER_shutdown ();
1719 return;
1720 }
1721 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
1722 /* start reading */
1723 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1724 udp_sock,
1725 &sock_read,
1726 NULL);
1727 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
1728 COMMUNICATOR_CONFIG_SECTION,
1729 COMMUNICATOR_ADDRESS_PREFIX,
1730 GNUNET_TRANSPORT_CC_RELIABLE,
1731 &mq_init,
1732 NULL,
1733 &notify_cb,
1734 NULL);
1735 is = GNUNET_NT_scanner_init ();
1736 nat = GNUNET_NAT_register (cfg,
1737 COMMUNICATOR_CONFIG_SECTION,
1738 IPPROTO_UDP,
1739 1 /* one address */,
1740 (const struct sockaddr **) &in,
1741 &in_len,
1742 &nat_address_cb,
1743 try_connection_reversal,
1744 NULL /* closure */);
1745 if (NULL == ch)
1746 {
1747 GNUNET_break (0);
1748 GNUNET_SCHEDULER_shutdown ();
1749 return;
1750 }
1751 ah = GNUNET_TRANSPORT_application_init (cfg);
1752 if (NULL == ah)
1753 {
1754 GNUNET_break (0);
1755 GNUNET_SCHEDULER_shutdown ();
1756 return;
1757 }
1758
1759 /* start broadcasting */
1760 // if (GNUNET_YES !=
1761 // GNUNET_CONFIGURATION_get_value_yesno (cfg,
1762 // COMMUNICATOR_CONFIG_SECTION,
1763 // "DISABLE_BROADCAST"))
1764 // {
1765 // broadcast_task = GNUNET_SCHEDULER_add_now (&do_broadcast, NULL);
1766 // }
1767}
1768
1769
1770int
1771main (int argc, char *const *argv)
1772{
1773 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1774 GNUNET_GETOPT_OPTION_END
1775 };
1776 int ret;
1777
1778 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
1779 "transport",
1780 "Starting quic communicator\n");
1781 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1782 return 2;
1783
1784 ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
1785 argv,
1786 "gnunet-communicator-quic",
1787 _ ("GNUnet QUIC communicator"),
1788 options,
1789 &run,
1790 NULL))
1791 ? 0
1792 : 1;
1793 GNUNET_free_nz ((void *) argv);
1794 return ret;
1795}
diff --git a/src/service/transport/gnunet-communicator-tcp.c b/src/service/transport/gnunet-communicator-tcp.c
new file mode 100644
index 000000000..02f5fc9f9
--- /dev/null
+++ b/src/service/transport/gnunet-communicator-tcp.c
@@ -0,0 +1,4182 @@
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 "gnunet_common.h"
31#include "platform.h"
32#include "gnunet_util_lib.h"
33#include "gnunet_core_service.h"
34#include "gnunet_peerstore_service.h"
35#include "gnunet_protocols.h"
36#include "gnunet_signatures.h"
37#include "gnunet_constants.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/**
45 * How long until we give up on establishing an NAT connection?
46 * Must be > 4 RTT
47 */
48#define NAT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
49
50/**
51 * How long do we believe our addresses to remain up (before
52 * the other peer should revalidate).
53 */
54#define ADDRESS_VALIDITY_PERIOD \
55 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
56
57/**
58 * How many messages do we keep at most in the queue to the
59 * transport service before we start to drop (default,
60 * can be changed via the configuration file).
61 * Should be _below_ the level of the communicator API, as
62 * otherwise we may read messages just to have them dropped
63 * by the communicator API.
64 */
65#define DEFAULT_MAX_QUEUE_LENGTH 8
66
67/**
68 * Size of our IO buffers for ciphertext data. Must be at
69 * least UINT_MAX + sizeof (struct TCPBox).
70 */
71#define BUF_SIZE (2 * 64 * 1024 + sizeof(struct TCPBox))
72
73/**
74 * How often do we rekey based on time (at least)
75 */
76#define DEFAULT_REKEY_INTERVAL GNUNET_TIME_UNIT_DAYS
77
78/**
79 * How long do we wait until we must have received the initial KX?
80 */
81#define PROTO_QUEUE_TIMEOUT GNUNET_TIME_UNIT_MINUTES
82
83/**
84 * How often do we rekey based on number of bytes transmitted?
85 * (additionally randomized). Currently 400 MB
86 */
87#define REKEY_MAX_BYTES (1024LLU * 1024 * 400)
88
89/**
90 * Size of the initial key exchange message sent first in both
91 * directions.
92 */
93#define INITIAL_KX_SIZE \
94 (sizeof(struct GNUNET_CRYPTO_EcdhePublicKey) \
95 + sizeof(struct TCPConfirmation))
96
97/**
98 * Size of the initial core key exchange messages.
99 */
100#define INITIAL_CORE_KX_SIZE \
101 (sizeof(struct EphemeralKeyMessage) \
102 + sizeof(struct PingMessage) \
103 + sizeof(struct PongMessage))
104
105/**
106 * Address prefix used by the communicator.
107 */
108#define COMMUNICATOR_ADDRESS_PREFIX "tcp"
109
110/**
111 * Configuration section used by the communicator.
112 */
113#define COMMUNICATOR_CONFIG_SECTION "communicator-tcp"
114
115GNUNET_NETWORK_STRUCT_BEGIN
116
117
118/**
119 * Signature we use to verify that the ephemeral key was really chosen by
120 * the specified sender.
121 */
122struct TcpHandshakeSignature
123{
124 /**
125 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE
126 */
127 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
128
129 /**
130 * Identity of the inititor of the TCP connection (TCP client).
131 */
132 struct GNUNET_PeerIdentity sender;
133
134 /**
135 * Presumed identity of the target of the TCP connection (TCP server)
136 */
137 struct GNUNET_PeerIdentity receiver;
138
139 /**
140 * Ephemeral key used by the @e sender.
141 */
142 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
143
144 /**
145 * Monotonic time of @e sender, to possibly help detect replay attacks
146 * (if receiver persists times by sender).
147 */
148 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
149
150 /**
151 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
152 */
153 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
154};
155
156/**
157 * Signature we use to verify that the ack from the receiver of the ephemeral key was really send by
158 * the specified sender.
159 */
160struct TcpHandshakeAckSignature
161{
162 /**
163 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK
164 */
165 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
166
167 /**
168 * Identity of the inititor of the TCP connection (TCP client).
169 */
170 struct GNUNET_PeerIdentity sender;
171
172 /**
173 * Presumed identity of the target of the TCP connection (TCP server)
174 */
175 struct GNUNET_PeerIdentity receiver;
176
177 /**
178 * Monotonic time of @e sender, to possibly help detect replay attacks
179 * (if receiver persists times by sender).
180 */
181 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
182
183 /**
184 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
185 */
186 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
187};
188
189/**
190 * Encrypted continuation of TCP initial handshake.
191 */
192struct TCPConfirmation
193{
194 /**
195 * Sender's identity
196 */
197 struct GNUNET_PeerIdentity sender;
198
199 /**
200 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE
201 */
202 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
203
204 /**
205 * Monotonic time of @e sender, to possibly help detect replay attacks
206 * (if receiver persists times by sender).
207 */
208 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
209
210 /**
211 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
212 */
213 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
214
215};
216
217/**
218 * Ack for the encrypted continuation of TCP initial handshake.
219 */
220struct TCPConfirmationAck
221{
222
223
224 /**
225 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK.
226 */
227 struct GNUNET_MessageHeader header;
228
229 /**
230 * Sender's identity
231 */
232 struct GNUNET_PeerIdentity sender;
233
234 /**
235 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK
236 */
237 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
238
239 /**
240 * Monotonic time of @e sender, to possibly help detect replay attacks
241 * (if receiver persists times by sender).
242 */
243 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
244
245 /**
246 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
247 */
248 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
249
250};
251
252/**
253 * TCP message box. Always sent encrypted!
254 */
255struct TCPBox
256{
257 /**
258 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX. Warning: the
259 * header size EXCLUDES the size of the `struct TCPBox`. We usually
260 * never do this, but here the payload may truly be 64k *after* the
261 * TCPBox (as we have no MTU)!!
262 */
263 struct GNUNET_MessageHeader header;
264
265 /**
266 * HMAC for the following encrypted message. Yes, we MUST use
267 * mac-then-encrypt here, as we want to hide the message sizes on
268 * the wire (zero plaintext design!). Using CTR mode, padding oracle
269 * attacks do not apply. Besides, due to the use of ephemeral keys
270 * (hopefully with effective replay protection from monotonic time!)
271 * the attacker is limited in using the oracle.
272 */
273 struct GNUNET_ShortHashCode hmac;
274
275 /* followed by as may bytes of payload as indicated in @e header,
276 excluding the TCPBox itself! */
277};
278
279
280/**
281 * TCP rekey message box. Always sent encrypted! Data after
282 * this message will use the new key.
283 */
284struct TCPRekey
285{
286 /**
287 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY.
288 */
289 struct GNUNET_MessageHeader header;
290
291 /**
292 * HMAC for the following encrypted message. Yes, we MUST use
293 * mac-then-encrypt here, as we want to hide the message sizes on
294 * the wire (zero plaintext design!). Using CTR mode padding oracle
295 * attacks do not apply. Besides, due to the use of ephemeral keys
296 * (hopefully with effective replay protection from monotonic time!)
297 * the attacker is limited in using the oracle.
298 */
299 struct GNUNET_ShortHashCode hmac;
300
301 /**
302 * New ephemeral key.
303 */
304 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
305
306 /**
307 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY
308 */
309 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
310
311 /**
312 * Monotonic time of @e sender, to possibly help detect replay attacks
313 * (if receiver persists times by sender).
314 */
315 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
316};
317
318/**
319 * Signature we use to verify that the ephemeral key was really chosen by
320 * the specified sender.
321 */
322struct TcpRekeySignature
323{
324 /**
325 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY
326 */
327 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
328
329 /**
330 * Identity of the inititor of the TCP connection (TCP client).
331 */
332 struct GNUNET_PeerIdentity sender;
333
334 /**
335 * Presumed identity of the target of the TCP connection (TCP server)
336 */
337 struct GNUNET_PeerIdentity receiver;
338
339 /**
340 * Ephemeral key used by the @e sender.
341 */
342 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
343
344 /**
345 * Monotonic time of @e sender, to possibly help detect replay attacks
346 * (if receiver persists times by sender).
347 */
348 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
349};
350
351/**
352 * TCP finish. Sender asks for the connection to be closed.
353 * Needed/useful in case we drop RST/FIN packets on the GNUnet
354 * port due to the possibility of malicious RST/FIN injection.
355 */
356struct TCPFinish
357{
358 /**
359 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH.
360 */
361 struct GNUNET_MessageHeader header;
362
363 /**
364 * HMAC for the following encrypted message. Yes, we MUST use
365 * mac-then-encrypt here, as we want to hide the message sizes on
366 * the wire (zero plaintext design!). Using CTR mode padding oracle
367 * attacks do not apply. Besides, due to the use of ephemeral keys
368 * (hopefully with effective replay protection from monotonic time!)
369 * the attacker is limited in using the oracle.
370 */
371 struct GNUNET_ShortHashCode hmac;
372};
373
374/**
375 * Basically a WELCOME message, but with the purpose
376 * of giving the waiting peer a client handle to use
377 */
378struct TCPNATProbeMessage
379{
380 /**
381 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
382 */
383 struct GNUNET_MessageHeader header;
384
385 /**
386 * Identity of the sender of the message.
387 */
388 struct GNUNET_PeerIdentity clientIdentity;
389};
390
391GNUNET_NETWORK_STRUCT_END
392
393/**
394 * Struct for pending nat reversals.
395 */
396struct PendingReversal
397{
398 /*
399 * Timeout task.
400 */
401 struct GNUNET_SCHEDULER_Task *timeout_task;
402
403 /**
404 * To whom are we like to talk to.
405 */
406 struct GNUNET_PeerIdentity target;
407
408 /**
409 * Address the reversal was send to.
410 */
411 struct sockaddr *in;
412};
413
414/**
415 * Struct to use as closure.
416 */
417struct ListenTask
418{
419 /**
420 * ID of listen task
421 */
422 struct GNUNET_SCHEDULER_Task *listen_task;
423
424 /**
425 * Listen socket.
426 */
427 struct GNUNET_NETWORK_Handle *listen_sock;
428};
429
430/**
431 * Handle for a queue.
432 */
433struct Queue
434{
435 /**
436 * To whom are we talking to.
437 */
438 struct GNUNET_PeerIdentity target;
439
440 /**
441 * Listen socket.
442 */
443 struct GNUNET_NETWORK_Handle *listen_sock;
444
445 /**
446 * socket that we transmit all data with on this queue
447 */
448 struct GNUNET_NETWORK_Handle *sock;
449
450 /**
451 * cipher for decryption of incoming data.
452 */
453 gcry_cipher_hd_t in_cipher;
454
455 /**
456 * cipher for encryption of outgoing data.
457 */
458 gcry_cipher_hd_t out_cipher;
459
460 /**
461 * Key in hash map
462 */
463 struct GNUNET_HashCode key;
464
465 /**
466 * Shared secret for HMAC verification on incoming data.
467 */
468 struct GNUNET_HashCode in_hmac;
469
470 /**
471 * Shared secret for HMAC generation on outgoing data, ratcheted after
472 * each operation.
473 */
474 struct GNUNET_HashCode out_hmac;
475
476 /**
477 * ID of read task for this connection.
478 */
479 struct GNUNET_SCHEDULER_Task *read_task;
480
481 /**
482 * ID of write task for this connection.
483 */
484 struct GNUNET_SCHEDULER_Task *write_task;
485
486 /**
487 * Address of the other peer.
488 */
489 struct sockaddr *address;
490
491 /**
492 * How many more bytes may we sent with the current @e out_cipher
493 * before we should rekey?
494 */
495 uint64_t rekey_left_bytes;
496
497 /**
498 * Until what time may we sent with the current @e out_cipher
499 * before we should rekey?
500 */
501 struct GNUNET_TIME_Absolute rekey_time;
502
503 /**
504 * Length of the address.
505 */
506 socklen_t address_len;
507
508 /**
509 * Message queue we are providing for the #ch.
510 */
511 struct GNUNET_MQ_Handle *mq;
512
513 /**
514 * handle for this queue with the #ch.
515 */
516 struct GNUNET_TRANSPORT_QueueHandle *qh;
517
518 /**
519 * Number of bytes we currently have in our write queue.
520 */
521 unsigned long long bytes_in_queue;
522
523 /**
524 * Buffer for reading ciphertext from network into.
525 */
526 char cread_buf[BUF_SIZE];
527
528 /**
529 * buffer for writing ciphertext to network.
530 */
531 char cwrite_buf[BUF_SIZE];
532
533 /**
534 * Plaintext buffer for decrypted plaintext.
535 */
536 char pread_buf[UINT16_MAX + 1 + sizeof(struct TCPBox)];
537
538 /**
539 * Plaintext buffer for messages to be encrypted.
540 */
541 char pwrite_buf[UINT16_MAX + 1 + sizeof(struct TCPBox)];
542
543 /**
544 * At which offset in the ciphertext read buffer should we
545 * append more ciphertext for transmission next?
546 */
547 size_t cread_off;
548
549 /**
550 * At which offset in the ciphertext write buffer should we
551 * append more ciphertext from reading next?
552 */
553 size_t cwrite_off;
554
555 /**
556 * At which offset in the plaintext input buffer should we
557 * append more plaintext from decryption next?
558 */
559 size_t pread_off;
560
561 /**
562 * At which offset in the plaintext output buffer should we
563 * append more plaintext for encryption next?
564 */
565 size_t pwrite_off;
566
567 /**
568 * Timeout for this queue.
569 */
570 struct GNUNET_TIME_Absolute timeout;
571
572 /**
573 * How may messages did we pass from this queue to CORE for which we
574 * have yet to receive an acknoweldgement that CORE is done with
575 * them? If "large" (or even just non-zero), we should throttle
576 * reading to provide flow control. See also #DEFAULT_MAX_QUEUE_LENGTH
577 * and #max_queue_length.
578 */
579 unsigned int backpressure;
580
581 /**
582 * Which network type does this queue use?
583 */
584 enum GNUNET_NetworkType nt;
585
586 /**
587 * The connection status of this queue.
588 */
589 enum GNUNET_TRANSPORT_ConnectionStatus cs;
590
591 /**
592 * Is MQ awaiting a #GNUNET_MQ_impl_send_continue() call?
593 */
594 int mq_awaits_continue;
595
596 /**
597 * Did we enqueue a finish message and are closing down the queue?
598 */
599 int finishing;
600
601 /**
602 * Did we technically destroy this queue, but kept the allocation
603 * around because of @e backpressure not being zero yet? Used
604 * simply to delay the final #GNUNET_free() operation until
605 * #core_read_finished_cb() has been called.
606 */
607 int destroyed;
608
609 /**
610 * #GNUNET_YES if we just rekeyed and must thus possibly
611 * re-decrypt ciphertext.
612 */
613 int rekeyed;
614
615 /**
616 * Monotonic time value for rekey message.
617 */
618 struct GNUNET_TIME_AbsoluteNBO rekey_monotonic_time;
619
620 /**
621 * Monotonic time value for handshake message.
622 */
623 struct GNUNET_TIME_AbsoluteNBO handshake_monotonic_time;
624
625 /**
626 * Monotonic time value for handshake ack message.
627 */
628 struct GNUNET_TIME_AbsoluteNBO handshake_ack_monotonic_time;
629
630 /**
631 * Challenge value used to protect against replay attack, if there is no stored monotonic time value.
632 */
633 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
634
635 /**
636 * 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.
637 */
638 struct GNUNET_CRYPTO_ChallengeNonceP challenge_received;
639
640 /**
641 * Iteration Context for retrieving the monotonic time send with key for rekeying.
642 */
643 struct GNUNET_PEERSTORE_IterateContext *rekey_monotime_get;
644
645 /**
646 * Iteration Context for retrieving the monotonic time send with the handshake.
647 */
648 struct GNUNET_PEERSTORE_IterateContext *handshake_monotime_get;
649
650 /**
651 * Iteration Context for retrieving the monotonic time send with the handshake ack.
652 */
653 struct GNUNET_PEERSTORE_IterateContext *handshake_ack_monotime_get;
654
655 /**
656 * Store Context for retrieving the monotonic time send with key for rekeying.
657 */
658 struct GNUNET_PEERSTORE_StoreContext *rekey_monotime_sc;
659
660 /**
661 * Store Context for retrieving the monotonic time send with the handshake.
662 */
663 struct GNUNET_PEERSTORE_StoreContext *handshake_monotime_sc;
664
665 /**
666 * Store Context for retrieving the monotonic time send with the handshake ack.
667 */
668 struct GNUNET_PEERSTORE_StoreContext *handshake_ack_monotime_sc;
669
670 /**
671 * Size of data received without KX challenge played back.
672 */
673 // TODO remove?
674 size_t unverified_size;
675
676 /**
677 * Has the initial (core) handshake already happened?
678 */
679 int initial_core_kx_done;
680};
681
682
683/**
684 * Handle for an incoming connection where we do not yet have enough
685 * information to setup a full queue.
686 */
687struct ProtoQueue
688{
689 /**
690 * Kept in a DLL.
691 */
692 struct ProtoQueue *next;
693
694 /**
695 * Kept in a DLL.
696 */
697 struct ProtoQueue *prev;
698
699 /**
700 * Listen socket.
701 */
702 struct GNUNET_NETWORK_Handle *listen_sock;
703
704 /**
705 * socket that we transmit all data with on this queue
706 */
707 struct GNUNET_NETWORK_Handle *sock;
708
709 /**
710 * ID of write task for this connection.
711 */
712 struct GNUNET_SCHEDULER_Task *write_task;
713
714 /**
715 * buffer for writing struct TCPNATProbeMessage to network.
716 */
717 char write_buf[sizeof (struct TCPNATProbeMessage)];
718
719 /**
720 * Offset of the buffer?
721 */
722 size_t write_off;
723
724 /**
725 * ID of read task for this connection.
726 */
727 struct GNUNET_SCHEDULER_Task *read_task;
728
729 /**
730 * Address of the other peer.
731 */
732 struct sockaddr *address;
733
734 /**
735 * Length of the address.
736 */
737 socklen_t address_len;
738
739 /**
740 * Timeout for this protoqueue.
741 */
742 struct GNUNET_TIME_Absolute timeout;
743
744 /**
745 * Buffer for reading all the information we need to upgrade from
746 * protoqueue to queue.
747 */
748 char ibuf[INITIAL_KX_SIZE];
749
750 /**
751 * Current offset for reading into @e ibuf.
752 */
753 size_t ibuf_off;
754};
755
756/**
757 * In case of port only configuration we like to bind to ipv4 and ipv6 addresses.
758 */
759struct PortOnlyIpv4Ipv6
760{
761 /**
762 * Ipv4 address we like to bind to.
763 */
764 struct sockaddr *addr_ipv4;
765
766 /**
767 * Length of ipv4 address.
768 */
769 socklen_t addr_len_ipv4;
770
771 /**
772 * Ipv6 address we like to bind to.
773 */
774 struct sockaddr *addr_ipv6;
775
776 /**
777 * Length of ipv6 address.
778 */
779 socklen_t addr_len_ipv6;
780
781};
782
783/**
784 * DLL to store the addresses we like to register at NAT service.
785 */
786struct Addresses
787{
788 /**
789 * Kept in a DLL.
790 */
791 struct Addresses *next;
792
793 /**
794 * Kept in a DLL.
795 */
796 struct Addresses *prev;
797
798 /**
799 * Address we like to register at NAT service.
800 */
801 struct sockaddr *addr;
802
803 /**
804 * Length of address we like to register at NAT service.
805 */
806 socklen_t addr_len;
807
808};
809
810
811/**
812 * Maximum queue length before we stop reading towards the transport service.
813 */
814static unsigned long long max_queue_length;
815
816/**
817 * For logging statistics.
818 */
819static struct GNUNET_STATISTICS_Handle *stats;
820
821/**
822 * Our environment.
823 */
824static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
825
826/**
827 * Queues (map from peer identity to `struct Queue`)
828 */
829static struct GNUNET_CONTAINER_MultiHashMap *queue_map;
830
831/**
832 * ListenTasks (map from socket to `struct ListenTask`)
833 */
834static struct GNUNET_CONTAINER_MultiHashMap *lt_map;
835
836/**
837 * Our public key.
838 */
839static struct GNUNET_PeerIdentity my_identity;
840
841/**
842 * The rekey byte maximum
843 */
844static unsigned long long rekey_max_bytes;
845
846/**
847 * The rekey interval
848 */
849static struct GNUNET_TIME_Relative rekey_interval;
850
851/**
852 * Our private key.
853 */
854static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
855
856/**
857 * Our configuration.
858 */
859static const struct GNUNET_CONFIGURATION_Handle *cfg;
860
861/**
862 * Network scanner to determine network types.
863 */
864static struct GNUNET_NT_InterfaceScanner *is;
865
866/**
867 * Connection to NAT service.
868 */
869static struct GNUNET_NAT_Handle *nat;
870
871/**
872 * Protoqueues DLL head.
873 */
874static struct ProtoQueue *proto_head;
875
876/**
877 * Protoqueues DLL tail.
878 */
879static struct ProtoQueue *proto_tail;
880
881/**
882 * Handle for DNS lookup of bindto address
883 */
884struct GNUNET_RESOLVER_RequestHandle *resolve_request_handle;
885
886/**
887 * Head of DLL with addresses we like to register at NAT servcie.
888 */
889static struct Addresses *addrs_head;
890
891/**
892 * Head of DLL with addresses we like to register at NAT servcie.
893 */
894static struct Addresses *addrs_tail;
895
896/**
897 * Number of addresses in the DLL for register at NAT service.
898 */
899static int addrs_lens;
900
901/**
902 * Database for peer's HELLOs.
903 */
904static struct GNUNET_PEERSTORE_Handle *peerstore;
905
906/**
907* A flag indicating we are already doing a shutdown.
908*/
909static int shutdown_running = GNUNET_NO;
910
911/**
912 * IPv6 disabled.
913 */
914static int disable_v6;
915
916/**
917 * The port the communicator should be assigned to.
918 */
919static unsigned int bind_port;
920
921/**
922 * Map of pending reversals.
923 */
924static struct GNUNET_CONTAINER_MultiHashMap *pending_reversals;
925
926/**
927 * We have been notified that our listen socket has something to
928 * read. Do the read and reschedule this function to be called again
929 * once more is available.
930 *
931 * @param cls NULL
932 */
933static void
934listen_cb (void *cls);
935
936/**
937 * Functions with this signature are called whenever we need
938 * to close a queue due to a disconnect or failure to
939 * establish a connection.
940 *
941 * @param queue queue to close down
942 */
943static void
944queue_destroy (struct Queue *queue)
945{
946 struct ListenTask *lt = NULL;
947 struct GNUNET_HashCode h_sock;
948 int sockfd;
949
950 if (NULL != queue->listen_sock)
951 {
952 sockfd = GNUNET_NETWORK_get_fd (queue->listen_sock);
953 GNUNET_CRYPTO_hash (&sockfd,
954 sizeof(int),
955 &h_sock);
956
957 lt = GNUNET_CONTAINER_multihashmap_get (lt_map, &h_sock);
958 }
959
960 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
961 "Disconnecting queue for peer `%s'\n",
962 GNUNET_i2s (&queue->target));
963 if (NULL != queue->rekey_monotime_sc)
964 {
965 GNUNET_PEERSTORE_store_cancel (queue->rekey_monotime_sc);
966 queue->rekey_monotime_sc = NULL;
967 }
968 if (NULL != queue->handshake_monotime_sc)
969 {
970 GNUNET_PEERSTORE_store_cancel (queue->handshake_monotime_sc);
971 queue->handshake_monotime_sc = NULL;
972 }
973 if (NULL != queue->handshake_ack_monotime_sc)
974 {
975 GNUNET_PEERSTORE_store_cancel (queue->handshake_ack_monotime_sc);
976 queue->handshake_ack_monotime_sc = NULL;
977 }
978 if (NULL != queue->rekey_monotime_get)
979 {
980 GNUNET_PEERSTORE_iteration_stop (queue->rekey_monotime_get);
981 queue->rekey_monotime_get = NULL;
982 }
983 if (NULL != queue->handshake_monotime_get)
984 {
985 GNUNET_PEERSTORE_iteration_stop (queue->handshake_monotime_get);
986 queue->handshake_monotime_get = NULL;
987 }
988 if (NULL != queue->handshake_ack_monotime_get)
989 {
990 GNUNET_PEERSTORE_iteration_stop (queue->handshake_ack_monotime_get);
991 queue->handshake_ack_monotime_get = NULL;
992 }
993 if (NULL != queue->qh)
994 {
995 GNUNET_TRANSPORT_communicator_mq_del (queue->qh);
996 queue->qh = NULL;
997 }
998 GNUNET_assert (
999 GNUNET_YES ==
1000 GNUNET_CONTAINER_multihashmap_remove (queue_map, &queue->key, queue));
1001 GNUNET_STATISTICS_set (stats,
1002 "# queues active",
1003 GNUNET_CONTAINER_multihashmap_size (queue_map),
1004 GNUNET_NO);
1005 if (NULL != queue->read_task)
1006 {
1007 GNUNET_SCHEDULER_cancel (queue->read_task);
1008 queue->read_task = NULL;
1009 }
1010 if (NULL != queue->write_task)
1011 {
1012 GNUNET_SCHEDULER_cancel (queue->write_task);
1013 queue->write_task = NULL;
1014 }
1015 if (GNUNET_SYSERR == GNUNET_NETWORK_socket_close (queue->sock))
1016 {
1017 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1018 "closing socket failed\n");
1019 }
1020 gcry_cipher_close (queue->in_cipher);
1021 gcry_cipher_close (queue->out_cipher);
1022 GNUNET_free (queue->address);
1023 if (0 != queue->backpressure)
1024 queue->destroyed = GNUNET_YES;
1025 else
1026 GNUNET_free (queue);
1027
1028 if (NULL == lt)
1029 return;
1030
1031 if ((! shutdown_running) && (NULL == lt->listen_task))
1032 {
1033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1034 "add read net listen\n");
1035 lt->listen_task = GNUNET_SCHEDULER_add_read_net (
1036 GNUNET_TIME_UNIT_FOREVER_REL,
1037 lt->listen_sock,
1038 &listen_cb,
1039 lt);
1040 }
1041 else
1042 GNUNET_free (lt);
1043}
1044
1045
1046/**
1047 * Compute @a mac over @a buf, and ratched the @a hmac_secret.
1048 *
1049 * @param[in,out] hmac_secret secret for HMAC calculation
1050 * @param buf buffer to MAC
1051 * @param buf_size number of bytes in @a buf
1052 * @param[out] smac where to write the HMAC
1053 */
1054static void
1055calculate_hmac (struct GNUNET_HashCode *hmac_secret,
1056 const void *buf,
1057 size_t buf_size,
1058 struct GNUNET_ShortHashCode *smac)
1059{
1060 struct GNUNET_HashCode mac;
1061
1062 GNUNET_CRYPTO_hmac_raw (hmac_secret,
1063 sizeof(struct GNUNET_HashCode),
1064 buf,
1065 buf_size,
1066 &mac);
1067 /* truncate to `struct GNUNET_ShortHashCode` */
1068 memcpy (smac, &mac, sizeof(struct GNUNET_ShortHashCode));
1069 /* ratchet hmac key */
1070 GNUNET_CRYPTO_hash (hmac_secret,
1071 sizeof(struct GNUNET_HashCode),
1072 hmac_secret);
1073}
1074
1075
1076/**
1077 * Append a 'finish' message to the outgoing transmission. Once the
1078 * finish has been transmitted, destroy the queue.
1079 *
1080 * @param queue queue to shut down nicely
1081 */
1082static void
1083queue_finish (struct Queue *queue)
1084{
1085 struct TCPFinish fin;
1086
1087 memset (&fin, 0, sizeof(fin));
1088 fin.header.size = htons (sizeof(fin));
1089 fin.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH);
1090 calculate_hmac (&queue->out_hmac, &fin, sizeof(fin), &fin.hmac);
1091 /* if there is any message left in pwrite_buf, we
1092 overwrite it (possibly dropping the last message
1093 from CORE hard here) */
1094 memcpy (queue->pwrite_buf, &fin, sizeof(fin));
1095 queue->pwrite_off = sizeof(fin);
1096 /* This flag will ensure that #queue_write() no longer
1097 notifies CORE about the possibility of sending
1098 more data, and that #queue_write() will call
1099 #queue_destroy() once the @c fin was fully written. */
1100 queue->finishing = GNUNET_YES;
1101}
1102
1103
1104/**
1105 * Queue read task. If we hit the timeout, disconnect it
1106 *
1107 * @param cls the `struct Queue *` to disconnect
1108 */
1109static void
1110queue_read (void *cls);
1111
1112
1113/**
1114 * Core tells us it is done processing a message that transport
1115 * received on a queue with status @a success.
1116 *
1117 * @param cls a `struct Queue *` where the message originally came from
1118 * @param success #GNUNET_OK on success
1119 */
1120static void
1121core_read_finished_cb (void *cls, int success)
1122{
1123 struct Queue *queue = cls;
1124 if (GNUNET_OK != success)
1125 GNUNET_STATISTICS_update (stats,
1126 "# messages lost in communicator API towards CORE",
1127 1,
1128 GNUNET_NO);
1129 if (NULL == queue)
1130 return;
1131
1132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1133 "backpressure %u\n",
1134 queue->backpressure);
1135
1136 queue->backpressure--;
1137 /* handle deferred queue destruction */
1138 if ((queue->destroyed) && (0 == queue->backpressure))
1139 {
1140 GNUNET_free (queue);
1141 return;
1142 }
1143 else if (GNUNET_YES != queue->destroyed)
1144 {
1145 queue->timeout =
1146 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
1147 );
1148 /* possibly unchoke reading, now that CORE made progress */
1149 if (NULL == queue->read_task)
1150 queue->read_task =
1151 GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_absolute_get_remaining (
1152 queue->timeout),
1153 queue->sock,
1154 &queue_read,
1155 queue);
1156 }
1157}
1158
1159
1160/**
1161 * We received @a plaintext_len bytes of @a plaintext on @a queue.
1162 * Pass it on to CORE. If transmission is actually happening,
1163 * increase backpressure counter.
1164 *
1165 * @param queue the queue that received the plaintext
1166 * @param plaintext the plaintext that was received
1167 * @param plaintext_len number of bytes of plaintext received
1168 */
1169static void
1170pass_plaintext_to_core (struct Queue *queue,
1171 const void *plaintext,
1172 size_t plaintext_len)
1173{
1174 const struct GNUNET_MessageHeader *hdr = plaintext;
1175 int ret;
1176
1177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1178 "pass message from %s to core\n",
1179 GNUNET_i2s (&queue->target));
1180
1181 if (ntohs (hdr->size) != plaintext_len)
1182 {
1183 /* NOTE: If we ever allow multiple CORE messages in one
1184 BOX, this will have to change! */
1185 GNUNET_break (0);
1186 return;
1187 }
1188 ret = GNUNET_TRANSPORT_communicator_receive (ch,
1189 &queue->target,
1190 hdr,
1191 ADDRESS_VALIDITY_PERIOD,
1192 &core_read_finished_cb,
1193 queue);
1194 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1195 "passed to core\n");
1196 if (GNUNET_OK == ret)
1197 queue->backpressure++;
1198 GNUNET_break (GNUNET_NO != ret); /* backpressure not working!? */
1199 if (GNUNET_SYSERR == ret)
1200 GNUNET_STATISTICS_update (stats,
1201 "# bytes lost due to CORE not running",
1202 plaintext_len,
1203 GNUNET_NO);
1204}
1205
1206
1207/**
1208 * Setup @a cipher based on shared secret @a dh and decrypting
1209 * peer @a pid.
1210 *
1211 * @param dh shared secret
1212 * @param pid decrypting peer's identity
1213 * @param[out] cipher cipher to initialize
1214 * @param[out] hmac_key HMAC key to initialize
1215 */
1216static void
1217setup_cipher (const struct GNUNET_HashCode *dh,
1218 const struct GNUNET_PeerIdentity *pid,
1219 gcry_cipher_hd_t *cipher,
1220 struct GNUNET_HashCode *hmac_key)
1221{
1222 char key[256 / 8];
1223 char ctr[128 / 8];
1224
1225 GNUNET_assert (0 == gcry_cipher_open (cipher,
1226 GCRY_CIPHER_AES256 /* low level: go for speed */
1227 ,
1228 GCRY_CIPHER_MODE_CTR,
1229 0 /* flags */));
1230 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (key,
1231 sizeof(key),
1232 "TCP-key",
1233 strlen ("TCP-key"),
1234 dh,
1235 sizeof(*dh),
1236 pid,
1237 sizeof(*pid),
1238 NULL,
1239 0));
1240 GNUNET_assert (0 == gcry_cipher_setkey (*cipher, key, sizeof(key)));
1241 GNUNET_assert (GNUNET_YES == GNUNET_CRYPTO_kdf (ctr,
1242 sizeof(ctr),
1243 "TCP-ctr",
1244 strlen ("TCP-ctr"),
1245 dh,
1246 sizeof(*dh),
1247 pid,
1248 sizeof(*pid),
1249 NULL,
1250 0));
1251 gcry_cipher_setctr (*cipher, ctr, sizeof(ctr));
1252 GNUNET_assert (GNUNET_YES ==
1253 GNUNET_CRYPTO_kdf (hmac_key,
1254 sizeof(struct GNUNET_HashCode),
1255 "TCP-hmac",
1256 strlen ("TCP-hmac"),
1257 dh,
1258 sizeof(*dh),
1259 pid,
1260 sizeof(*pid),
1261 NULL,
1262 0));
1263}
1264
1265
1266/**
1267 * Callback called when peerstore store operation for rekey monotime value is finished.
1268 * @param cls Queue context the store operation was executed.
1269 * @param success Store operation was successful (GNUNET_OK) or not.
1270 */
1271static void
1272rekey_monotime_store_cb (void *cls, int success)
1273{
1274 struct Queue *queue = cls;
1275 if (GNUNET_OK != success)
1276 {
1277 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1278 "Failed to store rekey monotonic time in PEERSTORE!\n");
1279 }
1280 queue->rekey_monotime_sc = NULL;
1281 GNUNET_PEERSTORE_iteration_next (queue->rekey_monotime_get, 1);
1282}
1283
1284
1285/**
1286 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY
1287 * where found.
1288 * @param cls Queue context the store operation was executed.
1289 * @param record The record found or NULL if there is no record left.
1290 * @param emsg Message from peerstore.
1291 */
1292static void
1293rekey_monotime_cb (void *cls,
1294 const struct GNUNET_PEERSTORE_Record *record,
1295 const char *emsg)
1296{
1297 struct Queue *queue = cls;
1298 struct GNUNET_TIME_AbsoluteNBO *mtbe;
1299 struct GNUNET_TIME_Absolute mt;
1300 const struct GNUNET_PeerIdentity *pid;
1301 struct GNUNET_TIME_AbsoluteNBO *rekey_monotonic_time;
1302
1303 (void) emsg;
1304
1305 rekey_monotonic_time = &queue->rekey_monotonic_time;
1306 pid = &queue->target;
1307 if (NULL == record)
1308 {
1309 queue->rekey_monotime_get = NULL;
1310 return;
1311 }
1312 if (sizeof(*mtbe) != record->value_size)
1313 {
1314 GNUNET_PEERSTORE_iteration_next (queue->rekey_monotime_get, 1);
1315 GNUNET_break (0);
1316 return;
1317 }
1318 mtbe = record->value;
1319 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
1320 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
1321 queue->rekey_monotonic_time).abs_value_us)
1322 {
1323 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1324 "Queue from %s dropped, rekey monotime in the past\n",
1325 GNUNET_i2s (&queue->target));
1326 GNUNET_break (0);
1327 GNUNET_PEERSTORE_iteration_stop (queue->rekey_monotime_get);
1328 queue->rekey_monotime_get = NULL;
1329 // FIXME: Why should we try to gracefully finish here??
1330 queue_finish (queue);
1331 return;
1332 }
1333 queue->rekey_monotime_sc = GNUNET_PEERSTORE_store (peerstore,
1334 "transport_tcp_communicator",
1335 pid,
1336 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY,
1337 rekey_monotonic_time,
1338 sizeof(*
1339 rekey_monotonic_time),
1340 GNUNET_TIME_UNIT_FOREVER_ABS,
1341 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
1342 &rekey_monotime_store_cb,
1343 queue);
1344}
1345
1346
1347/**
1348 * Setup cipher of @a queue for decryption.
1349 *
1350 * @param ephemeral ephemeral key we received from the other peer
1351 * @param[in,out] queue queue to initialize decryption cipher for
1352 */
1353static void
1354setup_in_cipher (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
1355 struct Queue *queue)
1356{
1357 struct GNUNET_HashCode k;
1358
1359 GNUNET_CRYPTO_eddsa_kem_decaps (my_private_key, ephemeral, &k);
1360 setup_cipher (&k, &my_identity, &queue->in_cipher, &queue->in_hmac);
1361}
1362
1363
1364/**
1365 * Handle @a rekey message on @a queue. The message was already
1366 * HMAC'ed, but we should additionally still check the signature.
1367 * Then we need to stop the old cipher and start afresh.
1368 *
1369 * @param queue the queue @a rekey was received on
1370 * @param rekey the rekey message
1371 */
1372static void
1373do_rekey (struct Queue *queue, const struct TCPRekey *rekey)
1374{
1375 struct TcpRekeySignature thp;
1376
1377 thp.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY);
1378 thp.purpose.size = htonl (sizeof(thp));
1379 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1380 "do_rekey size %u\n",
1381 thp.purpose.size);
1382 thp.sender = queue->target;
1383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1384 "sender %s\n",
1385 GNUNET_p2s (&thp.sender.public_key));
1386 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1387 "sender %s\n",
1388 GNUNET_p2s (&queue->target.public_key));
1389 thp.receiver = my_identity;
1390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1391 "receiver %s\n",
1392 GNUNET_p2s (&thp.receiver.public_key));
1393 thp.ephemeral = rekey->ephemeral;
1394 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1395 "ephemeral %s\n",
1396 GNUNET_e2s (&thp.ephemeral));
1397 thp.monotonic_time = rekey->monotonic_time;
1398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1399 "time %s\n",
1400 GNUNET_STRINGS_absolute_time_to_string (
1401 GNUNET_TIME_absolute_ntoh (thp.monotonic_time)));
1402 GNUNET_assert (ntohl ((&thp)->purpose.size) == sizeof (*(&thp)));
1403 if (GNUNET_OK !=
1404 GNUNET_CRYPTO_eddsa_verify (
1405 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY,
1406 &thp,
1407 &rekey->sender_sig,
1408 &queue->target.public_key))
1409 {
1410 GNUNET_break (0);
1411 // FIXME Why should we try to gracefully finish here?
1412 queue_finish (queue);
1413 return;
1414 }
1415 queue->rekey_monotonic_time = rekey->monotonic_time;
1416 queue->rekey_monotime_get = GNUNET_PEERSTORE_iteration_start (peerstore,
1417 "transport_tcp_communicator",
1418 &queue->target,
1419 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_REKEY,
1420 &
1421 rekey_monotime_cb,
1422 queue);
1423 gcry_cipher_close (queue->in_cipher);
1424 queue->rekeyed = GNUNET_YES;
1425 setup_in_cipher (&rekey->ephemeral, queue);
1426}
1427
1428
1429/**
1430 * Callback called when peerstore store operation for handshake ack monotime value is finished.
1431 * @param cls Queue context the store operation was executed.
1432 * @param success Store operation was successful (GNUNET_OK) or not.
1433 */
1434static void
1435handshake_ack_monotime_store_cb (void *cls, int success)
1436{
1437 struct Queue *queue = cls;
1438
1439 if (GNUNET_OK != success)
1440 {
1441 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1442 "Failed to store handshake ack monotonic time in PEERSTORE!\n");
1443 }
1444 queue->handshake_ack_monotime_sc = NULL;
1445 GNUNET_PEERSTORE_iteration_next (queue->handshake_ack_monotime_get, 1);
1446}
1447
1448
1449/**
1450 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK
1451 * where found.
1452 * @param cls Queue context the store operation was executed.
1453 * @param record The record found or NULL if there is no record left.
1454 * @param emsg Message from peerstore.
1455 */
1456static void
1457handshake_ack_monotime_cb (void *cls,
1458 const struct GNUNET_PEERSTORE_Record *record,
1459 const char *emsg)
1460{
1461 struct Queue *queue = cls;
1462 struct GNUNET_TIME_AbsoluteNBO *mtbe;
1463 struct GNUNET_TIME_Absolute mt;
1464 const struct GNUNET_PeerIdentity *pid;
1465 struct GNUNET_TIME_AbsoluteNBO *handshake_ack_monotonic_time;
1466
1467 (void) emsg;
1468
1469 handshake_ack_monotonic_time = &queue->handshake_ack_monotonic_time;
1470 pid = &queue->target;
1471 if (NULL == record)
1472 {
1473 queue->handshake_ack_monotime_get = NULL;
1474 return;
1475 }
1476 if (sizeof(*mtbe) != record->value_size)
1477 {
1478 GNUNET_PEERSTORE_iteration_next (queue->handshake_ack_monotime_get, 1);
1479 GNUNET_break (0);
1480 return;
1481 }
1482 mtbe = record->value;
1483 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
1484 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
1485 queue->handshake_ack_monotonic_time).abs_value_us)
1486 {
1487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1488 "Queue from %s dropped, handshake ack monotime in the past\n",
1489 GNUNET_i2s (&queue->target));
1490 GNUNET_break (0);
1491 GNUNET_PEERSTORE_iteration_stop (queue->handshake_ack_monotime_get);
1492 queue->handshake_ack_monotime_get = NULL;
1493 // FIXME: Why should we try to gracefully finish here?
1494 queue_finish (queue);
1495 return;
1496 }
1497 queue->handshake_ack_monotime_sc =
1498 GNUNET_PEERSTORE_store (peerstore,
1499 "transport_tcp_communicator",
1500 pid,
1501 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK,
1502 handshake_ack_monotonic_time,
1503 sizeof(*handshake_ack_monotonic_time),
1504 GNUNET_TIME_UNIT_FOREVER_ABS,
1505 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
1506 &handshake_ack_monotime_store_cb,
1507 queue);
1508}
1509
1510
1511/**
1512 * Sending challenge with TcpConfirmationAck back to sender of ephemeral key.
1513 *
1514 * @param tc The TCPConfirmation originally send.
1515 * @param queue The queue context.
1516 */
1517static void
1518send_challenge (struct GNUNET_CRYPTO_ChallengeNonceP challenge,
1519 struct Queue *queue)
1520{
1521 struct TCPConfirmationAck tca;
1522 struct TcpHandshakeAckSignature thas;
1523
1524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1525 "sending challenge\n");
1526
1527 tca.header.type = ntohs (
1528 GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK);
1529 tca.header.size = ntohs (sizeof(tca));
1530 tca.challenge = challenge;
1531 tca.sender = my_identity;
1532 tca.monotonic_time =
1533 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
1534 thas.purpose.purpose = htonl (
1535 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK);
1536 thas.purpose.size = htonl (sizeof(thas));
1537 thas.sender = my_identity;
1538 thas.receiver = queue->target;
1539 thas.monotonic_time = tca.monotonic_time;
1540 thas.challenge = tca.challenge;
1541 GNUNET_CRYPTO_eddsa_sign (my_private_key,
1542 &thas,
1543 &tca.sender_sig);
1544 GNUNET_assert (0 ==
1545 gcry_cipher_encrypt (queue->out_cipher,
1546 &queue->cwrite_buf[queue->cwrite_off],
1547 sizeof(tca),
1548 &tca,
1549 sizeof(tca)));
1550 queue->cwrite_off += sizeof(tca);
1551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1552 "sending challenge done\n");
1553}
1554
1555
1556/**
1557 * Setup cipher for outgoing data stream based on target and
1558 * our ephemeral private key.
1559 *
1560 * @param queue queue to setup outgoing (encryption) cipher for
1561 */
1562static void
1563setup_out_cipher (struct Queue *queue, struct GNUNET_HashCode *dh)
1564{
1565 setup_cipher (dh, &queue->target, &queue->out_cipher, &queue->out_hmac);
1566 queue->rekey_time = GNUNET_TIME_relative_to_absolute (rekey_interval);
1567 queue->rekey_left_bytes =
1568 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, rekey_max_bytes);
1569}
1570
1571
1572/**
1573 * Inject a `struct TCPRekey` message into the queue's plaintext
1574 * buffer.
1575 *
1576 * @param queue queue to perform rekeying on
1577 */
1578static void
1579inject_rekey (struct Queue *queue)
1580{
1581 struct TCPRekey rekey;
1582 struct TcpRekeySignature thp;
1583 struct GNUNET_HashCode k;
1584
1585 GNUNET_assert (0 == queue->pwrite_off);
1586 memset (&rekey, 0, sizeof(rekey));
1587 GNUNET_CRYPTO_eddsa_kem_encaps (&queue->target.public_key, &rekey.ephemeral,
1588 &k);
1589 rekey.header.type = ntohs (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY);
1590 rekey.header.size = ntohs (sizeof(rekey));
1591 rekey.monotonic_time =
1592 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
1593 thp.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_REKEY);
1594 thp.purpose.size = htonl (sizeof(thp));
1595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1596 "inject_rekey size %u\n",
1597 thp.purpose.size);
1598 thp.sender = my_identity;
1599 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1600 "sender %s\n",
1601 GNUNET_p2s (&thp.sender.public_key));
1602 thp.receiver = queue->target;
1603 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1604 "receiver %s\n",
1605 GNUNET_p2s (&thp.receiver.public_key));
1606 thp.ephemeral = rekey.ephemeral;
1607 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1608 "ephemeral %s\n",
1609 GNUNET_e2s (&thp.ephemeral));
1610 thp.monotonic_time = rekey.monotonic_time;
1611 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1612 "time %s\n",
1613 GNUNET_STRINGS_absolute_time_to_string (
1614 GNUNET_TIME_absolute_ntoh (thp.monotonic_time)));
1615 GNUNET_CRYPTO_eddsa_sign (my_private_key,
1616 &thp,
1617 &rekey.sender_sig);
1618 calculate_hmac (&queue->out_hmac, &rekey, sizeof(rekey), &rekey.hmac);
1619 /* Encrypt rekey message with 'old' cipher */
1620 GNUNET_assert (0 ==
1621 gcry_cipher_encrypt (queue->out_cipher,
1622 &queue->cwrite_buf[queue->cwrite_off],
1623 sizeof(rekey),
1624 &rekey,
1625 sizeof(rekey)));
1626 queue->cwrite_off += sizeof(rekey);
1627 /* Setup new cipher for successive messages */
1628 gcry_cipher_close (queue->out_cipher);
1629 setup_out_cipher (queue, &k);
1630}
1631
1632
1633static int
1634pending_reversals_delete_it (void *cls,
1635 const struct GNUNET_HashCode *key,
1636 void *value)
1637{
1638 (void) cls;
1639 struct PendingReversal *pending_reversal = value;
1640
1641 if (NULL != pending_reversal->timeout_task)
1642 {
1643 GNUNET_SCHEDULER_cancel (pending_reversal->timeout_task);
1644 pending_reversal->timeout_task = NULL;
1645 }
1646 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (
1647 pending_reversals,
1648 key,
1649 pending_reversal));
1650 GNUNET_free (pending_reversal->in);
1651 GNUNET_free (pending_reversal);
1652 return GNUNET_OK;
1653}
1654
1655
1656static void
1657check_and_remove_pending_reversal (struct sockaddr *in, sa_family_t sa_family,
1658 struct GNUNET_PeerIdentity *sender)
1659{
1660 if (AF_INET == sa_family)
1661 {
1662 struct PendingReversal *pending_reversal;
1663 struct GNUNET_HashCode key;
1664 struct sockaddr_in *natted_address;
1665
1666 natted_address = GNUNET_memdup (in, sizeof (struct sockaddr));
1667 natted_address->sin_port = 0;
1668 GNUNET_CRYPTO_hash (natted_address,
1669 sizeof(struct sockaddr),
1670 &key);
1671
1672 pending_reversal = GNUNET_CONTAINER_multihashmap_get (pending_reversals,
1673 &key);
1674 if (NULL != pending_reversal && (NULL == sender ||
1675 0 != memcmp (sender,
1676 &pending_reversal->target,
1677 sizeof(struct
1678 GNUNET_PeerIdentity))))
1679 {
1680 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
1681 "Removing invalid pending reversal for `%s'at `%s'\n",
1682 GNUNET_i2s (&pending_reversal->target),
1683 GNUNET_a2s (in, sizeof (struct sockaddr)));
1684 pending_reversals_delete_it (NULL, &key, pending_reversal);
1685 }
1686 GNUNET_free (natted_address);
1687 }
1688}
1689
1690
1691/**
1692 * Closes socket and frees memory associated with @a pq.
1693 *
1694 * @param pq proto queue to free
1695 */
1696static void
1697free_proto_queue (struct ProtoQueue *pq)
1698{
1699 if (NULL != pq->listen_sock)
1700 {
1701 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (pq->listen_sock));
1702 pq->listen_sock = NULL;
1703 }
1704 if (NULL != pq->read_task)
1705 {
1706 GNUNET_SCHEDULER_cancel (pq->read_task);
1707 pq->read_task = NULL;
1708 }
1709 if (NULL != pq->write_task)
1710 {
1711 GNUNET_SCHEDULER_cancel (pq->write_task);
1712 pq->write_task = NULL;
1713 }
1714 check_and_remove_pending_reversal (pq->address, pq->address->sa_family, NULL);
1715 GNUNET_NETWORK_socket_close (pq->sock);
1716 GNUNET_free (pq->address);
1717 GNUNET_CONTAINER_DLL_remove (proto_head, proto_tail, pq);
1718 GNUNET_free (pq);
1719}
1720
1721
1722/**
1723 * We have been notified that our socket is ready to write.
1724 * Then reschedule this function to be called again once more is available.
1725 *
1726 * @param cls a `struct ProtoQueue`
1727 */
1728static void
1729proto_queue_write (void *cls)
1730{
1731 struct ProtoQueue *pq = cls;
1732 ssize_t sent;
1733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "In proto queue write\n");
1734 pq->write_task = NULL;
1735 if (0 != pq->write_off)
1736 {
1737 sent = GNUNET_NETWORK_socket_send (pq->sock,
1738 pq->write_buf,
1739 pq->write_off);
1740 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1741 "Sent %lu bytes to TCP queue\n", sent);
1742 if ((-1 == sent) && (EAGAIN != errno) && (EINTR != errno))
1743 {
1744 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
1745 free_proto_queue (pq);
1746 return;
1747 }
1748 if (sent > 0)
1749 {
1750 size_t usent = (size_t) sent;
1751 pq->write_off -= usent;
1752 memmove (pq->write_buf,
1753 &pq->write_buf[usent],
1754 pq->write_off);
1755 }
1756 }
1757 /* do we care to write more? */
1758 if ((0 < pq->write_off))
1759 pq->write_task =
1760 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1761 pq->sock,
1762 &proto_queue_write,
1763 pq);
1764}
1765
1766
1767/**
1768 * We have been notified that our socket is ready to write.
1769 * Then reschedule this function to be called again once more is available.
1770 *
1771 * @param cls a `struct Queue`
1772 */
1773static void
1774queue_write (void *cls)
1775{
1776 struct Queue *queue = cls;
1777 ssize_t sent;
1778 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "In queue write\n");
1779 queue->write_task = NULL;
1780 if (0 != queue->cwrite_off)
1781 {
1782 sent = GNUNET_NETWORK_socket_send (queue->sock,
1783 queue->cwrite_buf,
1784 queue->cwrite_off);
1785 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1786 "Sent %lu bytes to TCP queue\n", sent);
1787 if ((-1 == sent) && (EAGAIN != errno) && (EINTR != errno))
1788 {
1789 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
1790 queue_destroy (queue);
1791 return;
1792 }
1793 if (sent > 0)
1794 {
1795 size_t usent = (size_t) sent;
1796 queue->cwrite_off -= usent;
1797 memmove (queue->cwrite_buf,
1798 &queue->cwrite_buf[usent],
1799 queue->cwrite_off);
1800 queue->timeout =
1801 GNUNET_TIME_relative_to_absolute (
1802 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1803 }
1804 }
1805 /* can we encrypt more? (always encrypt full messages, needed
1806 such that #mq_cancel() can work!) */
1807 unsigned int we_do_not_need_to_rekey = (0 < queue->rekey_left_bytes
1808 - (queue->cwrite_off
1809 + queue->pwrite_off
1810 + sizeof (struct TCPRekey)));
1811 if (we_do_not_need_to_rekey &&
1812 (queue->pwrite_off > 0) &&
1813 (queue->cwrite_off + queue->pwrite_off <= BUF_SIZE))
1814 {
1815 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1816 "Encrypting %lu bytes\n", queue->pwrite_off);
1817 GNUNET_assert (0 ==
1818 gcry_cipher_encrypt (queue->out_cipher,
1819 &queue->cwrite_buf[queue->cwrite_off],
1820 queue->pwrite_off,
1821 queue->pwrite_buf,
1822 queue->pwrite_off));
1823 if (queue->rekey_left_bytes > queue->pwrite_off)
1824 queue->rekey_left_bytes -= queue->pwrite_off;
1825 else
1826 queue->rekey_left_bytes = 0;
1827 queue->cwrite_off += queue->pwrite_off;
1828 queue->pwrite_off = 0;
1829 }
1830 // if ((-1 != unverified_size)&& ((0 == queue->pwrite_off) &&
1831 if (((0 == queue->rekey_left_bytes) ||
1832 (0 == GNUNET_TIME_absolute_get_remaining (
1833 queue->rekey_time).rel_value_us)) &&
1834 (((0 == queue->pwrite_off) || ! we_do_not_need_to_rekey) &&
1835 (queue->cwrite_off + sizeof (struct TCPRekey) <= BUF_SIZE)))
1836 {
1837 inject_rekey (queue);
1838 }
1839 if ((0 == queue->pwrite_off) && (! queue->finishing) &&
1840 (GNUNET_YES == queue->mq_awaits_continue))
1841 {
1842 queue->mq_awaits_continue = GNUNET_NO;
1843 GNUNET_MQ_impl_send_continue (queue->mq);
1844 }
1845 /* did we just finish writing 'finish'? */
1846 if ((0 == queue->cwrite_off) && (GNUNET_YES == queue->finishing))
1847 {
1848 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1849 "Finishing queue\n");
1850 queue_destroy (queue);
1851 return;
1852 }
1853 /* do we care to write more? */
1854 if ((0 < queue->cwrite_off) || (0 < queue->pwrite_off))
1855 queue->write_task =
1856 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1857 queue->sock,
1858 &queue_write,
1859 queue);
1860}
1861
1862
1863/**
1864 * Test if we have received a full message in plaintext.
1865 * If so, handle it.
1866 *
1867 * @param queue queue to process inbound plaintext for
1868 * @return number of bytes of plaintext handled, 0 for none
1869 */
1870static size_t
1871try_handle_plaintext (struct Queue *queue)
1872{
1873 const struct GNUNET_MessageHeader *hdr;
1874 const struct TCPConfirmationAck *tca;
1875 const struct TCPBox *box;
1876 const struct TCPRekey *rekey;
1877 const struct TCPFinish *fin;
1878 struct TCPRekey rekeyz;
1879 struct TCPFinish finz;
1880 struct GNUNET_ShortHashCode tmac;
1881 uint16_t type;
1882 size_t size = 0;
1883 struct TcpHandshakeAckSignature thas;
1884 const struct GNUNET_CRYPTO_ChallengeNonceP challenge = queue->challenge;
1885
1886 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1887 "try handle plaintext!\n");
1888
1889 hdr = (const struct GNUNET_MessageHeader *) queue->pread_buf;
1890 if ((sizeof(*hdr) > queue->pread_off))
1891 {
1892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1893 "Handling plaintext, not even a header!\n");
1894 return 0; /* not even a header */
1895 }
1896
1897 if ((GNUNET_YES != queue->initial_core_kx_done) && (queue->unverified_size >
1898 INITIAL_CORE_KX_SIZE))
1899 {
1900 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1901 "Already received data of size %lu bigger than KX size %lu!\n",
1902 queue->unverified_size,
1903 INITIAL_CORE_KX_SIZE);
1904 GNUNET_break_op (0);
1905 queue_finish (queue);
1906 return 0;
1907 }
1908
1909 type = ntohs (hdr->type);
1910 switch (type)
1911 {
1912 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_CONFIRMATION_ACK:
1913 tca = (const struct TCPConfirmationAck *) queue->pread_buf;
1914 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1915 "start processing ack\n");
1916 if (sizeof(*tca) > queue->pread_off)
1917 {
1918 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1919 "Handling plaintext size of tca greater than pread offset.\n")
1920 ;
1921 return 0;
1922 }
1923 if (ntohs (hdr->size) != sizeof(*tca))
1924 {
1925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1926 "Handling plaintext size does not match message type.\n");
1927 GNUNET_break_op (0);
1928 queue_finish (queue);
1929 return 0;
1930 }
1931
1932 thas.purpose.purpose = htonl (
1933 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK);
1934 thas.purpose.size = htonl (sizeof(thas));
1935 thas.sender = tca->sender;
1936 thas.receiver = my_identity;
1937 thas.monotonic_time = tca->monotonic_time;
1938 thas.challenge = tca->challenge;
1939
1940 if (GNUNET_SYSERR == GNUNET_CRYPTO_eddsa_verify (
1941 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE_ACK,
1942 &thas,
1943 &tca->sender_sig,
1944 &tca->sender.public_key))
1945 {
1946 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1947 "Verification of signature failed!\n");
1948 GNUNET_break (0);
1949 queue_finish (queue);
1950 return 0;
1951 }
1952 if (0 != GNUNET_memcmp (&tca->challenge, &challenge))
1953 {
1954 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1955 "Challenge in TCPConfirmationAck not correct!\n");
1956 GNUNET_break (0);
1957 queue_finish (queue);
1958 return 0;
1959 }
1960
1961 queue->handshake_ack_monotime_get = GNUNET_PEERSTORE_iteration_start (
1962 peerstore,
1963 "transport_tcp_communicator",
1964 &queue->target,
1965 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE_ACK,
1966 &handshake_ack_monotime_cb,
1967 queue);
1968
1969 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1970 "Handling plaintext, ack processed!\n");
1971
1972 if (GNUNET_TRANSPORT_CS_INBOUND == queue->cs)
1973 {
1974 send_challenge (queue->challenge_received, queue);
1975 queue->write_task =
1976 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
1977 queue->sock,
1978 &queue_write,
1979 queue);
1980 }
1981 else if (GNUNET_TRANSPORT_CS_OUTBOUND == queue->cs)
1982 {
1983 check_and_remove_pending_reversal (queue->address,
1984 queue->address->sa_family, NULL);
1985 }
1986
1987 /**
1988 * Once we received this ack, we consider this a verified connection.
1989 * FIXME: I am not sure this logic is sane here.
1990 */
1991 queue->initial_core_kx_done = GNUNET_YES;
1992
1993 char *foreign_addr;
1994
1995 switch (queue->address->sa_family)
1996 {
1997 case AF_INET:
1998 GNUNET_asprintf (&foreign_addr,
1999 "%s-%s",
2000 COMMUNICATOR_ADDRESS_PREFIX,
2001 GNUNET_a2s (queue->address, queue->address_len));
2002 break;
2003
2004 case AF_INET6:
2005 GNUNET_asprintf (&foreign_addr,
2006 "%s-%s",
2007 COMMUNICATOR_ADDRESS_PREFIX,
2008 GNUNET_a2s (queue->address, queue->address_len));
2009 break;
2010
2011 default:
2012 GNUNET_assert (0);
2013 }
2014
2015 queue->qh = GNUNET_TRANSPORT_communicator_mq_add (ch,
2016 &queue->target,
2017 foreign_addr,
2018 UINT16_MAX, /* no MTU */
2019 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
2020 0, /* Priority */
2021 queue->nt,
2022 queue->cs,
2023 queue->mq);
2024
2025 GNUNET_free (foreign_addr);
2026
2027 size = ntohs (hdr->size);
2028 break;
2029 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX:
2030 /* Special case: header size excludes box itself! */
2031 box = (const struct TCPBox *) queue->pread_buf;
2032 if (ntohs (hdr->size) + sizeof(struct TCPBox) > queue->pread_off)
2033 return 0;
2034 calculate_hmac (&queue->in_hmac, &box[1], ntohs (hdr->size), &tmac);
2035 if (0 != memcmp (&tmac, &box->hmac, sizeof(tmac)))
2036 {
2037 GNUNET_break_op (0);
2038 queue_finish (queue);
2039 return 0;
2040 }
2041 pass_plaintext_to_core (queue, (const void *) &box[1], ntohs (hdr->size));
2042 size = ntohs (hdr->size) + sizeof(*box);
2043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2044 "Handling plaintext, box processed!\n");
2045 GNUNET_STATISTICS_update (stats,
2046 "# bytes decrypted with BOX",
2047 size,
2048 GNUNET_NO);
2049 GNUNET_STATISTICS_update (stats,
2050 "# messages decrypted with BOX",
2051 1,
2052 GNUNET_NO);
2053 break;
2054
2055 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_REKEY:
2056 rekey = (const struct TCPRekey *) queue->pread_buf;
2057 if (sizeof(*rekey) > queue->pread_off)
2058 return 0;
2059 if (ntohs (hdr->size) != sizeof(*rekey))
2060 {
2061 GNUNET_break_op (0);
2062 queue_finish (queue);
2063 return 0;
2064 }
2065 rekeyz = *rekey;
2066 memset (&rekeyz.hmac, 0, sizeof(rekeyz.hmac));
2067 calculate_hmac (&queue->in_hmac, &rekeyz, sizeof(rekeyz), &tmac);
2068 if (0 != memcmp (&tmac, &rekey->hmac, sizeof(tmac)))
2069 {
2070 GNUNET_break_op (0);
2071 queue_finish (queue);
2072 return 0;
2073 }
2074 do_rekey (queue, rekey);
2075 size = ntohs (hdr->size);
2076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2077 "Handling plaintext, rekey processed!\n");
2078 GNUNET_STATISTICS_update (stats,
2079 "# rekeying successful",
2080 1,
2081 GNUNET_NO);
2082 break;
2083
2084 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_FINISH:
2085 fin = (const struct TCPFinish *) queue->pread_buf;
2086 if (sizeof(*fin) > queue->pread_off)
2087 return 0;
2088 if (ntohs (hdr->size) != sizeof(*fin))
2089 {
2090 GNUNET_break_op (0);
2091 queue_finish (queue);
2092 return 0;
2093 }
2094 finz = *fin;
2095 memset (&finz.hmac, 0, sizeof(finz.hmac));
2096 calculate_hmac (&queue->in_hmac, &finz, sizeof(finz), &tmac);
2097 if (0 != memcmp (&tmac, &fin->hmac, sizeof(tmac)))
2098 {
2099 GNUNET_break_op (0);
2100 queue_finish (queue);
2101 return 0;
2102 }
2103 /* handle FINISH by destroying queue */
2104 queue_destroy (queue);
2105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2106 "Handling plaintext, finish processed!\n");
2107 break;
2108
2109 default:
2110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2111 "Handling plaintext, nothing processed!\n");
2112 GNUNET_break_op (0);
2113 queue_finish (queue);
2114 return 0;
2115 }
2116 GNUNET_assert (0 != size);
2117 if (-1 != queue->unverified_size)
2118 queue->unverified_size += size;
2119 return size;
2120}
2121
2122
2123/**
2124 * Queue read task. If we hit the timeout, disconnect it
2125 *
2126 * @param cls the `struct Queue *` to disconnect
2127 */
2128static void
2129queue_read (void *cls)
2130{
2131 struct Queue *queue = cls;
2132 struct GNUNET_TIME_Relative left;
2133 ssize_t rcvd;
2134
2135 queue->read_task = NULL;
2136 rcvd = GNUNET_NETWORK_socket_recv (queue->sock,
2137 &queue->cread_buf[queue->cread_off],
2138 BUF_SIZE - queue->cread_off);
2139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2140 "Received %zd bytes from TCP queue\n", rcvd);
2141 if (-1 == rcvd)
2142 {
2143 if ((EAGAIN != errno) && (EINTR != errno))
2144 {
2145 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2146 queue_destroy (queue);
2147 return;
2148 }
2149 /* try again */
2150 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
2151 if (0 != left.rel_value_us)
2152 {
2153 queue->read_task =
2154 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read, queue);
2155 return;
2156 }
2157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2158 "Queue %p was idle for %s, disconnecting\n",
2159 queue,
2160 GNUNET_STRINGS_relative_time_to_string (
2161 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2162 GNUNET_YES));
2163 queue_destroy (queue);
2164 return;
2165 }
2166 if (0 == rcvd)
2167 {
2168 /* Orderly shutdown of connection */
2169 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2170 "Socket for queue %p seems to have been closed\n", queue);
2171 queue_destroy (queue);
2172 return;
2173 }
2174 queue->timeout =
2175 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2176 queue->cread_off += rcvd;
2177 while ((queue->pread_off < sizeof(queue->pread_buf)) &&
2178 (queue->cread_off > 0))
2179 {
2180 size_t max = GNUNET_MIN (sizeof(queue->pread_buf) - queue->pread_off,
2181 queue->cread_off);
2182 size_t done;
2183 size_t total;
2184 size_t old_pread_off = queue->pread_off;
2185
2186 GNUNET_assert (0 ==
2187 gcry_cipher_decrypt (queue->in_cipher,
2188 &queue->pread_buf[queue->pread_off],
2189 max,
2190 queue->cread_buf,
2191 max));
2192 queue->pread_off += max;
2193 total = 0;
2194 while (0 != (done = try_handle_plaintext (queue)))
2195 {
2196 /* 'done' bytes of plaintext were used, shift buffer */
2197 GNUNET_assert (done <= queue->pread_off);
2198 /* NOTE: this memmove() could possibly sometimes be
2199 avoided if we pass 'total' into try_handle_plaintext()
2200 and use it at an offset into the buffer there! */
2201 memmove (queue->pread_buf,
2202 &queue->pread_buf[done],
2203 queue->pread_off - done);
2204 queue->pread_off -= done;
2205 total += done;
2206 /* The last plaintext was a rekey, abort for now */
2207 if (GNUNET_YES == queue->rekeyed)
2208 break;
2209 }
2210 /* when we encounter a rekey message, the decryption above uses the
2211 wrong key for everything after the rekey; in that case, we have
2212 to re-do the decryption at 'total' instead of at 'max'.
2213 However, we have to take into account that the plaintext buffer may have
2214 already contained data and not jumped too far ahead in the ciphertext.
2215 If there is no rekey and the last message is incomplete (max > total),
2216 it is safe to keep the decryption so we shift by 'max' */
2217 if (GNUNET_YES == queue->rekeyed)
2218 {
2219 max = total - old_pread_off;
2220 queue->rekeyed = GNUNET_NO;
2221 queue->pread_off = 0;
2222 }
2223 memmove (queue->cread_buf, &queue->cread_buf[max], queue->cread_off - max);
2224 queue->cread_off -= max;
2225 }
2226 if (BUF_SIZE == queue->cread_off)
2227 return; /* buffer full, suspend reading */
2228 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
2229 if (0 != left.rel_value_us)
2230 {
2231 if (max_queue_length > queue->backpressure)
2232 {
2233 /* continue reading */
2234 queue->read_task =
2235 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read, queue);
2236 }
2237 return;
2238 }
2239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2240 "Queue %p was idle for %s, disconnecting\n",
2241 queue,
2242 GNUNET_STRINGS_relative_time_to_string (
2243 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
2244 GNUNET_YES));
2245 queue_destroy (queue);
2246}
2247
2248
2249/**
2250 * Convert a `struct sockaddr_in6 to a `struct sockaddr *`
2251 *
2252 * @param[out] sock_len set to the length of the address.
2253 * @param v6 The sockaddr_in6 to be converted.
2254 * @return The struct sockaddr *.
2255 */
2256static struct sockaddr *
2257tcp_address_to_sockaddr_numeric_v6 (socklen_t *sock_len,
2258 struct sockaddr_in6 v6,
2259 unsigned int port)
2260{
2261 struct sockaddr *in;
2262
2263 v6.sin6_family = AF_INET6;
2264 v6.sin6_port = htons ((uint16_t) port);
2265#if HAVE_SOCKADDR_IN_SIN_LEN
2266 v6.sin6_len = sizeof(struct sockaddr_in6);
2267#endif
2268 v6.sin6_flowinfo = 0;
2269 v6.sin6_scope_id = 0;
2270 in = GNUNET_memdup (&v6, sizeof(v6));
2271 *sock_len = sizeof(struct sockaddr_in6);
2272
2273 return in;
2274}
2275
2276
2277/**
2278 * Convert a `struct sockaddr_in4 to a `struct sockaddr *`
2279 *
2280 * @param[out] sock_len set to the length of the address.
2281 * @param v4 The sockaddr_in4 to be converted.
2282 * @return The struct sockaddr *.
2283 */
2284static struct sockaddr *
2285tcp_address_to_sockaddr_numeric_v4 (socklen_t *sock_len,
2286 struct sockaddr_in v4,
2287 unsigned int port)
2288{
2289 struct sockaddr *in;
2290
2291 v4.sin_family = AF_INET;
2292 v4.sin_port = htons ((uint16_t) port);
2293#if HAVE_SOCKADDR_IN_SIN_LEN
2294 v4.sin_len = sizeof(struct sockaddr_in);
2295#endif
2296 in = GNUNET_memdup (&v4, sizeof(v4));
2297 *sock_len = sizeof(struct sockaddr_in);
2298 return in;
2299}
2300
2301
2302/**
2303 * Convert TCP bind specification to a `struct PortOnlyIpv4Ipv6 *`
2304 *
2305 * @param bindto bind specification to convert.
2306 * @return The converted bindto specification.
2307 */
2308static struct PortOnlyIpv4Ipv6 *
2309tcp_address_to_sockaddr_port_only (const char *bindto, unsigned int *port)
2310{
2311 struct PortOnlyIpv4Ipv6 *po;
2312 struct sockaddr_in *i4;
2313 struct sockaddr_in6 *i6;
2314 socklen_t sock_len_ipv4;
2315 socklen_t sock_len_ipv6;
2316
2317 /* interpreting value as just a PORT number */
2318 if (*port > UINT16_MAX)
2319 {
2320 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2321 "BINDTO specification `%s' invalid: value too large for port\n",
2322 bindto);
2323 return NULL;
2324 }
2325
2326 po = GNUNET_new (struct PortOnlyIpv4Ipv6);
2327
2328 if (GNUNET_YES == disable_v6)
2329 {
2330 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2331 po->addr_ipv4 = tcp_address_to_sockaddr_numeric_v4 (&sock_len_ipv4, *i4,
2332 *port);
2333 po->addr_len_ipv4 = sock_len_ipv4;
2334 }
2335 else
2336 {
2337
2338 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2339 po->addr_ipv4 = tcp_address_to_sockaddr_numeric_v4 (&sock_len_ipv4, *i4,
2340 *port);
2341 po->addr_len_ipv4 = sock_len_ipv4;
2342
2343 i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
2344 po->addr_ipv6 = tcp_address_to_sockaddr_numeric_v6 (&sock_len_ipv6, *i6,
2345 *port);
2346
2347 po->addr_len_ipv6 = sock_len_ipv6;
2348
2349 GNUNET_free (i6);
2350 }
2351
2352 GNUNET_free (i4);
2353
2354 return po;
2355}
2356
2357
2358/**
2359 * This Method extracts the address part of the BINDTO string.
2360 *
2361 * @param bindto String we extract the address part from.
2362 * @return The extracted address string.
2363 */
2364static char *
2365extract_address (const char *bindto)
2366{
2367 char *addr;
2368 char *start;
2369 char *token;
2370 char *cp;
2371 char *rest = NULL;
2372
2373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2374 "extract address with bindto %s\n",
2375 bindto);
2376
2377 if (NULL == bindto)
2378 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2379 "bindto is NULL\n");
2380
2381 cp = GNUNET_strdup (bindto);
2382
2383 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2384 "extract address 2\n");
2385
2386 start = cp;
2387 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
2388 {
2389 start++; /* skip over '['*/
2390 cp[strlen (cp) - 1] = '\0'; /* eat ']'*/
2391 addr = GNUNET_strdup (start);
2392 }
2393 else
2394 {
2395 token = strtok_r (cp, "]", &rest);
2396 if (strlen (bindto) == strlen (token))
2397 {
2398 token = strtok_r (cp, ":", &rest);
2399 addr = GNUNET_strdup (token);
2400 }
2401 else
2402 {
2403 token++;
2404 addr = GNUNET_strdup (token);
2405 }
2406 }
2407
2408 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2409 "tcp address: %s\n",
2410 addr);
2411 GNUNET_free (cp);
2412 return addr;
2413}
2414
2415
2416/**
2417 * This Method extracts the port part of the BINDTO string.
2418 *
2419 * @param addr_and_port String we extract the port from.
2420 * @return The extracted port as unsigned int.
2421 */
2422static unsigned int
2423extract_port (const char *addr_and_port)
2424{
2425 unsigned int port;
2426 char dummy[2];
2427 char *token;
2428 char *addr;
2429 char *colon;
2430 char *cp;
2431 char *rest = NULL;
2432
2433 if (NULL != addr_and_port)
2434 {
2435 cp = GNUNET_strdup (addr_and_port);
2436 token = strtok_r (cp, "]", &rest);
2437 if (strlen (addr_and_port) == strlen (token))
2438 {
2439 colon = strrchr (cp, ':');
2440 if (NULL == colon)
2441 {
2442 GNUNET_free (cp);
2443 return 0;
2444 }
2445 addr = colon;
2446 addr++;
2447 }
2448 else
2449 {
2450 token = strtok_r (NULL, "]", &rest);
2451 if (NULL == token)
2452 {
2453 GNUNET_free (cp);
2454 return 0;
2455 }
2456 else
2457 {
2458 addr = token;
2459 addr++;
2460 }
2461 }
2462
2463
2464 if (1 == sscanf (addr, "%u%1s", &port, dummy))
2465 {
2466 /* interpreting value as just a PORT number */
2467 if (port > UINT16_MAX)
2468 {
2469 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2470 "Port `%u' invalid: value too large for port\n",
2471 port);
2472 GNUNET_free (cp);
2473 return 0;
2474 }
2475 }
2476 else
2477 {
2478 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2479 "BINDTO specification invalid: last ':' not followed by number\n");
2480 GNUNET_free (cp);
2481 return 0;
2482 }
2483 GNUNET_free (cp);
2484 }
2485 else
2486 {
2487 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2488 "return 0\n");
2489 /* interpret missing port as 0, aka pick any free one */
2490 port = 0;
2491 }
2492
2493 return port;
2494}
2495
2496
2497/**
2498 * Convert TCP bind specification to a `struct sockaddr *`
2499 *
2500 * @param bindto bind specification to convert
2501 * @param[out] sock_len set to the length of the address
2502 * @return converted bindto specification
2503 */
2504static struct sockaddr *
2505tcp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
2506{
2507 struct sockaddr *in;
2508 unsigned int port;
2509 struct sockaddr_in v4;
2510 struct sockaddr_in6 v6;
2511 char *start;
2512
2513 memset (&v4, 0, sizeof(v4));
2514 start = extract_address (bindto);
2515 GNUNET_assert (NULL != start);
2516 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2517 "start %s\n",
2518 start);
2519
2520 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2521 "!bindto %s\n",
2522 bindto);
2523
2524
2525 if (1 == inet_pton (AF_INET, start, &v4.sin_addr))
2526 {
2527 port = extract_port (bindto);
2528
2529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2530 "port %u\n",
2531 port);
2532
2533 in = tcp_address_to_sockaddr_numeric_v4 (sock_len, v4, port);
2534 }
2535 else if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
2536 {
2537 port = extract_port (bindto);
2538 in = tcp_address_to_sockaddr_numeric_v6 (sock_len, v6, port);
2539 }
2540 else
2541 {
2542 GNUNET_assert (0);
2543 }
2544
2545 GNUNET_free (start);
2546 return in;
2547}
2548
2549
2550/**
2551 * Signature of functions implementing the sending functionality of a
2552 * message queue.
2553 *
2554 * @param mq the message queue
2555 * @param msg the message to send
2556 * @param impl_state our `struct Queue`
2557 */
2558static void
2559mq_send (struct GNUNET_MQ_Handle *mq,
2560 const struct GNUNET_MessageHeader *msg,
2561 void *impl_state)
2562{
2563 struct Queue *queue = impl_state;
2564 uint16_t msize = ntohs (msg->size);
2565 struct TCPBox box;
2566 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2567 "In MQ send. Queue finishing: %s; write task running: %s\n",
2568 (GNUNET_YES == queue->finishing) ? "yes" : "no",
2569 (NULL == queue->write_task) ? "yes" : "no");
2570 GNUNET_assert (mq == queue->mq);
2571 queue->mq_awaits_continue = GNUNET_YES;
2572 if (GNUNET_YES == queue->finishing)
2573 return; /* this queue is dying, drop msg */
2574 GNUNET_assert (0 == queue->pwrite_off);
2575 box.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_TCP_BOX);
2576 box.header.size = htons (msize);
2577 calculate_hmac (&queue->out_hmac, msg, msize, &box.hmac);
2578 memcpy (&queue->pwrite_buf[queue->pwrite_off], &box, sizeof(box));
2579 queue->pwrite_off += sizeof(box);
2580 memcpy (&queue->pwrite_buf[queue->pwrite_off], msg, msize);
2581 queue->pwrite_off += msize;
2582 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2583 "%lu bytes of plaintext to send\n", queue->pwrite_off);
2584 GNUNET_assert (NULL != queue->sock);
2585 if (NULL == queue->write_task)
2586 queue->write_task =
2587 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2588 queue->sock,
2589 &queue_write,
2590 queue);
2591}
2592
2593
2594/**
2595 * Signature of functions implementing the destruction of a message
2596 * queue. Implementations must not free @a mq, but should take care
2597 * of @a impl_state.
2598 *
2599 * @param mq the message queue to destroy
2600 * @param impl_state our `struct Queue`
2601 */
2602static void
2603mq_destroy (struct GNUNET_MQ_Handle *mq, void *impl_state)
2604{
2605 struct Queue *queue = impl_state;
2606
2607 if (mq == queue->mq)
2608 {
2609 queue->mq = NULL;
2610 queue_finish (queue);
2611 }
2612}
2613
2614
2615/**
2616 * Implementation function that cancels the currently sent message.
2617 *
2618 * @param mq message queue
2619 * @param impl_state our `struct Queue`
2620 */
2621static void
2622mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
2623{
2624 struct Queue *queue = impl_state;
2625
2626 GNUNET_assert (0 != queue->pwrite_off);
2627 queue->pwrite_off = 0;
2628}
2629
2630
2631/**
2632 * Generic error handler, called with the appropriate
2633 * error code and the same closure specified at the creation of
2634 * the message queue.
2635 * Not every message queue implementation supports an error handler.
2636 *
2637 * @param cls our `struct Queue`
2638 * @param error error code
2639 */
2640static void
2641mq_error (void *cls, enum GNUNET_MQ_Error error)
2642{
2643 struct Queue *queue = cls;
2644
2645 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2646 "MQ error in queue to %s: %d\n",
2647 GNUNET_i2s (&queue->target),
2648 (int) error);
2649 queue_finish (queue);
2650}
2651
2652
2653/**
2654 * Add the given @a queue to our internal data structure. Setup the
2655 * MQ processing and inform transport that the queue is ready. Must
2656 * be called after the KX for outgoing messages has been bootstrapped.
2657 *
2658 * @param queue queue to boot
2659 */
2660static void
2661boot_queue (struct Queue *queue)
2662{
2663 queue->nt =
2664 GNUNET_NT_scanner_get_type (is, queue->address, queue->address_len);
2665 (void) GNUNET_CONTAINER_multihashmap_put (
2666 queue_map,
2667 &queue->key,
2668 queue,
2669 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2670 GNUNET_STATISTICS_set (stats,
2671 "# queues active",
2672 GNUNET_CONTAINER_multihashmap_size (queue_map),
2673 GNUNET_NO);
2674 queue->timeout =
2675 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2676 queue->mq = GNUNET_MQ_queue_for_callbacks (&mq_send,
2677 &mq_destroy,
2678 &mq_cancel,
2679 queue,
2680 NULL,
2681 &mq_error,
2682 queue);
2683}
2684
2685
2686/**
2687 * Generate and transmit our ephemeral key and the signature for
2688 * the initial KX with the other peer. Must be called first, before
2689 * any other bytes are ever written to the output buffer. Note that
2690 * our cipher must already be initialized when calling this function.
2691 * Helper function for #start_initial_kx_out().
2692 *
2693 * @param queue queue to do KX for
2694 * @param epub our public key for the KX
2695 */
2696static void
2697transmit_kx (struct Queue *queue,
2698 const struct GNUNET_CRYPTO_EcdhePublicKey *epub)
2699{
2700 struct TcpHandshakeSignature ths;
2701 struct TCPConfirmation tc;
2702
2703 memcpy (queue->cwrite_buf, epub, sizeof(*epub));
2704 queue->cwrite_off = sizeof(*epub);
2705 /* compute 'tc' and append in encrypted format to cwrite_buf */
2706 tc.sender = my_identity;
2707 tc.monotonic_time =
2708 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
2709 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
2710 &tc.challenge,
2711 sizeof(tc.challenge));
2712 ths.purpose.purpose = htonl (
2713 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE);
2714 ths.purpose.size = htonl (sizeof(ths));
2715 ths.sender = my_identity;
2716 ths.receiver = queue->target;
2717 ths.ephemeral = *epub;
2718 ths.monotonic_time = tc.monotonic_time;
2719 ths.challenge = tc.challenge;
2720 GNUNET_CRYPTO_eddsa_sign (my_private_key,
2721 &ths,
2722 &tc.sender_sig);
2723 GNUNET_assert (0 ==
2724 gcry_cipher_encrypt (queue->out_cipher,
2725 &queue->cwrite_buf[queue->cwrite_off],
2726 sizeof(tc),
2727 &tc,
2728 sizeof(tc)));
2729 queue->challenge = tc.challenge;
2730 queue->cwrite_off += sizeof(tc);
2731
2732 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2733 "handshake written\n");
2734}
2735
2736
2737/**
2738 * Initialize our key material for outgoing transmissions and
2739 * inform the other peer about it. Must be called first before
2740 * any data is sent.
2741 *
2742 * @param queue the queue to setup
2743 */
2744static void
2745start_initial_kx_out (struct Queue *queue)
2746{
2747 struct GNUNET_CRYPTO_EcdhePublicKey epub;
2748 struct GNUNET_HashCode k;
2749
2750 // TODO: We could use the Elligator KEM here! https://bugs.gnunet.org/view.php?id=8065
2751 GNUNET_CRYPTO_eddsa_kem_encaps (&queue->target.public_key, &epub, &k);
2752 setup_out_cipher (queue, &k);
2753 transmit_kx (queue, &epub);
2754}
2755
2756
2757/**
2758 * Callback called when peerstore store operation for handshake monotime is finished.
2759 * @param cls Queue context the store operation was executed.
2760 * @param success Store operation was successful (GNUNET_OK) or not.
2761 */
2762static void
2763handshake_monotime_store_cb (void *cls, int success)
2764{
2765 struct Queue *queue = cls;
2766 if (GNUNET_OK != success)
2767 {
2768 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2769 "Failed to store handshake monotonic time in PEERSTORE!\n");
2770 }
2771 queue->handshake_monotime_sc = NULL;
2772 GNUNET_PEERSTORE_iteration_next (queue->handshake_ack_monotime_get, 1);
2773}
2774
2775
2776/**
2777 * Callback called by peerstore when records for GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE
2778 * where found.
2779 * @param cls Queue context the store operation was executed.
2780 * @param record The record found or NULL if there is no record left.
2781 * @param emsg Message from peerstore.
2782 */
2783static void
2784handshake_monotime_cb (void *cls,
2785 const struct GNUNET_PEERSTORE_Record *record,
2786 const char *emsg)
2787{
2788 struct Queue *queue = cls;
2789 struct GNUNET_TIME_AbsoluteNBO *mtbe;
2790 struct GNUNET_TIME_Absolute mt;
2791 const struct GNUNET_PeerIdentity *pid;
2792 struct GNUNET_TIME_AbsoluteNBO *handshake_monotonic_time;
2793
2794 (void) emsg;
2795
2796 handshake_monotonic_time = &queue->handshake_monotonic_time;
2797 pid = &queue->target;
2798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2799 "tcp handshake with us %s\n",
2800 GNUNET_i2s (&my_identity));
2801 if (NULL == record)
2802 {
2803 queue->handshake_monotime_get = NULL;
2804 return;
2805 }
2806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2807 "tcp handshake from peer %s\n",
2808 GNUNET_i2s (pid));
2809 if (sizeof(*mtbe) != record->value_size)
2810 {
2811 GNUNET_PEERSTORE_iteration_next (queue->handshake_ack_monotime_get, 1);
2812 GNUNET_break (0);
2813 return;
2814 }
2815 mtbe = record->value;
2816 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
2817 if (mt.abs_value_us > GNUNET_TIME_absolute_ntoh (
2818 queue->handshake_monotonic_time).abs_value_us)
2819 {
2820 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2821 "Queue from %s dropped, handshake monotime in the past\n",
2822 GNUNET_i2s (&queue->target));
2823 GNUNET_break (0);
2824 GNUNET_PEERSTORE_iteration_stop (queue->handshake_ack_monotime_get);
2825 queue->handshake_ack_monotime_get = NULL;
2826 queue_finish (queue);
2827 return;
2828 }
2829 queue->handshake_monotime_sc = GNUNET_PEERSTORE_store (peerstore,
2830 "transport_tcp_communicator",
2831 pid,
2832 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE,
2833 handshake_monotonic_time,
2834 sizeof(*
2835 handshake_monotonic_time),
2836 GNUNET_TIME_UNIT_FOREVER_ABS,
2837 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
2838 &
2839 handshake_monotime_store_cb,
2840 queue);
2841}
2842
2843
2844/**
2845 * We have received the first bytes from the other side on a @a queue.
2846 * Decrypt the @a tc contained in @a ibuf and check the signature.
2847 * Note that #setup_in_cipher() must have already been called.
2848 *
2849 * @param queue queue to decrypt initial bytes from other peer for
2850 * @param[out] tc where to store the result
2851 * @param ibuf incoming data, of size
2852 * `INITIAL_KX_SIZE`
2853 * @return #GNUNET_OK if the signature was OK, #GNUNET_SYSERR if not
2854 */
2855static int
2856decrypt_and_check_tc (struct Queue *queue,
2857 struct TCPConfirmation *tc,
2858 char *ibuf)
2859{
2860 struct TcpHandshakeSignature ths;
2861 enum GNUNET_GenericReturnValue ret;
2862
2863 GNUNET_assert (
2864 0 ==
2865 gcry_cipher_decrypt (queue->in_cipher,
2866 tc,
2867 sizeof(*tc),
2868 &ibuf[sizeof(struct GNUNET_CRYPTO_EcdhePublicKey)],
2869 sizeof(*tc)));
2870 ths.purpose.purpose = htonl (
2871 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE);
2872 ths.purpose.size = htonl (sizeof(ths));
2873 ths.sender = tc->sender;
2874 ths.receiver = my_identity;
2875 memcpy (&ths.ephemeral, ibuf, sizeof(struct GNUNET_CRYPTO_EcdhePublicKey));
2876 ths.monotonic_time = tc->monotonic_time;
2877 ths.challenge = tc->challenge;
2878 ret = GNUNET_CRYPTO_eddsa_verify (
2879 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_TCP_HANDSHAKE,
2880 &ths,
2881 &tc->sender_sig,
2882 &tc->sender.public_key);
2883 if (GNUNET_YES == ret)
2884 queue->handshake_monotime_get =
2885 GNUNET_PEERSTORE_iteration_start (peerstore,
2886 "transport_tcp_communicator",
2887 &queue->target,
2888 GNUNET_PEERSTORE_TRANSPORT_TCP_COMMUNICATOR_HANDSHAKE,
2889 &handshake_monotime_cb,
2890 queue);
2891 return ret;
2892}
2893
2894
2895/**
2896 * Read from the socket of the queue until we have enough data
2897 * to initialize the decryption logic and can switch to regular
2898 * reading.
2899 *
2900 * @param cls a `struct Queue`
2901 */
2902static void
2903queue_read_kx (void *cls)
2904{
2905 struct Queue *queue = cls;
2906 ssize_t rcvd;
2907 struct GNUNET_TIME_Relative left;
2908 struct TCPConfirmation tc;
2909
2910 queue->read_task = NULL;
2911 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
2912 if (0 == left.rel_value_us)
2913 {
2914 queue_destroy (queue);
2915 return;
2916 }
2917 rcvd = GNUNET_NETWORK_socket_recv (queue->sock,
2918 &queue->cread_buf[queue->cread_off],
2919 BUF_SIZE - queue->cread_off);
2920 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2921 "Received %lu bytes to write in buffer of size %lu for KX from queue %p (expires in %"
2922 PRIu64 ")\n",
2923 rcvd, BUF_SIZE - queue->cread_off, queue, left.rel_value_us);
2924 if (-1 == rcvd)
2925 {
2926 if ((EAGAIN != errno) && (EINTR != errno))
2927 {
2928 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
2929 queue_destroy (queue);
2930 return;
2931 }
2932 queue->read_task =
2933 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read_kx, queue);
2934 return;
2935 }
2936 if (0 == rcvd)
2937 {
2938 /* Orderly shutdown of connection */
2939 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2940 "Socket for queue %p seems to have been closed\n", queue);
2941 queue_destroy (queue);
2942 return;
2943 }
2944 queue->cread_off += rcvd;
2945 if (queue->cread_off < INITIAL_KX_SIZE)
2946 {
2947 /* read more */
2948 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2949 "%lu/%lu bytes of KX read. Rescheduling...\n",
2950 queue->cread_off, INITIAL_KX_SIZE);
2951 queue->read_task =
2952 GNUNET_SCHEDULER_add_read_net (left, queue->sock, &queue_read_kx, queue);
2953 return;
2954 }
2955 /* we got all the data, let's find out who we are talking to! */
2956 setup_in_cipher ((const struct GNUNET_CRYPTO_EcdhePublicKey *)
2957 queue->cread_buf,
2958 queue);
2959 if (GNUNET_OK != decrypt_and_check_tc (queue, &tc, queue->cread_buf))
2960 {
2961 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
2962 "Invalid TCP KX received from %s\n",
2963 GNUNET_a2s (queue->address, queue->address_len));
2964 queue_destroy (queue);
2965 return;
2966 }
2967 if (0 !=
2968 memcmp (&tc.sender, &queue->target, sizeof(struct GNUNET_PeerIdentity)))
2969 {
2970 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2971 "Invalid sender in TCP KX received from %s\n",
2972 GNUNET_a2s (queue->address, queue->address_len));
2973 queue_destroy (queue);
2974 return;
2975 }
2976 send_challenge (tc.challenge, queue);
2977 queue->write_task =
2978 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
2979 queue->sock,
2980 &queue_write,
2981 queue);
2982
2983 /* update queue timeout */
2984 queue->timeout =
2985 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2986 /* prepare to continue with regular read task immediately */
2987 memmove (queue->cread_buf,
2988 &queue->cread_buf[INITIAL_KX_SIZE],
2989 queue->cread_off - (INITIAL_KX_SIZE));
2990 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2991 "cread_off is %lu bytes before adjusting\n",
2992 queue->cread_off);
2993 queue->cread_off -= INITIAL_KX_SIZE;
2994 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2995 "cread_off set to %lu bytes\n",
2996 queue->cread_off);
2997 queue->read_task = GNUNET_SCHEDULER_add_now (&queue_read, queue);
2998}
2999
3000
3001/**
3002 * Read from the socket of the proto queue until we have enough data
3003 * to upgrade to full queue.
3004 *
3005 * @param cls a `struct ProtoQueue`
3006 */
3007static void
3008proto_read_kx (void *cls)
3009{
3010 struct ProtoQueue *pq = cls;
3011 ssize_t rcvd;
3012 struct GNUNET_TIME_Relative left;
3013 struct Queue *queue;
3014 struct TCPConfirmation tc;
3015 GNUNET_SCHEDULER_TaskCallback read_task;
3016
3017 pq->read_task = NULL;
3018 left = GNUNET_TIME_absolute_get_remaining (pq->timeout);
3019 if (0 == left.rel_value_us)
3020 {
3021 free_proto_queue (pq);
3022 return;
3023 }
3024 rcvd = GNUNET_NETWORK_socket_recv (pq->sock,
3025 &pq->ibuf[pq->ibuf_off],
3026 sizeof(pq->ibuf) - pq->ibuf_off);
3027 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3028 "Proto received %lu bytes for KX\n", rcvd);
3029 if (-1 == rcvd)
3030 {
3031 if ((EAGAIN != errno) && (EINTR != errno))
3032 {
3033 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "recv");
3034 free_proto_queue (pq);
3035 return;
3036 }
3037 /* try again */
3038 pq->read_task =
3039 GNUNET_SCHEDULER_add_read_net (left, pq->sock, &proto_read_kx, pq);
3040 return;
3041 }
3042 if (0 == rcvd)
3043 {
3044 /* Orderly shutdown of connection */
3045 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3046 "Socket for proto queue %p seems to have been closed\n", pq);
3047 free_proto_queue (pq);
3048 return;
3049 }
3050 pq->ibuf_off += rcvd;
3051 if (sizeof (struct TCPNATProbeMessage) == pq->ibuf_off)
3052 {
3053 struct TCPNATProbeMessage *pm = (struct TCPNATProbeMessage *) pq->ibuf;
3054
3055 check_and_remove_pending_reversal (pq->address, pq->address->sa_family,
3056 &pm->clientIdentity);
3057
3058 queue = GNUNET_new (struct Queue);
3059 queue->target = pm->clientIdentity;
3060 queue->cs = GNUNET_TRANSPORT_CS_OUTBOUND;
3061 read_task = &queue_read_kx;
3062 }
3063 else if (pq->ibuf_off > sizeof(pq->ibuf))
3064 {
3065 /* read more */
3066 pq->read_task =
3067 GNUNET_SCHEDULER_add_read_net (left, pq->sock, &proto_read_kx, pq);
3068 return;
3069 }
3070 else
3071 {
3072 /* we got all the data, let's find out who we are talking to! */
3073 queue = GNUNET_new (struct Queue);
3074 setup_in_cipher ((const struct GNUNET_CRYPTO_EcdhePublicKey *) pq->ibuf,
3075 queue);
3076 if (GNUNET_OK != decrypt_and_check_tc (queue, &tc, pq->ibuf))
3077 {
3078 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3079 "Invalid TCP KX received from %s\n",
3080 GNUNET_a2s (pq->address, pq->address_len));
3081 gcry_cipher_close (queue->in_cipher);
3082 GNUNET_free (queue);
3083 free_proto_queue (pq);
3084 return;
3085 }
3086 queue->target = tc.sender;
3087 queue->cs = GNUNET_TRANSPORT_CS_INBOUND;
3088 read_task = &queue_read;
3089 }
3090 queue->address = pq->address; /* steals reference */
3091 queue->address_len = pq->address_len;
3092 queue->listen_sock = pq->listen_sock;
3093 queue->sock = pq->sock;
3094
3095 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3096 "created queue with target %s\n",
3097 GNUNET_i2s (&queue->target));
3098
3099 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3100 "start kx proto\n");
3101
3102 start_initial_kx_out (queue);
3103 boot_queue (queue);
3104 queue->read_task =
3105 GNUNET_SCHEDULER_add_read_net (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3106 queue->sock,
3107 read_task,
3108 queue);
3109 queue->write_task =
3110 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3111 queue->sock,
3112 &queue_write,
3113 queue);
3114 // TODO To early! Move it somewhere else.
3115 // send_challenge (tc.challenge, queue);
3116 queue->challenge_received = tc.challenge;
3117
3118 GNUNET_CONTAINER_DLL_remove (proto_head, proto_tail, pq);
3119 GNUNET_free (pq);
3120}
3121
3122
3123static struct ProtoQueue *
3124create_proto_queue (struct GNUNET_NETWORK_Handle *sock,
3125 struct sockaddr *in,
3126 socklen_t addrlen)
3127{
3128 struct ProtoQueue *pq = GNUNET_new (struct ProtoQueue);
3129
3130 if (NULL == sock)
3131 {
3132 // sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen);
3133 sock = GNUNET_NETWORK_socket_create (in->sa_family, SOCK_STREAM, 0);
3134 if (NULL == sock)
3135 {
3136 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3137 "socket(%d) failed: %s",
3138 in->sa_family,
3139 strerror (errno));
3140 GNUNET_free (in);
3141 GNUNET_free (pq);
3142 return NULL;
3143 }
3144 if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (sock, in, addrlen)) &&
3145 (errno != EINPROGRESS))
3146 {
3147 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3148 "connect to `%s' failed: %s",
3149 GNUNET_a2s (in, addrlen),
3150 strerror (errno));
3151 GNUNET_NETWORK_socket_close (sock);
3152 GNUNET_free (in);
3153 GNUNET_free (pq);
3154 return NULL;
3155 }
3156 }
3157 pq->address_len = addrlen;
3158 pq->address = in;
3159 pq->timeout = GNUNET_TIME_relative_to_absolute (PROTO_QUEUE_TIMEOUT);
3160 pq->sock = sock;
3161 pq->read_task = GNUNET_SCHEDULER_add_read_net (PROTO_QUEUE_TIMEOUT,
3162 pq->sock,
3163 &proto_read_kx,
3164 pq);
3165 GNUNET_CONTAINER_DLL_insert (proto_head, proto_tail, pq);
3166
3167 return pq;
3168}
3169
3170
3171/**
3172 * We have been notified that our listen socket has something to
3173 * read. Do the read and reschedule this function to be called again
3174 * once more is available.
3175 *
3176 * @param cls ListenTask with listening socket and task
3177 */
3178static void
3179listen_cb (void *cls)
3180{
3181 struct sockaddr_storage in;
3182 socklen_t addrlen;
3183 struct GNUNET_NETWORK_Handle *sock;
3184 struct ListenTask *lt;
3185 struct sockaddr *in_addr;
3186
3187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3188 "listen_cb\n");
3189
3190 lt = cls;
3191
3192 lt->listen_task = NULL;
3193 GNUNET_assert (NULL != lt->listen_sock);
3194 addrlen = sizeof(in);
3195 memset (&in, 0, sizeof(in));
3196 sock = GNUNET_NETWORK_socket_accept (lt->listen_sock,
3197 (struct sockaddr*) &in,
3198 &addrlen);
3199 if ((NULL == sock) && ((EMFILE == errno) || (ENFILE == errno)))
3200 return; /* system limit reached, wait until connection goes down */
3201 lt->listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3202 lt->listen_sock,
3203 &listen_cb,
3204 lt);
3205 if ((NULL == sock) && ((EAGAIN == errno) || (ENOBUFS == errno)))
3206 return;
3207 if (NULL == sock)
3208 {
3209 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "accept");
3210 return;
3211 }
3212 in_addr = GNUNET_memdup (&in, addrlen);
3213 create_proto_queue (sock, in_addr, addrlen);
3214}
3215
3216
3217static void
3218try_connection_reversal (void *cls,
3219 const struct sockaddr *addr,
3220 socklen_t addrlen)
3221{
3222 (void) cls;
3223 struct TCPNATProbeMessage pm;
3224 struct ProtoQueue *pq;
3225 struct sockaddr *in_addr;
3226
3227 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3228 "addr->sa_family %d\n",
3229 addr->sa_family);
3230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3231 "Try to connect back\n");
3232 in_addr = GNUNET_memdup (addr, addrlen);
3233 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3234 "in_addr->sa_family %d\n",
3235 in_addr->sa_family);
3236 pq = create_proto_queue (NULL, in_addr, addrlen);
3237 if (NULL != pq)
3238 {
3239 pm.header.size = htons (sizeof(struct TCPNATProbeMessage));
3240 pm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
3241 pm.clientIdentity = my_identity;
3242 memcpy (pq->write_buf, &pm, sizeof(struct TCPNATProbeMessage));
3243 pq->write_off = sizeof(struct TCPNATProbeMessage);
3244 pq->write_task = GNUNET_SCHEDULER_add_write_net (PROTO_QUEUE_TIMEOUT,
3245 pq->sock,
3246 &proto_queue_write,
3247 pq);
3248 }
3249 else
3250 {
3251 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3252 "Couldn't create ProtoQueue for sending TCPNATProbeMessage\n");
3253 }
3254}
3255
3256
3257static void
3258pending_reversal_timeout (void *cls)
3259{
3260 struct sockaddr *in = cls;
3261 struct PendingReversal *pending_reversal;
3262 struct GNUNET_HashCode key;
3263
3264 GNUNET_CRYPTO_hash (in,
3265 sizeof(struct sockaddr),
3266 &key);
3267 pending_reversal = GNUNET_CONTAINER_multihashmap_get (pending_reversals,
3268 &key);
3269
3270 GNUNET_assert (NULL != pending_reversal);
3271
3272 if (GNUNET_NO == GNUNET_CONTAINER_multihashmap_remove (pending_reversals,
3273 &key,
3274 pending_reversal))
3275 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3276 "No pending reversal found for address %s\n",
3277 GNUNET_a2s (in, sizeof (struct sockaddr)));
3278 GNUNET_free (pending_reversal->in);
3279 GNUNET_free (pending_reversal);
3280}
3281
3282
3283/**
3284 * Function called by the transport service to initialize a
3285 * message queue given address information about another peer.
3286 * If and when the communication channel is established, the
3287 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
3288 * to notify the service that the channel is now up. It is
3289 * the responsibility of the communicator to manage sane
3290 * retries and timeouts for any @a peer/@a address combination
3291 * provided by the transport service. Timeouts and retries
3292 * do not need to be signalled to the transport service.
3293 *
3294 * @param cls closure
3295 * @param peer identity of the other peer
3296 * @param address where to send the message, human-readable
3297 * communicator-specific format, 0-terminated, UTF-8
3298 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is
3299 * invalid
3300 */
3301static int
3302mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
3303{
3304 struct sockaddr *in;
3305 socklen_t in_len = 0;
3306 const char *path;
3307 struct sockaddr_in *v4;
3308 struct sockaddr_in6 *v6;
3309 unsigned int is_natd = GNUNET_NO;
3310 struct GNUNET_HashCode key;
3311 struct GNUNET_HashCode queue_map_key;
3312 struct GNUNET_HashContext *hsh;
3313 struct Queue *queue;
3314
3315 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3316 "Connecting to %s at %s\n",
3317 GNUNET_i2s (peer),
3318 address);
3319 if (0 != strncmp (address,
3320 COMMUNICATOR_ADDRESS_PREFIX "-",
3321 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
3322 {
3323 GNUNET_break_op (0);
3324 return GNUNET_SYSERR;
3325 }
3326 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
3327 in = tcp_address_to_sockaddr (path, &in_len);
3328
3329 if (NULL == in)
3330 {
3331 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3332 "Failed to setup TCP socket address\n");
3333 return GNUNET_SYSERR;
3334 }
3335
3336 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3337 "in %s\n",
3338 GNUNET_a2s (in, in_len));
3339
3340 hsh = GNUNET_CRYPTO_hash_context_start ();
3341 GNUNET_CRYPTO_hash_context_read (hsh, address, strlen (address));
3342 GNUNET_CRYPTO_hash_context_read (hsh, peer, sizeof (*peer));
3343 GNUNET_CRYPTO_hash_context_finish (hsh, &queue_map_key);
3344 queue = GNUNET_CONTAINER_multihashmap_get (queue_map, &queue_map_key);
3345
3346 if (NULL != queue)
3347 {
3348 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3349 "Queue for %s already exists or is in construction\n", address);
3350 GNUNET_free (in);
3351 return GNUNET_NO;
3352 }
3353 switch (in->sa_family)
3354 {
3355 case AF_INET:
3356 v4 = (struct sockaddr_in *) in;
3357 if (0 == v4->sin_port)
3358 {
3359 is_natd = GNUNET_YES;
3360 GNUNET_CRYPTO_hash (in,
3361 sizeof(struct sockaddr),
3362 &key);
3363 if (GNUNET_YES == GNUNET_CONTAINER_multihashmap_contains (
3364 pending_reversals,
3365 &key))
3366 {
3367 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3368 "There is already a request reversal for `%s'at `%s'\n",
3369 GNUNET_i2s (peer),
3370 address);
3371 GNUNET_free (in);
3372 return GNUNET_SYSERR;
3373 }
3374 }
3375 break;
3376
3377 case AF_INET6:
3378 if (GNUNET_YES == disable_v6)
3379 {
3380 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3381 "IPv6 disabled, skipping %s\n", address);
3382 GNUNET_free (in);
3383 return GNUNET_SYSERR;
3384 }
3385 v6 = (struct sockaddr_in6 *) in;
3386 if (0 == v6->sin6_port)
3387 {
3388 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3389 "Request reversal for `%s' at `%s' not possible for an IPv6 address\n",
3390 GNUNET_i2s (peer),
3391 address);
3392 GNUNET_free (in);
3393 return GNUNET_SYSERR;
3394 }
3395 break;
3396
3397 default:
3398 GNUNET_assert (0);
3399 }
3400
3401 if (GNUNET_YES == is_natd)
3402 {
3403 struct sockaddr_in local_sa;
3404 struct PendingReversal *pending_reversal;
3405
3406 memset (&local_sa, 0, sizeof(local_sa));
3407 local_sa.sin_family = AF_INET;
3408 local_sa.sin_port = htons (bind_port);
3409 /* We leave sin_address at 0, let the kernel figure it out,
3410 even if our bind() is more specific. (May want to reconsider
3411 later.) */
3412 if (GNUNET_OK != GNUNET_NAT_request_reversal (nat, &local_sa, v4))
3413 {
3414 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3415 "request reversal for `%s' at `%s' failed\n",
3416 GNUNET_i2s (peer),
3417 address);
3418 GNUNET_free (in);
3419 return GNUNET_SYSERR;
3420 }
3421 pending_reversal = GNUNET_new (struct PendingReversal);
3422 pending_reversal->in = in;
3423 GNUNET_assert (GNUNET_OK ==
3424 GNUNET_CONTAINER_multihashmap_put (pending_reversals,
3425 &key,
3426 pending_reversal,
3427 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3428 pending_reversal->target = *peer;
3429 pending_reversal->timeout_task = GNUNET_SCHEDULER_add_delayed (NAT_TIMEOUT,
3430 &
3431 pending_reversal_timeout,
3432 in);
3433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3434 "Created NAT WAIT connection to `%s' at `%s'\n",
3435 GNUNET_i2s (peer),
3436 GNUNET_a2s (in, sizeof (struct sockaddr)));
3437 }
3438 else
3439 {
3440 struct GNUNET_NETWORK_Handle *sock;
3441
3442 sock = GNUNET_NETWORK_socket_create (in->sa_family, SOCK_STREAM,
3443 IPPROTO_TCP);
3444 if (NULL == sock)
3445 {
3446 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3447 "socket(%d) failed: %s",
3448 in->sa_family,
3449 strerror (errno));
3450 GNUNET_free (in);
3451 return GNUNET_SYSERR;
3452 }
3453 if ((GNUNET_OK != GNUNET_NETWORK_socket_connect (sock, in, in_len)) &&
3454 (errno != EINPROGRESS))
3455 {
3456 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3457 "connect to `%s' failed: %s",
3458 address,
3459 strerror (errno));
3460 GNUNET_NETWORK_socket_close (sock);
3461 GNUNET_free (in);
3462 return GNUNET_SYSERR;
3463 }
3464
3465 queue = GNUNET_new (struct Queue);
3466 queue->target = *peer;
3467 queue->key = queue_map_key;
3468 queue->address = in;
3469 queue->address_len = in_len;
3470 queue->sock = sock;
3471 queue->cs = GNUNET_TRANSPORT_CS_OUTBOUND;
3472 boot_queue (queue);
3473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3474 "booted queue with target %s\n",
3475 GNUNET_i2s (&queue->target));
3476 // queue->mq_awaits_continue = GNUNET_YES;
3477 queue->read_task =
3478 GNUNET_SCHEDULER_add_read_net (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
3479 queue->sock,
3480 &queue_read_kx,
3481 queue);
3482
3483
3484 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3485 "start kx mq_init\n");
3486
3487 start_initial_kx_out (queue);
3488 queue->write_task =
3489 GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
3490 queue->sock,
3491 &queue_write,
3492 queue);
3493 }
3494
3495 return GNUNET_OK;
3496}
3497
3498
3499/**
3500 * Iterator over all ListenTasks to clean up.
3501 *
3502 * @param cls NULL
3503 * @param key unused
3504 * @param value the ListenTask to cancel.
3505 * @return #GNUNET_OK to continue to iterate
3506 */
3507static int
3508get_lt_delete_it (void *cls,
3509 const struct GNUNET_HashCode *key,
3510 void *value)
3511{
3512 struct ListenTask *lt = value;
3513
3514 (void) cls;
3515 (void) key;
3516 if (NULL != lt->listen_task)
3517 {
3518 GNUNET_SCHEDULER_cancel (lt->listen_task);
3519 lt->listen_task = NULL;
3520 }
3521 if (NULL != lt->listen_sock)
3522 {
3523 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (lt->listen_sock));
3524 lt->listen_sock = NULL;
3525 }
3526 GNUNET_free (lt);
3527 return GNUNET_OK;
3528}
3529
3530
3531/**
3532 * Iterator over all message queues to clean up.
3533 *
3534 * @param cls NULL
3535 * @param target unused
3536 * @param value the queue to destroy
3537 * @return #GNUNET_OK to continue to iterate
3538 */
3539static int
3540get_queue_delete_it (void *cls,
3541 const struct GNUNET_HashCode *target,
3542 void *value)
3543{
3544 struct Queue *queue = value;
3545
3546 (void) cls;
3547 (void) target;
3548 queue_destroy (queue);
3549 return GNUNET_OK;
3550}
3551
3552
3553/**
3554 * Shutdown the UNIX communicator.
3555 *
3556 * @param cls NULL (always)
3557 */
3558static void
3559do_shutdown (void *cls)
3560{
3561 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3562 "Shutdown %s!\n",
3563 shutdown_running ? "running" : "not running");
3564
3565 if (GNUNET_YES == shutdown_running)
3566 return;
3567 else
3568 shutdown_running = GNUNET_YES;
3569
3570 while (NULL != proto_head)
3571 free_proto_queue (proto_head);
3572 if (NULL != nat)
3573 {
3574 GNUNET_NAT_unregister (nat);
3575 nat = NULL;
3576 }
3577 GNUNET_CONTAINER_multihashmap_iterate (pending_reversals,
3578 &pending_reversals_delete_it, NULL);
3579 GNUNET_CONTAINER_multihashmap_destroy (pending_reversals);
3580 GNUNET_CONTAINER_multihashmap_iterate (lt_map, &get_lt_delete_it, NULL);
3581 GNUNET_CONTAINER_multihashmap_destroy (lt_map);
3582 GNUNET_CONTAINER_multihashmap_iterate (queue_map, &get_queue_delete_it, NULL);
3583 GNUNET_CONTAINER_multihashmap_destroy (queue_map);
3584 if (NULL != ch)
3585 {
3586 GNUNET_TRANSPORT_communicator_address_remove_all (ch);
3587 GNUNET_TRANSPORT_communicator_disconnect (ch);
3588 ch = NULL;
3589 }
3590 if (NULL != stats)
3591 {
3592 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
3593 stats = NULL;
3594 }
3595 if (NULL != my_private_key)
3596 {
3597 GNUNET_free (my_private_key);
3598 my_private_key = NULL;
3599 }
3600 if (NULL != is)
3601 {
3602 GNUNET_NT_scanner_done (is);
3603 is = NULL;
3604 }
3605 if (NULL != peerstore)
3606 {
3607 GNUNET_PEERSTORE_disconnect (peerstore);
3608 peerstore = NULL;
3609 }
3610 if (NULL != resolve_request_handle)
3611 {
3612 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3613 resolve_request_handle = NULL;
3614 }
3615 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3616 "Shutdown done!\n");
3617}
3618
3619
3620/**
3621 * Function called when the transport service has received an
3622 * acknowledgement for this communicator (!) via a different return
3623 * path.
3624 *
3625 * Not applicable for TCP.
3626 *
3627 * @param cls closure
3628 * @param sender which peer sent the notification
3629 * @param msg payload
3630 */
3631static void
3632enc_notify_cb (void *cls,
3633 const struct GNUNET_PeerIdentity *sender,
3634 const struct GNUNET_MessageHeader *msg)
3635{
3636 (void) cls;
3637 (void) sender;
3638 (void) msg;
3639 GNUNET_break_op (0);
3640}
3641
3642
3643/**
3644 * Signature of the callback passed to #GNUNET_NAT_register() for
3645 * a function to call whenever our set of 'valid' addresses changes.
3646 *
3647 * @param cls closure
3648 * @param[in,out] app_ctx location where the app can store stuff
3649 * on add and retrieve it on remove
3650 * @param add_remove #GNUNET_YES to add a new public IP address,
3651 * #GNUNET_NO to remove a previous (now invalid) one
3652 * @param ac address class the address belongs to
3653 * @param addr either the previous or the new public IP address
3654 * @param addrlen actual length of the @a addr
3655 */
3656static void
3657nat_address_cb (void *cls,
3658 void **app_ctx,
3659 int add_remove,
3660 enum GNUNET_NAT_AddressClass ac,
3661 const struct sockaddr *addr,
3662 socklen_t addrlen)
3663{
3664 char *my_addr;
3665 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
3666
3667 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3668 "nat address cb %s %s\n",
3669 add_remove ? "add" : "remove",
3670 GNUNET_a2s (addr, addrlen));
3671
3672 if (GNUNET_YES == add_remove)
3673 {
3674 enum GNUNET_NetworkType nt;
3675
3676 GNUNET_asprintf (&my_addr,
3677 "%s-%s",
3678 COMMUNICATOR_ADDRESS_PREFIX,
3679 GNUNET_a2s (addr, addrlen));
3680 nt = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3681 ai =
3682 GNUNET_TRANSPORT_communicator_address_add (ch,
3683 my_addr,
3684 nt,
3685 GNUNET_TIME_UNIT_FOREVER_REL);
3686 GNUNET_free (my_addr);
3687 *app_ctx = ai;
3688 }
3689 else
3690 {
3691 ai = *app_ctx;
3692 GNUNET_TRANSPORT_communicator_address_remove (ai);
3693 *app_ctx = NULL;
3694 }
3695}
3696
3697
3698/**
3699 * This method adds addresses to the DLL, that are later register at the NAT service.
3700 */
3701static void
3702add_addr (struct sockaddr *in, socklen_t in_len)
3703{
3704
3705 struct Addresses *saddrs;
3706
3707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3708 "add address %s\n",
3709 GNUNET_a2s (in, in_len));
3710
3711 saddrs = GNUNET_new (struct Addresses);
3712 saddrs->addr = in;
3713 saddrs->addr_len = in_len;
3714 GNUNET_CONTAINER_DLL_insert (addrs_head, addrs_tail, saddrs);
3715
3716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3717 "after add address %s\n",
3718 GNUNET_a2s (in, in_len));
3719
3720 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3721 "add address %s\n",
3722 GNUNET_a2s (saddrs->addr, saddrs->addr_len));
3723
3724 addrs_lens++;
3725}
3726
3727
3728/**
3729 * This method launch network interactions for each address we like to bind to.
3730 *
3731 * @param addr The address we will listen to.
3732 * @param in_len The length of the address we will listen to.
3733 * @return GNUNET_SYSERR in case of error. GNUNET_OK in case we are successfully listen to the address.
3734 */
3735static int
3736init_socket (struct sockaddr *addr,
3737 socklen_t in_len)
3738{
3739 struct sockaddr_storage in_sto;
3740 socklen_t sto_len;
3741 struct GNUNET_NETWORK_Handle *listen_sock;
3742 struct ListenTask *lt;
3743 int sockfd;
3744 struct GNUNET_HashCode h_sock;
3745
3746 if (NULL == addr)
3747 {
3748 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3749 "Address is NULL.\n");
3750 return GNUNET_SYSERR;
3751 }
3752
3753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3754 "address %s\n",
3755 GNUNET_a2s (addr, in_len));
3756
3757 listen_sock =
3758 GNUNET_NETWORK_socket_create (addr->sa_family, SOCK_STREAM, IPPROTO_TCP);
3759 if (NULL == listen_sock)
3760 {
3761 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
3762 return GNUNET_SYSERR;
3763 }
3764
3765 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (listen_sock, addr, in_len))
3766 {
3767 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
3768 GNUNET_NETWORK_socket_close (listen_sock);
3769 listen_sock = NULL;
3770 return GNUNET_SYSERR;
3771 }
3772
3773 if (GNUNET_OK !=
3774 GNUNET_NETWORK_socket_listen (listen_sock,
3775 5))
3776 {
3777 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR,
3778 "listen");
3779 GNUNET_NETWORK_socket_close (listen_sock);
3780 listen_sock = NULL;
3781 return GNUNET_SYSERR;
3782 }
3783
3784 /* We might have bound to port 0, allowing the OS to figure it out;
3785 thus, get the real IN-address from the socket */
3786 sto_len = sizeof(in_sto);
3787
3788 if (0 != getsockname (GNUNET_NETWORK_get_fd (listen_sock),
3789 (struct sockaddr *) &in_sto,
3790 &sto_len))
3791 {
3792 memcpy (&in_sto, addr, in_len);
3793 sto_len = in_len;
3794 }
3795
3796 // addr = (struct sockaddr *) &in_sto;
3797 in_len = sto_len;
3798 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3799 "Bound to `%s'\n",
3800 GNUNET_a2s ((const struct sockaddr *) &in_sto, sto_len));
3801 if (NULL == stats)
3802 stats = GNUNET_STATISTICS_create ("communicator-tcp", cfg);
3803
3804 if (NULL == is)
3805 is = GNUNET_NT_scanner_init ();
3806
3807 if (NULL == my_private_key)
3808 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
3809 if (NULL == my_private_key)
3810 {
3811 GNUNET_log (
3812 GNUNET_ERROR_TYPE_ERROR,
3813 _ (
3814 "Transport service is lacking key configuration settings. Exiting.\n"));
3815 if (NULL != resolve_request_handle)
3816 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3817 GNUNET_SCHEDULER_shutdown ();
3818 return GNUNET_SYSERR;
3819 }
3820 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
3821 /* start listening */
3822
3823 lt = GNUNET_new (struct ListenTask);
3824 lt->listen_sock = listen_sock;
3825
3826 lt->listen_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3827 listen_sock,
3828 &listen_cb,
3829 lt);
3830
3831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3832 "creating hash\n");
3833 sockfd = GNUNET_NETWORK_get_fd (lt->listen_sock);
3834 GNUNET_CRYPTO_hash (&sockfd,
3835 sizeof(int),
3836 &h_sock);
3837
3838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3839 "creating map\n");
3840 if (NULL == lt_map)
3841 lt_map = GNUNET_CONTAINER_multihashmap_create (2, GNUNET_NO);
3842
3843 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3844 "creating map entry\n");
3845 GNUNET_assert (GNUNET_OK ==
3846 GNUNET_CONTAINER_multihashmap_put (lt_map,
3847 &h_sock,
3848 lt,
3849 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
3850
3851 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3852 "map entry created\n");
3853
3854 if (NULL == queue_map)
3855 queue_map = GNUNET_CONTAINER_multihashmap_create (10, GNUNET_NO);
3856
3857 if (NULL == ch)
3858 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
3859 COMMUNICATOR_CONFIG_SECTION,
3860 COMMUNICATOR_ADDRESS_PREFIX,
3861 GNUNET_TRANSPORT_CC_RELIABLE,
3862 &mq_init,
3863 NULL,
3864 &enc_notify_cb,
3865 NULL);
3866
3867 if (NULL == ch)
3868 {
3869 GNUNET_break (0);
3870 if (NULL != resolve_request_handle)
3871 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3872 GNUNET_SCHEDULER_shutdown ();
3873 return GNUNET_SYSERR;
3874 }
3875
3876 add_addr (addr, in_len);
3877 return GNUNET_OK;
3878
3879}
3880
3881
3882/**
3883 * This method reads from the DLL addrs_head to register them at the NAT service.
3884 */
3885static void
3886nat_register ()
3887{
3888 struct sockaddr **saddrs;
3889 socklen_t *saddr_lens;
3890 int i;
3891 size_t len;
3892
3893 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3894 "starting nat register!\n");
3895 len = 0;
3896 i = 0;
3897 saddrs = GNUNET_malloc ((addrs_lens) * sizeof(struct sockaddr *));
3898 saddr_lens = GNUNET_malloc ((addrs_lens) * sizeof(socklen_t));
3899 for (struct Addresses *pos = addrs_head; NULL != pos; pos = pos->next)
3900 {
3901 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3902 "registering address %s\n",
3903 GNUNET_a2s (addrs_head->addr, addrs_head->addr_len));
3904
3905 saddr_lens[i] = addrs_head->addr_len;
3906 len += saddr_lens[i];
3907 saddrs[i] = GNUNET_memdup (addrs_head->addr, saddr_lens[i]);
3908 i++;
3909 }
3910
3911 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3912 "registering addresses %lu %lu %lu %lu\n",
3913 (addrs_lens) * sizeof(struct sockaddr *),
3914 (addrs_lens) * sizeof(socklen_t),
3915 len,
3916 sizeof(COMMUNICATOR_CONFIG_SECTION));
3917 nat = GNUNET_NAT_register (cfg,
3918 COMMUNICATOR_CONFIG_SECTION,
3919 IPPROTO_TCP,
3920 addrs_lens,
3921 (const struct sockaddr **) saddrs,
3922 saddr_lens,
3923 &nat_address_cb,
3924 try_connection_reversal,
3925 NULL /* closure */);
3926 for (i = addrs_lens - 1; i >= 0; i--)
3927 GNUNET_free (saddrs[i]);
3928 GNUNET_free (saddrs);
3929 GNUNET_free (saddr_lens);
3930
3931 if (NULL == nat)
3932 {
3933 GNUNET_break (0);
3934 if (NULL != resolve_request_handle)
3935 GNUNET_RESOLVER_request_cancel (resolve_request_handle);
3936 GNUNET_SCHEDULER_shutdown ();
3937 }
3938}
3939
3940
3941/**
3942 * This method is the callback called by the resolver API, and wraps method init_socket.
3943 *
3944 * @param cls The port we will bind to.
3945 * @param addr The address we will bind to.
3946 * @param in_len The length of the address we will bind to.
3947 */
3948static void
3949init_socket_resolv (void *cls,
3950 const struct sockaddr *addr,
3951 socklen_t in_len)
3952{
3953 struct sockaddr_in *v4;
3954 struct sockaddr_in6 *v6;
3955 struct sockaddr *in;
3956
3957 (void) cls;
3958 if (NULL != addr)
3959 {
3960 if (AF_INET == addr->sa_family)
3961 {
3962 v4 = (struct sockaddr_in *) addr;
3963 in = tcp_address_to_sockaddr_numeric_v4 (&in_len, *v4, bind_port);// _global);
3964 }
3965 else if (AF_INET6 == addr->sa_family)
3966 {
3967 v6 = (struct sockaddr_in6 *) addr;
3968 in = tcp_address_to_sockaddr_numeric_v6 (&in_len, *v6, bind_port);// _global);
3969 }
3970 else
3971 {
3972 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3973 "Address family %u not suitable (not AF_INET %u nor AF_INET6 %u \n",
3974 addr->sa_family,
3975 AF_INET,
3976 AF_INET6);
3977 return;
3978 }
3979 init_socket (in, in_len);
3980 }
3981 else
3982 {
3983 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3984 "Address is NULL. This might be an error or the resolver finished resolving.\n");
3985 if (NULL == addrs_head)
3986 {
3987 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
3988 "Resolver finished resolving, but we do not listen to an address!.\n");
3989 return;
3990 }
3991 nat_register ();
3992 }
3993}
3994
3995
3996/**
3997 * Setup communicator and launch network interactions.
3998 *
3999 * @param cls NULL (always)
4000 * @param args remaining command-line arguments
4001 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
4002 * @param c configuration
4003 */
4004static void
4005run (void *cls,
4006 char *const *args,
4007 const char *cfgfile,
4008 const struct GNUNET_CONFIGURATION_Handle *c)
4009{
4010 char *bindto;
4011 struct sockaddr *in;
4012 socklen_t in_len;
4013 struct sockaddr_in v4;
4014 struct sockaddr_in6 v6;
4015 char *start;
4016 unsigned int port;
4017 char dummy[2];
4018 char *rest = NULL;
4019 struct PortOnlyIpv4Ipv6 *po;
4020 socklen_t addr_len_ipv4;
4021 socklen_t addr_len_ipv6;
4022
4023 (void) cls;
4024
4025 pending_reversals = GNUNET_CONTAINER_multihashmap_create (16, GNUNET_NO);
4026 memset (&v4,0,sizeof(struct sockaddr_in));
4027 memset (&v6,0,sizeof(struct sockaddr_in6));
4028 cfg = c;
4029 if (GNUNET_OK !=
4030 GNUNET_CONFIGURATION_get_value_string (cfg,
4031 COMMUNICATOR_CONFIG_SECTION,
4032 "BINDTO",
4033 &bindto))
4034 {
4035 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
4036 COMMUNICATOR_CONFIG_SECTION,
4037 "BINDTO");
4038 return;
4039 }
4040 if (GNUNET_OK !=
4041 GNUNET_CONFIGURATION_get_value_number (cfg,
4042 COMMUNICATOR_CONFIG_SECTION,
4043 "MAX_QUEUE_LENGTH",
4044 &max_queue_length))
4045 {
4046 max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
4047 }
4048 if (GNUNET_OK !=
4049 GNUNET_CONFIGURATION_get_value_time (cfg,
4050 COMMUNICATOR_CONFIG_SECTION,
4051 "REKEY_INTERVAL",
4052 &rekey_interval))
4053 {
4054 rekey_interval = DEFAULT_REKEY_INTERVAL;
4055 }
4056 if (GNUNET_OK !=
4057 GNUNET_CONFIGURATION_get_value_number (cfg,
4058 COMMUNICATOR_CONFIG_SECTION,
4059 "REKEY_MAX_BYTES",
4060 &rekey_max_bytes))
4061 {
4062 rekey_max_bytes = REKEY_MAX_BYTES;
4063 }
4064 disable_v6 = GNUNET_NO;
4065 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
4066 (GNUNET_YES ==
4067 GNUNET_CONFIGURATION_get_value_yesno (cfg,
4068 COMMUNICATOR_CONFIG_SECTION,
4069 "DISABLE_V6")))
4070 {
4071 disable_v6 = GNUNET_YES;
4072 }
4073 peerstore = GNUNET_PEERSTORE_connect (cfg);
4074 if (NULL == peerstore)
4075 {
4076 GNUNET_free (bindto);
4077 GNUNET_break (0);
4078 GNUNET_SCHEDULER_shutdown ();
4079 return;
4080 }
4081
4082 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
4083
4084 if (1 == sscanf (bindto, "%u%1s", &bind_port, dummy))
4085 {
4086 po = tcp_address_to_sockaddr_port_only (bindto, &bind_port);
4087 addr_len_ipv4 = po->addr_len_ipv4;
4088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4089 "address po %s\n",
4090 GNUNET_a2s (po->addr_ipv4, addr_len_ipv4));
4091 if (NULL != po->addr_ipv4)
4092 {
4093 init_socket (po->addr_ipv4, addr_len_ipv4);
4094 }
4095 if (NULL != po->addr_ipv6)
4096 {
4097 addr_len_ipv6 = po->addr_len_ipv6;
4098 init_socket (po->addr_ipv6, addr_len_ipv6);
4099 }
4100 GNUNET_free (po);
4101 nat_register ();
4102 GNUNET_free (bindto);
4103 return;
4104 }
4105
4106 start = extract_address (bindto);
4107 // FIXME: check for NULL == start...
4108 if (1 == inet_pton (AF_INET, start, &v4.sin_addr))
4109 {
4110 bind_port = extract_port (bindto);
4111
4112 in = tcp_address_to_sockaddr_numeric_v4 (&in_len, v4, bind_port);
4113 init_socket (in, in_len);
4114 nat_register ();
4115 GNUNET_free (start);
4116 GNUNET_free (bindto);
4117 return;
4118 }
4119
4120 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
4121 {
4122 bind_port = extract_port (bindto);
4123 in = tcp_address_to_sockaddr_numeric_v6 (&in_len, v6, bind_port);
4124 init_socket (in, in_len);
4125 nat_register ();
4126 GNUNET_free (start);
4127 GNUNET_free (bindto);
4128 return;
4129 }
4130
4131 bind_port = extract_port (bindto);
4132 resolve_request_handle = GNUNET_RESOLVER_ip_get (strtok_r (bindto,
4133 ":",
4134 &rest),
4135 AF_UNSPEC,
4136 GNUNET_TIME_UNIT_MINUTES,
4137 &init_socket_resolv,
4138 &port);
4139
4140 GNUNET_free (bindto);
4141 GNUNET_free (start);
4142}
4143
4144
4145/**
4146 * The main function for the UNIX communicator.
4147 *
4148 * @param argc number of arguments from the command line
4149 * @param argv command line arguments
4150 * @return 0 ok, 1 on error
4151 */
4152int
4153main (int argc, char *const *argv)
4154{
4155 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
4156 GNUNET_GETOPT_OPTION_END
4157 };
4158 int ret;
4159
4160 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4161 "Starting tcp communicator\n");
4162 if (GNUNET_OK !=
4163 GNUNET_STRINGS_get_utf8_args (argc, argv,
4164 &argc, &argv))
4165 return 2;
4166
4167 ret = (GNUNET_OK ==
4168 GNUNET_PROGRAM_run (argc,
4169 argv,
4170 "gnunet-communicator-tcp",
4171 _ ("GNUnet TCP communicator"),
4172 options,
4173 &run,
4174 NULL))
4175 ? 0
4176 : 1;
4177 GNUNET_free_nz ((void *) argv);
4178 return ret;
4179}
4180
4181
4182/* end of gnunet-communicator-tcp.c */
diff --git a/src/service/transport/gnunet-communicator-udp.c b/src/service/transport/gnunet-communicator-udp.c
new file mode 100644
index 000000000..fa5294218
--- /dev/null
+++ b/src/service/transport/gnunet-communicator-udp.c
@@ -0,0 +1,3665 @@
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_common.h"
42#include "gnunet_util_lib.h"
43#include "gnunet_protocols.h"
44#include "gnunet_signatures.h"
45#include "gnunet_constants.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 64
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 96
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 256
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 * Representative of ephemeral key for KX.
202 */
203 struct GNUNET_CRYPTO_ElligatorRepresentative representative;
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 uint8_t gcm_tag[GCM_TAG_SIZE];
210
211};
212
213
214/**
215 * Encrypted continuation of UDP initial handshake, followed
216 * by message header with payload.
217 */
218struct UDPConfirmation
219{
220 /**
221 * Sender's identity
222 */
223 struct GNUNET_PeerIdentity sender;
224
225 /**
226 * Sender's signature of type #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE
227 */
228 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
229
230 /**
231 * Monotonic time of @e sender, to possibly help detect replay attacks
232 * (if receiver persists times by sender).
233 */
234 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
235
236 /* followed by messages */
237
238 /* padding may follow actual messages */
239};
240
241
242/**
243 * UDP key acknowledgement. May be sent via backchannel. Allows the
244 * sender to use `struct UDPBox` with the acknowledge key henceforth.
245 */
246struct UDPAck
247{
248 /**
249 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK.
250 */
251 struct GNUNET_MessageHeader header;
252
253 /**
254 * Sequence acknowledgement limit. Specifies current maximum sequence
255 * number supported by receiver.
256 */
257 uint32_t sequence_ack GNUNET_PACKED;
258
259 /**
260 * CMAC of the base key being acknowledged.
261 */
262 struct GNUNET_HashCode cmac;
263};
264
265
266/**
267 * Signature we use to verify that the broadcast was really made by
268 * the peer that claims to have made it. Basically, affirms that the
269 * peer is really using this IP address (albeit possibly not in _our_
270 * LAN). Makes it difficult for peers in the LAN to claim to
271 * be just any global peer -- an attacker must have at least
272 * shared a LAN with the peer they're pretending to be here.
273 */
274struct UdpBroadcastSignature
275{
276 /**
277 * Purpose must be #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST
278 */
279 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
280
281 /**
282 * Identity of the inititor of the UDP broadcast.
283 */
284 struct GNUNET_PeerIdentity sender;
285
286 /**
287 * Hash of the sender's UDP address.
288 */
289 struct GNUNET_HashCode h_address;
290};
291
292
293/**
294 * Broadcast by peer in LAN announcing its presence. Unusual in that
295 * we don't pad these to full MTU, as we cannot prevent being
296 * recognized in LAN as GNUnet peers if this feature is enabled
297 * anyway. Also, the entire message is in cleartext.
298 */
299struct UDPBroadcast
300{
301 /**
302 * Sender's peer identity.
303 */
304 struct GNUNET_PeerIdentity sender;
305
306 /**
307 * Sender's signature of type
308 * #GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST
309 */
310 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
311};
312
313
314/**
315 * UDP message box. Always sent encrypted, only allowed after
316 * the receiver sent a `struct UDPAck` for the base key!
317 */
318struct UDPBox
319{
320 /**
321 * Key and IV identification code. KDF applied to an acknowledged
322 * base key and a sequence number. Sequence numbers must be used
323 * monotonically increasing up to the maximum specified in
324 * `struct UDPAck`. Without further `struct UDPAck`s, the sender
325 * must fall back to sending handshakes!
326 */
327 struct GNUNET_ShortHashCode kid;
328
329 /**
330 * 128-bit authentication tag for the following encrypted message,
331 * from GCM. MAC starts at the @e body_start that follows and
332 * extends until the end of the UDP payload. If the @e hmac is
333 * wrong, the receiver should check if the message might be a
334 * `struct UdpHandshakeSignature`.
335 */
336 uint8_t gcm_tag[GCM_TAG_SIZE];
337
338};
339
340/**
341 * Plaintext of a rekey payload in a UDPBox.
342 */
343struct UDPRekey
344{
345 /**
346 * Type is #GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_REKEY.
347 */
348 struct GNUNET_MessageHeader header;
349
350 /**
351 * Ephemeral key to rekey with.
352 */
353 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral;
354};
355
356GNUNET_NETWORK_STRUCT_END
357
358/**
359 * Shared secret we generated for a particular sender or receiver.
360 */
361struct SharedSecret;
362
363
364/**
365 * Pre-generated "kid" code (key and IV identification code) to
366 * quickly derive master key for a `struct UDPBox`.
367 */
368struct KeyCacheEntry
369{
370 /**
371 * Kept in a DLL.
372 */
373 struct KeyCacheEntry *next;
374
375 /**
376 * Kept in a DLL.
377 */
378 struct KeyCacheEntry *prev;
379
380 /**
381 * Key and IV identification code. KDF applied to an acknowledged
382 * base key and a sequence number. Sequence numbers must be used
383 * monotonically increasing up to the maximum specified in
384 * `struct UDPAck`. Without further `struct UDPAck`s, the sender
385 * must fall back to sending handshakes!
386 */
387 struct GNUNET_ShortHashCode kid;
388
389 /**
390 * Corresponding shared secret.
391 */
392 struct SharedSecret *ss;
393
394 /**
395 * Sequence number used to derive this entry from master key.
396 */
397 uint32_t sequence_number;
398};
399
400
401/**
402 * Information we track per sender address we have recently been
403 * in contact with (decryption from sender).
404 */
405struct SenderAddress;
406
407/**
408 * Information we track per receiving address we have recently been
409 * in contact with (encryption to receiver).
410 */
411struct ReceiverAddress;
412
413/**
414 * Shared secret we generated for a particular sender or receiver.
415 */
416struct SharedSecret
417{
418 /**
419 * Kept in a DLL.
420 */
421 struct SharedSecret *next;
422
423 /**
424 * Kept in a DLL.
425 */
426 struct SharedSecret *prev;
427
428 /**
429 * Kept in a DLL, sorted by sequence number. Only if we are decrypting.
430 */
431 struct KeyCacheEntry *kce_head;
432
433 /**
434 * Kept in a DLL, sorted by sequence number. Only if we are decrypting.
435 */
436 struct KeyCacheEntry *kce_tail;
437
438 /**
439 * Sender we use this shared secret with, or NULL.
440 */
441 struct SenderAddress *sender;
442
443 /**
444 * Receiver we use this shared secret with, or NULL.
445 */
446 struct ReceiverAddress *receiver;
447
448 /**
449 * Master shared secret.
450 */
451 struct GNUNET_HashCode master;
452
453 /**
454 * CMAC is used to identify @e master in ACKs.
455 */
456 struct GNUNET_HashCode cmac;
457
458 /**
459 * Up to which sequence number did we use this @e master already?
460 * (for encrypting only)
461 */
462 uint32_t sequence_used;
463
464 /**
465 * Up to which sequence number did the other peer allow us to use
466 * this key, or up to which number did we allow the other peer to
467 * use this key?
468 */
469 uint32_t sequence_allowed;
470
471 /**
472 * Number of active KCN entries.
473 */
474 unsigned int active_kce_count;
475
476 /**
477 * Bytes sent with this shared secret
478 */
479 size_t bytes_sent;
480
481 /**
482 * rekey initiated for this secret?
483 */
484 int rekey_initiated;
485
486 /**
487 * Also precompute keys despite sufficient acks (for rekey)
488 */
489 int override_available_acks;
490};
491
492
493/**
494 * Information we track per sender address we have recently been
495 * in contact with (we decrypt messages from the sender).
496 */
497struct SenderAddress
498{
499 /**
500 * To whom are we talking to.
501 */
502 struct GNUNET_PeerIdentity target;
503
504 /**
505 * Entry in sender expiration heap.
506 */
507 struct GNUNET_CONTAINER_HeapNode *hn;
508
509 /**
510 * Shared secrets we used with @e target, first used is head.
511 */
512 struct SharedSecret *ss_head;
513
514 /**
515 * Shared secrets we used with @e target, last used is tail.
516 */
517 struct SharedSecret *ss_tail;
518
519 /**
520 * Address of the other peer.
521 */
522 struct sockaddr *address;
523
524 /**
525 * Length of the address.
526 */
527 socklen_t address_len;
528
529 /**
530 * The address key for this entry.
531 */
532 struct GNUNET_HashCode key;
533
534 /**
535 * Timeout for this sender.
536 */
537 struct GNUNET_TIME_Absolute timeout;
538
539 /**
540 * Length of the DLL at @a ss_head.
541 */
542 unsigned int num_secrets;
543
544 /**
545 * Number of BOX keys from ACKs we have currently
546 * available for this sender.
547 */
548 unsigned int acks_available;
549
550 /**
551 * Which network type does this queue use?
552 */
553 enum GNUNET_NetworkType nt;
554
555 /**
556 * sender_destroy already called on sender.
557 */
558 int sender_destroy_called;
559
560 /**
561 * ID of kce working queue task
562 */
563 struct GNUNET_SCHEDULER_Task *kce_task;
564
565 /**
566 * Is the kce_task finished?
567 */
568 int kce_task_finished;
569
570 /**
571 * When KCE finishes, send ACK if GNUNET_YES
572 */
573 int kce_send_ack_on_finish;
574};
575
576
577/**
578 * Information we track per receiving address we have recently been
579 * in contact with (encryption to receiver).
580 */
581struct ReceiverAddress
582{
583 /**
584 * Timeout for this receiver address.
585 */
586 struct GNUNET_TIME_Absolute rekey_timeout;
587
588 /**
589 * To whom are we talking to.
590 */
591 struct GNUNET_PeerIdentity target;
592
593 /**
594 * The address key for this entry.
595 */
596 struct GNUNET_HashCode key;
597
598 /**
599 * Shared secrets we received from @e target, first used is head.
600 */
601 struct SharedSecret *ss_head;
602
603 /**
604 * Shared secrets we received with @e target, last used is tail.
605 */
606 struct SharedSecret *ss_tail;
607
608 /**
609 * Address of the receiver in the human-readable format
610 * with the #COMMUNICATOR_ADDRESS_PREFIX.
611 */
612 char *foreign_addr;
613
614 /**
615 * Address of the other peer.
616 */
617 struct sockaddr *address;
618
619 /**
620 * Length of the address.
621 */
622 socklen_t address_len;
623
624 /**
625 * Entry in sender expiration heap.
626 */
627 struct GNUNET_CONTAINER_HeapNode *hn;
628
629 /**
630 * KX message queue we are providing for the #ch.
631 */
632 struct GNUNET_MQ_Handle *kx_mq;
633
634 /**
635 * Default message queue we are providing for the #ch.
636 */
637 struct GNUNET_MQ_Handle *d_mq;
638
639 /**
640 * handle for KX queue with the #ch.
641 */
642 struct GNUNET_TRANSPORT_QueueHandle *kx_qh;
643
644 /**
645 * handle for default queue with the #ch.
646 */
647 struct GNUNET_TRANSPORT_QueueHandle *d_qh;
648
649 /**
650 * Timeout for this receiver address.
651 */
652 struct GNUNET_TIME_Absolute timeout;
653
654 /**
655 * MTU we allowed transport for this receiver's KX queue.
656 */
657 size_t kx_mtu;
658
659 /**
660 * MTU we allowed transport for this receiver's default queue.
661 */
662 size_t d_mtu;
663
664 /**
665 * Length of the DLL at @a ss_head.
666 */
667 unsigned int num_secrets;
668
669 /**
670 * Number of BOX keys from ACKs we have currently
671 * available for this receiver.
672 */
673 unsigned int acks_available;
674
675 /**
676 * Which network type does this queue use?
677 */
678 enum GNUNET_NetworkType nt;
679
680 /**
681 * receiver_destroy already called on receiver.
682 */
683 int receiver_destroy_called;
684};
685
686/**
687 * Interface we broadcast our presence on.
688 */
689struct BroadcastInterface
690{
691 /**
692 * Kept in a DLL.
693 */
694 struct BroadcastInterface *next;
695
696 /**
697 * Kept in a DLL.
698 */
699 struct BroadcastInterface *prev;
700
701 /**
702 * Task for this broadcast interface.
703 */
704 struct GNUNET_SCHEDULER_Task *broadcast_task;
705
706 /**
707 * Sender's address of the interface.
708 */
709 struct sockaddr *sa;
710
711 /**
712 * Broadcast address to use on the interface.
713 */
714 struct sockaddr *ba;
715
716 /**
717 * Message we broadcast on this interface.
718 */
719 struct UDPBroadcast bcm;
720
721 /**
722 * If this is an IPv6 interface, this is the request
723 * we use to join/leave the group.
724 */
725 struct ipv6_mreq mcreq;
726
727 /**
728 * Number of bytes in @e sa.
729 */
730 socklen_t salen;
731
732 /**
733 * Was this interface found in the last #iface_proc() scan?
734 */
735 int found;
736};
737
738/**
739 * The rekey interval
740 */
741static struct GNUNET_TIME_Relative rekey_interval;
742
743/**
744 * How often we do rekey based on number of bytes transmitted
745 */
746static unsigned long long rekey_max_bytes;
747
748/**
749 * Cache of pre-generated key IDs.
750 */
751static struct GNUNET_CONTAINER_MultiShortmap *key_cache;
752
753/**
754 * ID of read task
755 */
756static struct GNUNET_SCHEDULER_Task *read_task;
757
758/**
759 * ID of timeout task
760 */
761static struct GNUNET_SCHEDULER_Task *timeout_task;
762
763/**
764 * ID of master broadcast task
765 */
766static struct GNUNET_SCHEDULER_Task *broadcast_task;
767
768/**
769 * For logging statistics.
770 */
771static struct GNUNET_STATISTICS_Handle *stats;
772
773/**
774 * Our environment.
775 */
776static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
777
778/**
779 * Receivers (map from peer identity to `struct ReceiverAddress`)
780 */
781static struct GNUNET_CONTAINER_MultiHashMap *receivers;
782
783/**
784 * Senders (map from peer identity to `struct SenderAddress`)
785 */
786static struct GNUNET_CONTAINER_MultiHashMap *senders;
787
788/**
789 * Expiration heap for senders (contains `struct SenderAddress`)
790 */
791static struct GNUNET_CONTAINER_Heap *senders_heap;
792
793/**
794 * Expiration heap for receivers (contains `struct ReceiverAddress`)
795 */
796static struct GNUNET_CONTAINER_Heap *receivers_heap;
797
798/**
799 * Broadcast interface tasks. Kept in a DLL.
800 */
801static struct BroadcastInterface *bi_head;
802
803/**
804 * Broadcast interface tasks. Kept in a DLL.
805 */
806static struct BroadcastInterface *bi_tail;
807
808/**
809 * Our socket.
810 */
811static struct GNUNET_NETWORK_Handle *udp_sock;
812
813/**
814 * #GNUNET_YES if #udp_sock supports IPv6.
815 */
816static int have_v6_socket;
817
818/**
819 * Our public key.
820 */
821static struct GNUNET_PeerIdentity my_identity;
822
823/**
824 * Our private key.
825 */
826static struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
827
828/**
829 * Our configuration.
830 */
831static const struct GNUNET_CONFIGURATION_Handle *cfg;
832
833/**
834 * Our handle to report addresses for validation to TRANSPORT.
835 */
836static struct GNUNET_TRANSPORT_ApplicationHandle *ah;
837
838/**
839 * Network scanner to determine network types.
840 */
841static struct GNUNET_NT_InterfaceScanner *is;
842
843/**
844 * Connection to NAT service.
845 */
846static struct GNUNET_NAT_Handle *nat;
847
848/**
849 * Port number to which we are actually bound.
850 */
851static uint16_t my_port;
852
853/**
854 * IPv6 disabled or not.
855 */
856static int disable_v6;
857
858
859/**
860 * An interface went away, stop broadcasting on it.
861 *
862 * @param bi entity to close down
863 */
864static void
865bi_destroy (struct BroadcastInterface *bi)
866{
867 if (AF_INET6 == bi->sa->sa_family)
868 {
869 /* Leave the multicast group */
870 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
871 IPPROTO_IPV6,
872 IPV6_LEAVE_GROUP,
873 &bi->mcreq,
874 sizeof(bi->mcreq)))
875 {
876 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
877 }
878 }
879 GNUNET_CONTAINER_DLL_remove (bi_head, bi_tail, bi);
880 GNUNET_SCHEDULER_cancel (bi->broadcast_task);
881 GNUNET_free (bi->sa);
882 GNUNET_free (bi->ba);
883 GNUNET_free (bi);
884}
885
886static int
887secret_destroy (struct SharedSecret *ss);
888
889/**
890 * Destroys a receiving state due to timeout or shutdown.
891 *
892 * @param receiver entity to close down
893 */
894static void
895receiver_destroy (struct ReceiverAddress *receiver)
896{
897 struct SharedSecret *ss;
898 receiver->receiver_destroy_called = GNUNET_YES;
899
900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
901 "Disconnecting receiver for peer `%s'\n",
902 GNUNET_i2s (&receiver->target));
903 if (NULL != receiver->kx_qh)
904 {
905 GNUNET_TRANSPORT_communicator_mq_del (receiver->kx_qh);
906 receiver->kx_qh = NULL;
907 receiver->kx_mq = NULL;
908 }
909 if (NULL != receiver->d_qh)
910 {
911 GNUNET_TRANSPORT_communicator_mq_del (receiver->d_qh);
912 receiver->d_qh = NULL;
913 }
914 else if (NULL != receiver->d_mq)
915 {
916 GNUNET_MQ_destroy (receiver->d_mq);
917 receiver->d_mq = NULL;
918 }
919 GNUNET_assert (GNUNET_YES ==
920 GNUNET_CONTAINER_multihashmap_remove (receivers,
921 &receiver->key,
922 receiver));
923 GNUNET_assert (receiver == GNUNET_CONTAINER_heap_remove_node (receiver->hn));
924 GNUNET_STATISTICS_set (stats,
925 "# receivers active",
926 GNUNET_CONTAINER_multihashmap_size (receivers),
927 GNUNET_NO);
928 while (NULL != (ss = receiver->ss_head))
929 {
930 secret_destroy (ss);
931 }
932 GNUNET_free (receiver->address);
933 GNUNET_free (receiver->foreign_addr);
934 GNUNET_free (receiver);
935}
936
937
938/**
939 * Free memory used by key cache entry.
940 *
941 * @param kce the key cache entry
942 */
943static void
944kce_destroy (struct KeyCacheEntry *kce)
945{
946 struct SharedSecret *ss = kce->ss;
947
948 ss->active_kce_count--;
949 GNUNET_CONTAINER_DLL_remove (ss->kce_head, ss->kce_tail, kce);
950 GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multishortmap_remove (key_cache,
951 &kce->kid,
952 kce));
953 GNUNET_free (kce);
954}
955
956
957/**
958 * Compute @a kid.
959 *
960 * @param msec master secret for HMAC calculation
961 * @param serial number for the @a smac calculation
962 * @param[out] kid where to write the key ID
963 */
964static void
965get_kid (const struct GNUNET_HashCode *msec,
966 uint32_t serial,
967 struct GNUNET_ShortHashCode *kid)
968{
969 uint32_t sid = htonl (serial);
970
971 GNUNET_CRYPTO_hkdf (kid,
972 sizeof(*kid),
973 GCRY_MD_SHA512,
974 GCRY_MD_SHA256,
975 &sid,
976 sizeof(sid),
977 msec,
978 sizeof(*msec),
979 "UDP-KID",
980 strlen ("UDP-KID"),
981 NULL,
982 0);
983}
984
985
986/**
987 * Setup key cache entry for sequence number @a seq and shared secret @a ss.
988 *
989 * @param ss shared secret
990 * @param seq sequence number for the key cache entry
991 */
992static void
993kce_generate (struct SharedSecret *ss, uint32_t seq)
994{
995 struct KeyCacheEntry *kce;
996
997 GNUNET_assert (0 < seq);
998 kce = GNUNET_new (struct KeyCacheEntry);
999 kce->ss = ss;
1000 kce->sequence_number = seq;
1001 get_kid (&ss->master, seq, &kce->kid);
1002 GNUNET_CONTAINER_DLL_insert (ss->kce_head, ss->kce_tail, kce);
1003 ss->active_kce_count++;
1004 ss->sender->acks_available++;
1005 (void) GNUNET_CONTAINER_multishortmap_put (
1006 key_cache,
1007 &kce->kid,
1008 kce,
1009 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1010 GNUNET_STATISTICS_set (stats,
1011 "# KIDs active",
1012 GNUNET_CONTAINER_multishortmap_size (key_cache),
1013 GNUNET_NO);
1014}
1015
1016
1017/**
1018 * Destroy @a ss and associated key cache entries.
1019 *
1020 * @param ss shared secret to destroy
1021 * @param withoutKce If GNUNET_YES shared secrets with kce will not be destroyed.
1022 */
1023static int
1024secret_destroy (struct SharedSecret *ss)
1025{
1026 struct SenderAddress *sender;
1027 struct ReceiverAddress *receiver;
1028 struct KeyCacheEntry *kce;
1029
1030 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1031 "secret %s destroy %u\n",
1032 GNUNET_h2s (&ss->master),
1033 ss->sequence_allowed);
1034 if (NULL != (sender = ss->sender))
1035 {
1036 GNUNET_CONTAINER_DLL_remove (sender->ss_head, sender->ss_tail, ss);
1037 sender->num_secrets--;
1038 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1039 "%u sender->num_secrets %u allowed %u used, %u available\n",
1040 sender->num_secrets, ss->sequence_allowed, ss->sequence_used,
1041 sender->acks_available);
1042 sender->acks_available -= (ss->sequence_allowed - ss->sequence_used);
1043 if (NULL != ss->sender->kce_task)
1044 {
1045 GNUNET_SCHEDULER_cancel (ss->sender->kce_task);
1046 ss->sender->kce_task = NULL;
1047 }
1048 }
1049 if (NULL != (receiver = ss->receiver))
1050 {
1051 GNUNET_CONTAINER_DLL_remove (receiver->ss_head, receiver->ss_tail, ss);
1052 receiver->num_secrets--;
1053 receiver->acks_available -= (ss->sequence_allowed - ss->sequence_used);
1054 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1055 "%u receiver->num_secrets\n",
1056 receiver->num_secrets);
1057 }
1058 while (NULL != (kce = ss->kce_head))
1059 kce_destroy (kce);
1060 GNUNET_STATISTICS_update (stats, "# Secrets active", -1, GNUNET_NO);
1061 GNUNET_STATISTICS_set (stats,
1062 "# KIDs active",
1063 GNUNET_CONTAINER_multishortmap_size (key_cache),
1064 GNUNET_NO);
1065 GNUNET_free (ss);
1066 return GNUNET_YES;
1067}
1068
1069
1070/**
1071 * Functions with this signature are called whenever we need
1072 * to close a sender's state due to timeout.
1073 *
1074 * @param sender entity to close down
1075 */
1076static void
1077sender_destroy (struct SenderAddress *sender)
1078{
1079 struct SharedSecret *ss;
1080 sender->sender_destroy_called = GNUNET_YES;
1081 GNUNET_assert (
1082 GNUNET_YES ==
1083 GNUNET_CONTAINER_multihashmap_remove (senders, &sender->key, sender));
1084 GNUNET_assert (sender == GNUNET_CONTAINER_heap_remove_node (sender->hn));
1085 GNUNET_STATISTICS_set (stats,
1086 "# senders active",
1087 GNUNET_CONTAINER_multihashmap_size (senders),
1088 GNUNET_NO);
1089 while (NULL != (ss = sender->ss_head))
1090 {
1091 secret_destroy (ss);
1092 }
1093 GNUNET_free (sender->address);
1094 GNUNET_free (sender);
1095}
1096
1097
1098/**
1099 * Compute @a key and @a iv.
1100 *
1101 * @param msec master secret for calculation
1102 * @param serial number for the @a smac calculation
1103 * @param[out] key where to write the decryption key
1104 * @param[out] iv where to write the IV
1105 */
1106static void
1107get_iv_key (const struct GNUNET_HashCode *msec,
1108 uint32_t serial,
1109 char key[AES_KEY_SIZE],
1110 char iv[AES_IV_SIZE])
1111{
1112 uint32_t sid = htonl (serial);
1113 char res[AES_KEY_SIZE + AES_IV_SIZE];
1114
1115 GNUNET_CRYPTO_hkdf (res,
1116 sizeof(res),
1117 GCRY_MD_SHA512,
1118 GCRY_MD_SHA256,
1119 &sid,
1120 sizeof(sid),
1121 msec,
1122 sizeof(*msec),
1123 "UDP-IV-KEY",
1124 strlen ("UDP-IV-KEY"),
1125 NULL,
1126 0);
1127 memcpy (key, res, AES_KEY_SIZE);
1128 memcpy (iv, &res[AES_KEY_SIZE], AES_IV_SIZE);
1129}
1130
1131
1132/**
1133 * Increment sender timeout due to activity.
1134 *
1135 * @param sender address for which the timeout should be rescheduled
1136 */
1137static void
1138reschedule_sender_timeout (struct SenderAddress *sender)
1139{
1140 sender->timeout =
1141 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1142 GNUNET_CONTAINER_heap_update_cost (sender->hn, sender->timeout.abs_value_us);
1143}
1144
1145
1146/**
1147 * Increment receiver timeout due to activity.
1148 *
1149 * @param receiver address for which the timeout should be rescheduled
1150 */
1151static void
1152reschedule_receiver_timeout (struct ReceiverAddress *receiver)
1153{
1154 receiver->timeout =
1155 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1156 GNUNET_CONTAINER_heap_update_cost (receiver->hn,
1157 receiver->timeout.abs_value_us);
1158}
1159
1160
1161/**
1162 * Task run to check #receiver_heap and #sender_heap for timeouts.
1163 *
1164 * @param cls unused, NULL
1165 */
1166static void
1167check_timeouts (void *cls)
1168{
1169 struct GNUNET_TIME_Relative st;
1170 struct GNUNET_TIME_Relative rt;
1171 struct GNUNET_TIME_Relative delay;
1172 struct ReceiverAddress *receiver;
1173 struct SenderAddress *sender;
1174
1175 (void) cls;
1176 timeout_task = NULL;
1177 rt = GNUNET_TIME_UNIT_FOREVER_REL;
1178 while (NULL != (receiver = GNUNET_CONTAINER_heap_peek (receivers_heap)))
1179 {
1180 rt = GNUNET_TIME_absolute_get_remaining (receiver->timeout);
1181 if (0 != rt.rel_value_us)
1182 break;
1183 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1184 "Receiver timed out\n");
1185 receiver_destroy (receiver);
1186 }
1187 st = GNUNET_TIME_UNIT_FOREVER_REL;
1188 while (NULL != (sender = GNUNET_CONTAINER_heap_peek (senders_heap)))
1189 {
1190 if (GNUNET_YES != sender->sender_destroy_called)
1191 {
1192 st = GNUNET_TIME_absolute_get_remaining (sender->timeout);
1193 if (0 != st.rel_value_us)
1194 break;
1195 sender_destroy (sender);
1196 }
1197 }
1198 delay = GNUNET_TIME_relative_min (rt, st);
1199 if (delay.rel_value_us < GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
1200 timeout_task = GNUNET_SCHEDULER_add_delayed (delay, &check_timeouts, NULL);
1201}
1202
1203
1204/**
1205 * Calculate cmac from master in @a ss.
1206 *
1207 * @param[in,out] ss data structure to complete
1208 */
1209static void
1210calculate_cmac (struct SharedSecret *ss)
1211{
1212 GNUNET_CRYPTO_hkdf (&ss->cmac,
1213 sizeof(ss->cmac),
1214 GCRY_MD_SHA512,
1215 GCRY_MD_SHA256,
1216 "CMAC",
1217 strlen ("CMAC"),
1218 &ss->master,
1219 sizeof(ss->master),
1220 "UDP-CMAC",
1221 strlen ("UDP-CMAC"),
1222 NULL,
1223 0);
1224}
1225
1226
1227/**
1228 * We received @a plaintext_len bytes of @a plaintext from a @a sender.
1229 * Pass it on to CORE.
1230 *
1231 * @param queue the queue that received the plaintext
1232 * @param plaintext the plaintext that was received
1233 * @param plaintext_len number of bytes of plaintext received
1234 */
1235static void
1236pass_plaintext_to_core (struct SenderAddress *sender,
1237 const void *plaintext,
1238 size_t plaintext_len)
1239{
1240 const struct GNUNET_MessageHeader *hdr = plaintext;
1241 const char *pos = plaintext;
1242
1243 while (ntohs (hdr->size) <= plaintext_len)
1244 {
1245 GNUNET_STATISTICS_update (stats,
1246 "# bytes given to core",
1247 ntohs (hdr->size),
1248 GNUNET_NO);
1249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1250 "Giving %u bytes to TNG\n", ntohs (hdr->size));
1251 GNUNET_assert (GNUNET_SYSERR !=
1252 GNUNET_TRANSPORT_communicator_receive (ch,
1253 &sender->target,
1254 hdr,
1255 ADDRESS_VALIDITY_PERIOD,
1256 NULL /* no flow control possible */
1257 ,
1258 NULL));
1259 /* move on to next message, if any */
1260 plaintext_len -= ntohs (hdr->size);
1261 if (plaintext_len < sizeof(*hdr))
1262 break;
1263 pos += ntohs (hdr->size);
1264 hdr = (const struct GNUNET_MessageHeader *) pos;
1265 // TODO for now..., we do not actually sen >1msg or have a way of telling
1266 // if we are done
1267 break;
1268 }
1269 GNUNET_STATISTICS_update (stats,
1270 "# bytes padding discarded",
1271 plaintext_len,
1272 GNUNET_NO);
1273}
1274
1275
1276/**
1277 * Setup @a cipher based on shared secret @a msec and
1278 * serial number @a serial.
1279 *
1280 * @param msec master shared secret
1281 * @param serial serial number of cipher to set up
1282 * @param cipher[out] cipher to initialize
1283 */
1284static void
1285setup_cipher (const struct GNUNET_HashCode *msec,
1286 uint32_t serial,
1287 gcry_cipher_hd_t *cipher)
1288{
1289 char key[AES_KEY_SIZE];
1290 char iv[AES_IV_SIZE];
1291 int rc;
1292
1293 GNUNET_assert (0 ==
1294 gcry_cipher_open (cipher,
1295 GCRY_CIPHER_AES256 /* low level: go for speed */
1296 ,
1297 GCRY_CIPHER_MODE_GCM,
1298 0 /* flags */));
1299 get_iv_key (msec, serial, key, iv);
1300 rc = gcry_cipher_setkey (*cipher, key, sizeof(key));
1301 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
1302 rc = gcry_cipher_setiv (*cipher, iv, sizeof(iv));
1303 GNUNET_assert ((0 == rc) || ((char) rc == GPG_ERR_WEAK_KEY));
1304}
1305
1306
1307/**
1308 * Try to decrypt @a buf using shared secret @a ss and key/iv
1309 * derived using @a serial.
1310 *
1311 * @param ss shared secret
1312 * @param tag GCM authentication tag
1313 * @param serial serial number to use
1314 * @param in_buf input buffer to decrypt
1315 * @param in_buf_size number of bytes in @a in_buf and available in @a out_buf
1316 * @param out_buf where to write the result
1317 * @return #GNUNET_OK on success
1318 */
1319static int
1320try_decrypt (const struct SharedSecret *ss,
1321 const uint8_t *tag,
1322 uint32_t serial,
1323 const char *in_buf,
1324 size_t in_buf_size,
1325 char *out_buf)
1326{
1327 gcry_cipher_hd_t cipher;
1328
1329 setup_cipher (&ss->master, serial, &cipher);
1330 GNUNET_assert (
1331 0 ==
1332 gcry_cipher_decrypt (cipher, out_buf, in_buf_size, in_buf, in_buf_size));
1333 if (0 != gcry_cipher_checktag (cipher, tag, GCM_TAG_SIZE))
1334 {
1335 gcry_cipher_close (cipher);
1336 GNUNET_STATISTICS_update (stats,
1337 "# AEAD authentication failures",
1338 1,
1339 GNUNET_NO);
1340 return GNUNET_SYSERR;
1341 }
1342 gcry_cipher_close (cipher);
1343 return GNUNET_OK;
1344}
1345
1346
1347/**
1348 * Setup shared secret for decryption.
1349 *
1350 * @param ephemeral ephemeral key we received from the other peer
1351 * @return new shared secret
1352 */
1353static struct SharedSecret *
1354setup_shared_secret_dec (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral)
1355{
1356 struct SharedSecret *ss;
1357
1358 ss = GNUNET_new (struct SharedSecret);
1359 GNUNET_CRYPTO_eddsa_kem_decaps (my_private_key, ephemeral, &ss->master);
1360 calculate_cmac (ss);
1361 return ss;
1362}
1363
1364
1365/**
1366 * Setup shared secret for decryption for initial handshake.
1367 *
1368 * @param representative of ephemeral key we received from the other peer
1369 * @return new shared secret
1370 */
1371static struct SharedSecret *
1372setup_initial_shared_secret_dec (const struct
1373 GNUNET_CRYPTO_ElligatorRepresentative *
1374 representative)
1375{
1376 struct SharedSecret *ss;
1377
1378 ss = GNUNET_new (struct SharedSecret);
1379 GNUNET_CRYPTO_eddsa_elligator_kem_decaps (my_private_key, representative,
1380 &ss->master);
1381 calculate_cmac (ss);
1382 return ss;
1383}
1384
1385
1386/**
1387 * Setup new shared secret for encryption using KEM.
1388 *
1389 * @param[out] ephemeral ephemeral key to be sent to other peer (encapsulated key from KEM)
1390 * @param[in,out] receiver queue to initialize encryption key for
1391 * @return new shared secret
1392 */
1393static struct SharedSecret *
1394setup_shared_secret_ephemeral (struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
1395 struct ReceiverAddress *receiver)
1396{
1397 struct SharedSecret *ss;
1398 struct GNUNET_HashCode k;
1399
1400 GNUNET_CRYPTO_eddsa_kem_encaps (&receiver->target.public_key, ephemeral, &k);
1401 ss = GNUNET_new (struct SharedSecret);
1402 memcpy (&ss->master, &k, sizeof (k));
1403 calculate_cmac (ss);
1404 ss->receiver = receiver;
1405 GNUNET_CONTAINER_DLL_insert (receiver->ss_head, receiver->ss_tail, ss);
1406 receiver->num_secrets++;
1407 GNUNET_STATISTICS_update (stats, "# Secrets active", 1, GNUNET_NO);
1408 return ss;
1409}
1410
1411
1412/**
1413 * Setup new shared secret for encryption using KEM for initial handshake.
1414 *
1415 * @param[out] representative of ephemeral key to be sent to other peer (encapsulated key from KEM)
1416 * @param[in,out] receiver queue to initialize encryption key for
1417 * @return new shared secret
1418 */
1419static struct SharedSecret *
1420setup_initial_shared_secret_ephemeral (struct
1421 GNUNET_CRYPTO_ElligatorRepresentative *
1422 representative,
1423 struct ReceiverAddress *receiver)
1424{
1425 struct SharedSecret *ss;
1426 struct GNUNET_HashCode k;
1427
1428 GNUNET_CRYPTO_eddsa_elligator_kem_encaps (&receiver->target.public_key,
1429 representative, &k);
1430 ss = GNUNET_new (struct SharedSecret);
1431 memcpy (&ss->master, &k, sizeof (k));
1432 calculate_cmac (ss);
1433 ss->receiver = receiver;
1434 GNUNET_CONTAINER_DLL_insert (receiver->ss_head, receiver->ss_tail, ss);
1435 receiver->num_secrets++;
1436 GNUNET_STATISTICS_update (stats, "# Secrets active", 1, GNUNET_NO);
1437 return ss;
1438}
1439
1440
1441/**
1442 * Setup the MQ for the @a receiver. If a queue exists,
1443 * the existing one is destroyed. Then the MTU is
1444 * recalculated and a fresh queue is initialized.
1445 *
1446 * @param receiver receiver to setup MQ for
1447 */
1448static void
1449setup_receiver_mq (struct ReceiverAddress *receiver);
1450
1451
1452/**
1453 * Best effort try to purge some secrets.
1454 * Ideally those, not ACKed.
1455 *
1456 * @param ss_list_tail the oldest secret in the list of interest.
1457 * @return number of deleted secrets.
1458 */
1459unsigned int
1460purge_secrets (struct SharedSecret *ss_list_tail)
1461{
1462 struct SharedSecret *pos;
1463 struct SharedSecret *ss_to_purge;
1464 unsigned int deleted = 0;
1465
1466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1467 "Purging secrets.\n");
1468 pos = ss_list_tail;
1469 while (NULL != pos)
1470 {
1471 ss_to_purge = pos;
1472 pos = pos->prev;
1473
1474 // FIXME we may also want to purge old unacked.
1475 if (rekey_max_bytes <= ss_to_purge->bytes_sent)
1476 {
1477 secret_destroy (ss_to_purge);
1478 deleted++;
1479 }
1480 }
1481 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1482 "Finished purging all, deleted %u.\n", deleted);
1483 return deleted;
1484}
1485
1486
1487static void
1488add_acks (struct SharedSecret *ss, int acks_to_add)
1489{
1490
1491 struct ReceiverAddress *receiver = ss->receiver;
1492
1493 GNUNET_assert (NULL != ss);
1494 GNUNET_assert (NULL != receiver);
1495
1496 if (NULL == receiver->d_qh)
1497 {
1498 receiver->d_qh =
1499 GNUNET_TRANSPORT_communicator_mq_add (ch,
1500 &receiver->target,
1501 receiver->foreign_addr,
1502 receiver->d_mtu,
1503 acks_to_add,
1504 1, /* Priority */
1505 receiver->nt,
1506 GNUNET_TRANSPORT_CS_OUTBOUND,
1507 receiver->d_mq);
1508 }
1509 else
1510 {
1511 GNUNET_TRANSPORT_communicator_mq_update (ch,
1512 receiver->d_qh,
1513 acks_to_add,
1514 1);
1515 }
1516
1517 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1518 "Tell transport we have %u more acks!\n",
1519 acks_to_add);
1520
1521 // Until here for alternativ 1
1522
1523 /* move ss to head to avoid discarding it anytime soon! */
1524
1525 // GNUNET_CONTAINER_DLL_remove (receiver->ss_head, receiver->ss_tail, ss);
1526 // GNUNET_CONTAINER_DLL_insert (receiver->ss_head, receiver->ss_tail, ss);
1527}
1528
1529
1530/**
1531 * We received an ACK for @a pid. Check if it is for
1532 * the receiver in @a value and if so, handle it and
1533 * return #GNUNET_NO. Otherwise, return #GNUNET_YES.
1534 *
1535 * @param cls a `const struct UDPAck`
1536 * @param pid peer the ACK is from
1537 * @param value a `struct ReceiverAddress`
1538 * @return #GNUNET_YES to continue to iterate
1539 */
1540static int
1541handle_ack (void *cls, const struct GNUNET_HashCode *key, void *value)
1542{
1543 const struct UDPAck *ack = cls;
1544 struct ReceiverAddress *receiver = value;
1545 uint32_t acks_to_add;
1546 uint32_t allowed;
1547
1548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1549 "in handle ack with cmac %s\n",
1550 GNUNET_h2s (&ack->cmac));
1551
1552 (void) key;
1553 for (struct SharedSecret *ss = receiver->ss_head; NULL != ss; ss = ss->next)
1554 {
1555 if (0 == memcmp (&ack->cmac, &ss->cmac, sizeof(struct GNUNET_HashCode)))
1556 {
1557
1558 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1559 "Found matching cmac\n");
1560
1561 allowed = ntohl (ack->sequence_ack);
1562
1563 if (allowed <= ss->sequence_allowed)
1564 {
1565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1566 "Ignoring ack, not giving us increased window\n.");
1567 return GNUNET_NO;
1568 }
1569 acks_to_add = (allowed - ss->sequence_allowed);
1570 GNUNET_assert (0 != acks_to_add);
1571 receiver->acks_available += (allowed - ss->sequence_allowed);
1572 ss->sequence_allowed = allowed;
1573 add_acks (ss, acks_to_add);
1574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1575 "New sequence allows until %u (+%u). Acks available to us: %u. For secret %s\n",
1576 allowed,
1577 acks_to_add,
1578 receiver->acks_available,
1579 GNUNET_h2s (&ss->master));
1580 return GNUNET_NO;
1581 }
1582 }
1583 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1584 "Matching cmac not found for ack!\n");
1585 return GNUNET_YES;
1586}
1587
1588
1589/**
1590 * We established a shared secret with a sender. We should try to send
1591 * the sender an `struct UDPAck` at the next opportunity to allow the
1592 * sender to use @a ss longer (assuming we did not yet already
1593 * recently).
1594 *
1595 * @param ss shared secret to generate ACKs for
1596 */
1597static void
1598consider_ss_ack (struct SharedSecret *ss)
1599{
1600 struct UDPAck ack;
1601 GNUNET_assert (NULL != ss->sender);
1602 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1603 "Considering SS UDPAck %s\n",
1604 GNUNET_i2s_full (&ss->sender->target));
1605
1606 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1607 "Sender has %u acks available.\n",
1608 ss->sender->acks_available);
1609 /* drop ancient KeyCacheEntries */
1610 while ((NULL != ss->kce_head) &&
1611 (MAX_SQN_DELTA <
1612 ss->kce_head->sequence_number - ss->kce_tail->sequence_number))
1613 kce_destroy (ss->kce_tail);
1614
1615
1616 ack.header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK);
1617 ack.header.size = htons (sizeof(ack));
1618 ack.sequence_ack = htonl (ss->sequence_allowed);
1619 ack.cmac = ss->cmac;
1620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1621 "Notifying transport with UDPAck %s, sequence %u and master %s\n",
1622 GNUNET_i2s_full (&ss->sender->target),
1623 ss->sequence_allowed,
1624 GNUNET_h2s (&(ss->master)));
1625 GNUNET_TRANSPORT_communicator_notify (ch,
1626 &ss->sender->target,
1627 COMMUNICATOR_ADDRESS_PREFIX,
1628 &ack.header);
1629}
1630
1631
1632static void
1633kce_generate_cb (void *cls)
1634{
1635 struct SharedSecret *ss = cls;
1636 ss->sender->kce_task = NULL;
1637
1638 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1639 "Precomputing %u keys for master %s\n",
1640 GENERATE_AT_ONCE,
1641 GNUNET_h2s (&(ss->master)));
1642 if ((ss->override_available_acks != GNUNET_YES) &&
1643 (KCN_TARGET < ss->sender->acks_available))
1644 return;
1645 for (int i = 0; i < GENERATE_AT_ONCE; i++)
1646 kce_generate (ss, ++ss->sequence_allowed);
1647
1648 /**
1649 * As long as we loose over 30% of max acks in reschedule,
1650 * We keep generating acks for this ss.
1651 */
1652 if (KCN_TARGET > ss->sender->acks_available)
1653 {
1654 ss->sender->kce_task = GNUNET_SCHEDULER_add_delayed (
1655 WORKING_QUEUE_INTERVALL,
1656 kce_generate_cb,
1657 ss);
1658 return;
1659 }
1660 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1661 "We have enough keys (ACKs: %u).\n", ss->sender->acks_available);
1662 ss->sender->kce_task_finished = GNUNET_YES;
1663 ss->override_available_acks = GNUNET_NO;
1664 if (ss->sender->kce_send_ack_on_finish == GNUNET_YES)
1665 consider_ss_ack (ss);
1666}
1667
1668
1669/**
1670 * Test if we have received a valid message in plaintext.
1671 * If so, handle it.
1672 *
1673 * @param sender peer to process inbound plaintext for
1674 * @param buf buffer we received
1675 * @param buf_size number of bytes in @a buf
1676 */
1677static void
1678try_handle_plaintext (struct SenderAddress *sender,
1679 const void *buf,
1680 size_t buf_size)
1681{
1682 const struct GNUNET_MessageHeader *hdr;
1683 const struct UDPAck *ack;
1684 const struct UDPRekey *rekey;
1685 struct SharedSecret *ss_rekey;
1686 const char *buf_pos = buf;
1687 size_t bytes_remaining = buf_size;
1688 uint16_t type;
1689
1690 hdr = (struct GNUNET_MessageHeader*) buf_pos;
1691 if (sizeof(*hdr) > bytes_remaining)
1692 {
1693 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Plaintext too short, dropping...\n");
1694 return; /* no data left */
1695 }
1696 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1697 "try_handle_plaintext of size %llu (%u %lu) and type %u\n",
1698 (unsigned long long) bytes_remaining,
1699 ntohs (hdr->size),
1700 sizeof(*hdr),
1701 ntohs (hdr->type));
1702 if (ntohs (hdr->size) > bytes_remaining)
1703 return; /* buffer too short for indicated message length */
1704 type = ntohs (hdr->type);
1705 switch (type)
1706 {
1707 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_REKEY:
1708 rekey = (struct UDPRekey*) buf_pos;
1709 ss_rekey = setup_shared_secret_dec (&rekey->ephemeral);
1710 ss_rekey->sender = sender;
1711 GNUNET_CONTAINER_DLL_insert (sender->ss_head, sender->ss_tail, ss_rekey);
1712 sender->num_secrets++;
1713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1714 "Received rekey secret with cmac %s\n",
1715 GNUNET_h2s (&(ss_rekey->cmac)));
1716 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1717 "Received secret with master %s.\n",
1718 GNUNET_h2s (&(ss_rekey->master)));
1719 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1720 "We have %u sequence_allowed.\n",
1721 ss_rekey->sequence_allowed);
1722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1723 "We have a sender %p\n",
1724 ss_rekey->sender);
1725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1726 "We have %u acks available.\n",
1727 ss_rekey->sender->acks_available);
1728 GNUNET_STATISTICS_update (stats,
1729 "# rekeying successful",
1730 1,
1731 GNUNET_NO);
1732 ss_rekey->sender->kce_send_ack_on_finish = GNUNET_YES;
1733 ss_rekey->override_available_acks = GNUNET_YES;
1734 // FIXME
1735 kce_generate_cb (ss_rekey);
1736 /* ss_rekey->sender->kce_task = GNUNET_SCHEDULER_add_delayed (
1737 WORKING_QUEUE_INTERVALL,
1738 kce_generate_cb,
1739 ss_rekey);*/
1740 // FIXME: Theoretically, this could be an Ack
1741 buf_pos += ntohs (hdr->size);
1742 bytes_remaining -= ntohs (hdr->size);
1743 pass_plaintext_to_core (sender, buf_pos, bytes_remaining);
1744 if (0 == purge_secrets (sender->ss_tail))
1745 {
1746 // No secret purged. Delete oldest.
1747 if (sender->num_secrets > MAX_SECRETS)
1748 {
1749 secret_destroy (sender->ss_tail);
1750 }
1751 }
1752 break;
1753 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK:
1754 /* lookup master secret by 'cmac', then update sequence_max */
1755 ack = (struct UDPAck*) buf_pos;
1756 GNUNET_CONTAINER_multihashmap_get_multiple (receivers,
1757 &sender->key,
1758 &handle_ack,
1759 (void *) ack);
1760 /* There could be more messages after the ACK, handle those as well */
1761 buf_pos += ntohs (hdr->size);
1762 bytes_remaining -= ntohs (hdr->size);
1763 pass_plaintext_to_core (sender, buf_pos, bytes_remaining);
1764 break;
1765
1766 case GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD:
1767 /* skip padding */
1768 break;
1769
1770 default:
1771 pass_plaintext_to_core (sender, buf_pos, bytes_remaining);
1772 }
1773 return;
1774}
1775
1776
1777/**
1778 * We received a @a box with matching @a kce. Decrypt and process it.
1779 *
1780 * @param box the data we received
1781 * @param box_len number of bytes in @a box
1782 * @param kce key index to decrypt @a box
1783 */
1784static void
1785decrypt_box (const struct UDPBox *box,
1786 size_t box_len,
1787 struct KeyCacheEntry *kce)
1788{
1789 struct SharedSecret *ss = kce->ss;
1790 struct SharedSecret *ss_c = ss->sender->ss_tail;
1791 struct SharedSecret *ss_tmp;
1792 int ss_destroyed = 0;
1793 char out_buf[box_len - sizeof(*box)];
1794
1795 GNUNET_assert (NULL != ss->sender);
1796 if (GNUNET_OK != try_decrypt (ss,
1797 box->gcm_tag,
1798 kce->sequence_number,
1799 (const char *) &box[1],
1800 sizeof(out_buf),
1801 out_buf))
1802 {
1803 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Failed decryption.\n");
1804 GNUNET_STATISTICS_update (stats,
1805 "# Decryption failures with valid KCE",
1806 1,
1807 GNUNET_NO);
1808 kce_destroy (kce);
1809 ss->sender->acks_available--;
1810 return;
1811 }
1812 kce_destroy (kce);
1813 kce = NULL;
1814 ss->bytes_sent += box_len;
1815 ss->sender->acks_available--;
1816 ss->sequence_used++;
1817 GNUNET_STATISTICS_update (stats,
1818 "# bytes decrypted with BOX",
1819 sizeof(out_buf),
1820 GNUNET_NO);
1821 GNUNET_STATISTICS_update (stats,
1822 "# messages decrypted with BOX",
1823 1,
1824 GNUNET_NO);
1825 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1826 "decrypted UDPBox with kid %s\n",
1827 GNUNET_sh2s (&box->kid));
1828 try_handle_plaintext (ss->sender, out_buf, sizeof(out_buf));
1829
1830 while (NULL != ss_c)
1831 {
1832 if (ss_c->bytes_sent >= rekey_max_bytes)
1833 {
1834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1835 "Removing SS because rekey bytes reached.\n");
1836 ss_tmp = ss_c->prev;
1837 if (ss == ss_c)
1838 ss_destroyed = 1;
1839 secret_destroy (ss_c);
1840 ss_c = ss_tmp;
1841 continue;
1842 }
1843 ss_c = ss_c->prev;
1844 }
1845 if (1 == ss_destroyed)
1846 return;
1847 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1848 "Sender has %u ack left.\n",
1849 ss->sender->acks_available);
1850 if ((KCN_THRESHOLD > ss->sender->acks_available) &&
1851 (NULL == ss->sender->kce_task) &&
1852 (GNUNET_YES == ss->sender->kce_task_finished))
1853 {
1854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1855 "Sender has %u ack left which is under threshold.\n",
1856 ss->sender->acks_available);
1857 ss->sender->kce_send_ack_on_finish = GNUNET_YES;
1858 ss->sender->kce_task = GNUNET_SCHEDULER_add_now (
1859 kce_generate_cb,
1860 ss);
1861 }
1862}
1863
1864
1865/**
1866 * Closure for #find_sender_by_address()
1867 */
1868struct SearchContext
1869{
1870 /**
1871 * Address we are looking for.
1872 */
1873 const struct sockaddr *address;
1874
1875 /**
1876 * Number of bytes in @e address.
1877 */
1878 socklen_t address_len;
1879
1880 /**
1881 * Return value to set if we found a match.
1882 */
1883 struct SenderAddress *sender;
1884};
1885
1886
1887/**
1888 * Create sender address for @a target. Note that we
1889 * might already have one, so a fresh one is only allocated
1890 * if one does not yet exist for @a address.
1891 *
1892 * @param target peer to generate address for
1893 * @param address target address
1894 * @param address_len number of bytes in @a address
1895 * @return data structure to keep track of key material for
1896 * decrypting data from @a target
1897 */
1898static struct SenderAddress *
1899setup_sender (const struct GNUNET_PeerIdentity *target,
1900 const struct sockaddr *address,
1901 socklen_t address_len)
1902{
1903 struct SenderAddress *sender;
1904 struct GNUNET_HashContext *hsh;
1905 struct GNUNET_HashCode sender_key;
1906
1907 hsh = GNUNET_CRYPTO_hash_context_start ();
1908 GNUNET_CRYPTO_hash_context_read (hsh, address, address_len);
1909 GNUNET_CRYPTO_hash_context_read (hsh, target, sizeof(*target));
1910 GNUNET_CRYPTO_hash_context_finish (hsh, &sender_key);
1911
1912 sender = GNUNET_CONTAINER_multihashmap_get (senders, &sender_key);
1913 if (NULL != sender)
1914 {
1915 reschedule_sender_timeout (sender);
1916 return sender;
1917 }
1918 sender = GNUNET_new (struct SenderAddress);
1919 sender->key = sender_key;
1920 sender->target = *target;
1921 sender->address = GNUNET_memdup (address, address_len);
1922 sender->address_len = address_len;
1923 (void) GNUNET_CONTAINER_multihashmap_put (
1924 senders,
1925 &sender->key,
1926 sender,
1927 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
1928 GNUNET_STATISTICS_set (stats,
1929 "# senders active",
1930 GNUNET_CONTAINER_multihashmap_size (receivers),
1931 GNUNET_NO);
1932 sender->timeout =
1933 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
1934 sender->hn = GNUNET_CONTAINER_heap_insert (senders_heap,
1935 sender,
1936 sender->timeout.abs_value_us);
1937 sender->nt = GNUNET_NT_scanner_get_type (is, address, address_len);
1938 if (NULL == timeout_task)
1939 timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL);
1940 return sender;
1941}
1942
1943
1944/**
1945 * Check signature from @a uc against @a ephemeral.
1946 *
1947 * @param ephemeral key that is signed
1948 * @param uc signature of claimant
1949 * @return #GNUNET_OK if signature is valid
1950 */
1951static int
1952verify_confirmation (const struct GNUNET_CRYPTO_EcdhePublicKey *ephemeral,
1953 const struct UDPConfirmation *uc)
1954{
1955 struct UdpHandshakeSignature uhs;
1956
1957 uhs.purpose.purpose = htonl (
1958 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE);
1959 uhs.purpose.size = htonl (sizeof(uhs));
1960 uhs.sender = uc->sender;
1961 uhs.receiver = my_identity;
1962 uhs.ephemeral = *ephemeral;
1963 uhs.monotonic_time = uc->monotonic_time;
1964 return GNUNET_CRYPTO_eddsa_verify (
1965 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE,
1966 &uhs,
1967 &uc->sender_sig,
1968 &uc->sender.public_key);
1969}
1970
1971
1972/**
1973 * Converts @a address to the address string format used by this
1974 * communicator in HELLOs.
1975 *
1976 * @param address the address to convert, must be AF_INET or AF_INET6.
1977 * @param address_len number of bytes in @a address
1978 * @return string representation of @a address
1979 */
1980static char *
1981sockaddr_to_udpaddr_string (const struct sockaddr *address,
1982 socklen_t address_len)
1983{
1984 char *ret;
1985
1986 switch (address->sa_family)
1987 {
1988 case AF_INET:
1989 GNUNET_asprintf (&ret,
1990 "%s-%s",
1991 COMMUNICATOR_ADDRESS_PREFIX,
1992 GNUNET_a2s (address, address_len));
1993 break;
1994
1995 case AF_INET6:
1996 GNUNET_asprintf (&ret,
1997 "%s-%s",
1998 COMMUNICATOR_ADDRESS_PREFIX,
1999 GNUNET_a2s (address, address_len));
2000 break;
2001
2002 default:
2003 GNUNET_assert (0);
2004 }
2005 return ret;
2006}
2007
2008
2009/**
2010 * Socket read task.
2011 *
2012 * @param cls NULL
2013 */
2014static void
2015sock_read (void *cls)
2016{
2017 struct sockaddr_storage sa;
2018 struct sockaddr_in *addr_verify;
2019 socklen_t salen = sizeof(sa);
2020 char buf[UINT16_MAX];
2021 ssize_t rcvd;
2022
2023 (void) cls;
2024 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
2025 udp_sock,
2026 &sock_read,
2027 NULL);
2028 while (1)
2029 {
2030 rcvd = GNUNET_NETWORK_socket_recvfrom (udp_sock,
2031 buf,
2032 sizeof(buf),
2033 (struct sockaddr *) &sa,
2034 &salen);
2035 if (-1 == rcvd)
2036 {
2037 struct sockaddr *addr = (struct sockaddr*) &sa;
2038
2039 if (EAGAIN == errno)
2040 break; // We are done reading data
2041 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2042 "Failed to recv from %s family %d failed sock %p\n",
2043 GNUNET_a2s ((struct sockaddr*) &sa,
2044 sizeof (*addr)),
2045 addr->sa_family,
2046 udp_sock);
2047 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "recv");
2048 return;
2049 }
2050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2051 "Read %llu bytes\n",
2052 (unsigned long long) rcvd);
2053 if (0 == rcvd)
2054 {
2055 GNUNET_break_op (0);
2056 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2057 "Read 0 bytes from UDP socket\n");
2058 return;
2059 }
2060
2061 /* first, see if it is a UDPBox */
2062 if (rcvd > sizeof(struct UDPBox))
2063 {
2064 const struct UDPBox *box;
2065 struct KeyCacheEntry *kce;
2066
2067 box = (const struct UDPBox *) buf;
2068 kce = GNUNET_CONTAINER_multishortmap_get (key_cache, &box->kid);
2069 if (NULL != kce)
2070 {
2071 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2072 "Found KCE with kid %s\n",
2073 GNUNET_sh2s (&box->kid));
2074 decrypt_box (box, (size_t) rcvd, kce);
2075 continue;
2076 }
2077 }
2078
2079 /* next, check if it is a broadcast */
2080 if (sizeof(struct UDPBroadcast) == rcvd)
2081 {
2082 const struct UDPBroadcast *ub;
2083 struct UdpBroadcastSignature uhs;
2084 struct GNUNET_PeerIdentity sender;
2085
2086 addr_verify = GNUNET_memdup (&sa, salen);
2087 addr_verify->sin_port = 0;
2088 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2089 "received UDPBroadcast from %s\n",
2090 GNUNET_a2s ((const struct sockaddr *) addr_verify, salen));
2091 ub = (const struct UDPBroadcast *) buf;
2092 uhs.purpose.purpose = htonl (
2093 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST);
2094 uhs.purpose.size = htonl (sizeof(uhs));
2095 uhs.sender = ub->sender;
2096 sender = ub->sender;
2097 if (0 == memcmp (&sender, &my_identity, sizeof (struct
2098 GNUNET_PeerIdentity)))
2099 {
2100 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2101 "Received our own broadcast\n");
2102 GNUNET_free (addr_verify);
2103 continue;
2104 }
2105 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2106 "checking UDPBroadcastSignature for %s\n",
2107 GNUNET_i2s (&sender));
2108 GNUNET_CRYPTO_hash ((struct sockaddr *) addr_verify, salen,
2109 &uhs.h_address);
2110 if (GNUNET_OK ==
2111 GNUNET_CRYPTO_eddsa_verify (
2112 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST,
2113 &uhs,
2114 &ub->sender_sig,
2115 &ub->sender.public_key))
2116 {
2117 char *addr_s;
2118 enum GNUNET_NetworkType nt;
2119
2120 addr_s =
2121 sockaddr_to_udpaddr_string ((const struct sockaddr *) &sa, salen);
2122 GNUNET_STATISTICS_update (stats, "# broadcasts received", 1, GNUNET_NO);
2123 /* use our own mechanism to determine network type */
2124 nt =
2125 GNUNET_NT_scanner_get_type (is, (const struct sockaddr *) &sa, salen);
2126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2127 "validating address %s received from UDPBroadcast\n",
2128 GNUNET_i2s (&sender));
2129 GNUNET_TRANSPORT_application_validate (ah, &sender, nt, addr_s);
2130 GNUNET_free (addr_s);
2131 GNUNET_free (addr_verify);
2132 continue;
2133 }
2134 else
2135 {
2136 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2137 "VerifyingPeer %s is verifying UDPBroadcast\n",
2138 GNUNET_i2s (&my_identity));
2139 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
2140 "Verifying UDPBroadcast from %s failed\n",
2141 GNUNET_i2s (&ub->sender));
2142 }
2143 GNUNET_free (addr_verify);
2144 /* continue with KX, mostly for statistics... */
2145 }
2146
2147
2148 /* finally, test if it is a KX */
2149 if (rcvd < sizeof(struct UDPConfirmation) + sizeof(struct InitialKX))
2150 {
2151 GNUNET_STATISTICS_update (stats,
2152 "# messages dropped (no kid, too small for KX)",
2153 1,
2154 GNUNET_NO);
2155 continue;
2156 }
2157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2158 "Got KX\n");
2159 {
2160 const struct InitialKX *kx;
2161 struct SharedSecret *ss;
2162 char pbuf[rcvd - sizeof(struct InitialKX)];
2163 const struct UDPConfirmation *uc;
2164 struct SenderAddress *sender;
2165
2166 kx = (const struct InitialKX *) buf;
2167 ss = setup_initial_shared_secret_dec (&kx->representative);
2168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2169 "Before DEC\n");
2170
2171 if (GNUNET_OK != try_decrypt (ss,
2172 kx->gcm_tag,
2173 0,
2174 &buf[sizeof(*kx)],
2175 sizeof(pbuf),
2176 pbuf))
2177 {
2178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2179 "Unable to decrypt tag, dropping...\n");
2180 GNUNET_free (ss);
2181 GNUNET_STATISTICS_update (
2182 stats,
2183 "# messages dropped (no kid, AEAD decryption failed)",
2184 1,
2185 GNUNET_NO);
2186 continue;
2187 }
2188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2189 "Before VERIFY\n");
2190
2191 uc = (const struct UDPConfirmation *) pbuf;
2192
2193 struct GNUNET_CRYPTO_EcdhePublicKey pub_ephemeral;
2194 GNUNET_CRYPTO_ecdhe_elligator_decoding (&pub_ephemeral, NULL,
2195 &kx->representative);
2196 if (GNUNET_OK != verify_confirmation (&pub_ephemeral, uc)) // TODO: need ephemeral instead of representative
2197 {
2198 GNUNET_break_op (0);
2199 GNUNET_free (ss);
2200 GNUNET_STATISTICS_update (stats,
2201 "# messages dropped (sender signature invalid)",
2202 1,
2203 GNUNET_NO);
2204 continue;
2205 }
2206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2207 "Before SETUP_SENDER\n");
2208
2209 calculate_cmac (ss);
2210 sender = setup_sender (&uc->sender, (const struct sockaddr *) &sa, salen);
2211 ss->sender = sender;
2212 GNUNET_CONTAINER_DLL_insert (sender->ss_head, sender->ss_tail, ss);
2213 if ((KCN_THRESHOLD > ss->sender->acks_available) &&
2214 (NULL == ss->sender->kce_task) &&
2215 (GNUNET_NO == ss->sender->kce_task_finished))
2216 {
2217 // TODO This task must be per sender! FIXME: This is a nice todo, but I do not know what must be done here to fix.
2218 ss->sender->kce_send_ack_on_finish = GNUNET_YES;
2219 ss->sender->kce_task = GNUNET_SCHEDULER_add_now (
2220 kce_generate_cb,
2221 ss);
2222 }
2223 sender->num_secrets++;
2224 GNUNET_STATISTICS_update (stats, "# Secrets active", 1, GNUNET_NO);
2225 GNUNET_STATISTICS_update (stats,
2226 "# messages decrypted without BOX",
2227 1,
2228 GNUNET_NO);
2229 try_handle_plaintext (sender, &uc[1], sizeof(pbuf) - sizeof(*uc));
2230 if (0 == purge_secrets (sender->ss_tail))
2231 {
2232 // No secret purged. Delete oldest.
2233 if (sender->num_secrets > MAX_SECRETS)
2234 {
2235 secret_destroy (sender->ss_tail);
2236 }
2237 }
2238 }
2239 }
2240}
2241
2242
2243/**
2244 * Convert UDP bind specification to a `struct sockaddr *`
2245 *
2246 * @param bindto bind specification to convert
2247 * @param[out] sock_len set to the length of the address
2248 * @return converted bindto specification
2249 */
2250static struct sockaddr *
2251udp_address_to_sockaddr (const char *bindto, socklen_t *sock_len)
2252{
2253 struct sockaddr *in;
2254 unsigned int port;
2255 char dummy[2];
2256 char *colon;
2257 char *cp;
2258
2259 if (1 == sscanf (bindto, "%u%1s", &port, dummy))
2260 {
2261 /* interpreting value as just a PORT number */
2262 if (port > UINT16_MAX)
2263 {
2264 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2265 "BINDTO specification `%s' invalid: value too large for port\n",
2266 bindto);
2267 return NULL;
2268 }
2269 if (GNUNET_YES == disable_v6)
2270 {
2271 struct sockaddr_in *i4;
2272
2273 i4 = GNUNET_malloc (sizeof(struct sockaddr_in));
2274 i4->sin_family = AF_INET;
2275 i4->sin_port = htons ((uint16_t) port);
2276 *sock_len = sizeof(struct sockaddr_in);
2277 in = (struct sockaddr *) i4;
2278 }
2279 else
2280 {
2281 struct sockaddr_in6 *i6;
2282
2283 i6 = GNUNET_malloc (sizeof(struct sockaddr_in6));
2284 i6->sin6_family = AF_INET6;
2285 i6->sin6_port = htons ((uint16_t) port);
2286 *sock_len = sizeof(struct sockaddr_in6);
2287 in = (struct sockaddr *) i6;
2288 }
2289 return in;
2290 }
2291 cp = GNUNET_strdup (bindto);
2292 colon = strrchr (cp, ':');
2293 if (NULL != colon)
2294 {
2295 /* interpret value after colon as port */
2296 *colon = '\0';
2297 colon++;
2298 if (1 == sscanf (colon, "%u%1s", &port, dummy))
2299 {
2300 /* interpreting value as just a PORT number */
2301 if (port > UINT16_MAX)
2302 {
2303 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2304 "BINDTO specification `%s' invalid: value too large for port\n",
2305 bindto);
2306 GNUNET_free (cp);
2307 return NULL;
2308 }
2309 }
2310 else
2311 {
2312 GNUNET_log (
2313 GNUNET_ERROR_TYPE_ERROR,
2314 "BINDTO specification `%s' invalid: last ':' not followed by number\n",
2315 bindto);
2316 GNUNET_free (cp);
2317 return NULL;
2318 }
2319 }
2320 else
2321 {
2322 /* interpret missing port as 0, aka pick any free one */
2323 port = 0;
2324 }
2325 {
2326 /* try IPv4 */
2327 struct sockaddr_in v4;
2328
2329 memset (&v4, 0, sizeof(v4));
2330 if (1 == inet_pton (AF_INET, cp, &v4.sin_addr))
2331 {
2332 v4.sin_family = AF_INET;
2333 v4.sin_port = htons ((uint16_t) port);
2334#if HAVE_SOCKADDR_IN_SIN_LEN
2335 v4.sin_len = sizeof(struct sockaddr_in);
2336#endif
2337 in = GNUNET_memdup (&v4, sizeof(struct sockaddr_in));
2338 *sock_len = sizeof(struct sockaddr_in);
2339 GNUNET_free (cp);
2340 return in;
2341 }
2342 }
2343 {
2344 /* try IPv6 */
2345 struct sockaddr_in6 v6;
2346 const char *start;
2347
2348 memset (&v6, 0, sizeof(v6));
2349 start = cp;
2350 if (('[' == *cp) && (']' == cp[strlen (cp) - 1]))
2351 {
2352 start++; /* skip over '[' */
2353 cp[strlen (cp) - 1] = '\0'; /* eat ']' */
2354 }
2355 if (1 == inet_pton (AF_INET6, start, &v6.sin6_addr))
2356 {
2357 v6.sin6_family = AF_INET6;
2358 v6.sin6_port = htons ((uint16_t) port);
2359#if HAVE_SOCKADDR_IN_SIN_LEN
2360 v6.sin6_len = sizeof(struct sockaddr_in6);
2361#endif
2362 in = GNUNET_memdup (&v6, sizeof(v6));
2363 *sock_len = sizeof(v6);
2364 GNUNET_free (cp);
2365 return in;
2366 }
2367 }
2368 /* #5528 FIXME (feature!): maybe also try getnameinfo()? */
2369 GNUNET_free (cp);
2370 return NULL;
2371}
2372
2373
2374/**
2375 * Pad @a dgram by @a pad_size using @a out_cipher.
2376 *
2377 * @param out_cipher cipher to use
2378 * @param dgram datagram to pad
2379 * @param pad_size number of bytes of padding to append
2380 */
2381static void
2382do_pad (gcry_cipher_hd_t out_cipher, char *dgram, size_t pad_size)
2383{
2384 char pad[pad_size];
2385
2386 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_WEAK, pad, sizeof(pad));
2387 if (sizeof(pad) > sizeof(struct GNUNET_MessageHeader))
2388 {
2389 struct GNUNET_MessageHeader hdr =
2390 { .size = htons (sizeof(pad)),
2391 .type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_PAD) };
2392
2393 memcpy (pad, &hdr, sizeof(hdr));
2394 }
2395 GNUNET_assert (
2396 0 ==
2397 gcry_cipher_encrypt (out_cipher, dgram, sizeof(pad), pad, sizeof(pad)));
2398}
2399
2400
2401static void
2402send_msg_with_kx (const struct GNUNET_MessageHeader *msg, struct
2403 ReceiverAddress *receiver,
2404 struct GNUNET_MQ_Handle *mq)
2405{
2406 uint16_t msize = ntohs (msg->size);
2407 struct UdpHandshakeSignature uhs;
2408 struct UDPConfirmation uc;
2409 struct InitialKX kx;
2410 char dgram[receiver->kx_mtu + sizeof(uc) + sizeof(kx)];
2411 size_t dpos;
2412 gcry_cipher_hd_t out_cipher;
2413 struct SharedSecret *ss;
2414
2415 if (msize > receiver->kx_mtu)
2416 {
2417 GNUNET_break (0);
2418 if (GNUNET_YES != receiver->receiver_destroy_called)
2419 receiver_destroy (receiver);
2420 return;
2421 }
2422 reschedule_receiver_timeout (receiver);
2423
2424 /* setup key material */
2425 struct GNUNET_CRYPTO_ElligatorRepresentative repr;
2426 ss = setup_initial_shared_secret_ephemeral (&repr, receiver);
2427 GNUNET_CRYPTO_ecdhe_elligator_decoding (&uhs.ephemeral, NULL,
2428 &repr);
2429
2430 if (0 == purge_secrets (receiver->ss_tail))
2431 {
2432 // No secret purged. Delete oldest.
2433 if (receiver->num_secrets > MAX_SECRETS)
2434 {
2435 secret_destroy (receiver->ss_tail);
2436 }
2437 }
2438
2439 setup_cipher (&ss->master, 0, &out_cipher);
2440 /* compute 'uc' */
2441 uc.sender = my_identity;
2442 uc.monotonic_time =
2443 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (cfg));
2444 uhs.purpose.purpose = htonl (
2445 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_HANDSHAKE);
2446 uhs.purpose.size = htonl (sizeof(uhs));
2447 uhs.sender = my_identity;
2448 uhs.receiver = receiver->target;
2449 uhs.monotonic_time = uc.monotonic_time;
2450 GNUNET_CRYPTO_eddsa_sign (my_private_key,
2451 &uhs,
2452 &uc.sender_sig);
2453 /* Leave space for kx */
2454 dpos = sizeof(kx);
2455 /* Append encrypted uc to dgram */
2456 GNUNET_assert (0 == gcry_cipher_encrypt (out_cipher,
2457 &dgram[dpos],
2458 sizeof(uc),
2459 &uc,
2460 sizeof(uc)));
2461 dpos += sizeof(uc);
2462 /* Append encrypted payload to dgram */
2463 GNUNET_assert (
2464 0 == gcry_cipher_encrypt (out_cipher, &dgram[dpos], msize, msg, msize));
2465 dpos += msize;
2466 do_pad (out_cipher, &dgram[dpos], sizeof(dgram) - dpos);
2467 /* Datagram starts with kx */
2468 kx.representative = repr;
2469 GNUNET_assert (
2470 0 == gcry_cipher_gettag (out_cipher, kx.gcm_tag, sizeof(kx.gcm_tag)));
2471 gcry_cipher_close (out_cipher);
2472 memcpy (dgram, &kx, sizeof(kx));
2473 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
2474 dgram,
2475 sizeof(dgram),
2476 receiver->address,
2477 receiver->address_len))
2478 {
2479 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
2480 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2481 "Sending KX with payload size %u to %s family %d failed sock %p\n",
2482 msize,
2483 GNUNET_a2s (receiver->address,
2484 receiver->address_len),
2485 receiver->address->sa_family,
2486 udp_sock);
2487 GNUNET_MQ_impl_send_continue (mq);
2488 receiver_destroy (receiver);
2489 return;
2490 }
2491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2492 "Sending KX with payload size %u to %s\n",
2493 msize,
2494 GNUNET_a2s (receiver->address,
2495 receiver->address_len));
2496 GNUNET_MQ_impl_send_continue (mq);
2497}
2498
2499
2500/**
2501 * Signature of functions implementing the sending functionality of a
2502 * message queue.
2503 *
2504 * @param mq the message queue
2505 * @param msg the message to send
2506 * @param impl_state our `struct ReceiverAddress`
2507 */
2508static void
2509mq_send_kx (struct GNUNET_MQ_Handle *mq,
2510 const struct GNUNET_MessageHeader *msg,
2511 void *impl_state)
2512{
2513 struct ReceiverAddress *receiver = impl_state;
2514
2515 GNUNET_assert (mq == receiver->kx_mq);
2516 send_msg_with_kx (msg, receiver, mq);
2517}
2518
2519
2520static void
2521create_rekey (struct ReceiverAddress *receiver, struct SharedSecret *ss, struct
2522 UDPRekey *rekey)
2523{
2524 struct SharedSecret *ss_rekey;
2525
2526 ss->rekey_initiated = GNUNET_YES;
2527 /* setup key material */
2528 ss_rekey = setup_shared_secret_ephemeral (&rekey->ephemeral,
2529 receiver);
2530 ss_rekey->sequence_allowed = 0;
2531 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2532 "Setup secret with k = %s\n",
2533 GNUNET_h2s (&(ss_rekey->master)));
2534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2535 "Setup secret with H(k) = %s\n",
2536 GNUNET_h2s (&(ss_rekey->cmac)));
2537
2538 /* Append encrypted payload to dgram */
2539 rekey->header.type = htons (GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_REKEY);
2540 rekey->header.size = htons (sizeof (struct UDPRekey));
2541}
2542
2543
2544/**
2545 * Signature of functions implementing the sending functionality of a
2546 * message queue.
2547 *
2548 * @param mq the message queue
2549 * @param msg the message to send
2550 * @param impl_state our `struct ReceiverAddress`
2551 */
2552static void
2553mq_send_d (struct GNUNET_MQ_Handle *mq,
2554 const struct GNUNET_MessageHeader *msg,
2555 void *impl_state)
2556{
2557 struct ReceiverAddress *receiver = impl_state;
2558 struct UDPRekey rekey;
2559 struct SharedSecret *ss;
2560 int inject_rekey = GNUNET_NO;
2561 uint16_t msize = ntohs (msg->size);
2562
2563 GNUNET_assert (mq == receiver->d_mq);
2564 if ((msize > receiver->d_mtu) ||
2565 (0 == receiver->acks_available))
2566 {
2567 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2568 "msize: %u, mtu: %llu, acks: %u\n",
2569 (unsigned int) msize,
2570 (unsigned long long) receiver->d_mtu,
2571 receiver->acks_available);
2572
2573 GNUNET_break (0);
2574 if (GNUNET_YES != receiver->receiver_destroy_called)
2575 receiver_destroy (receiver);
2576 return;
2577 }
2578 reschedule_receiver_timeout (receiver);
2579
2580 if (receiver->num_secrets > MAX_SECRETS)
2581 {
2582 if ((0 == purge_secrets (receiver->ss_tail)) &&
2583 (NULL != receiver->ss_tail))
2584 {
2585 // No secret purged. Delete oldest.
2586 secret_destroy (receiver->ss_tail);
2587 }
2588 }
2589 /* begin "BOX" encryption method, scan for ACKs from tail! */
2590 ss = receiver->ss_tail;
2591 struct SharedSecret *ss_tmp;
2592 while (NULL != ss)
2593 {
2594 size_t payload_len = sizeof(struct UDPBox) + receiver->d_mtu;
2595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2596 "Considering SS %s sequence used: %u sequence allowed: %u bytes sent: %lu.\n",
2597 GNUNET_h2s (&ss->master), ss->sequence_used,
2598 ss->sequence_allowed, ss->bytes_sent);
2599 if (ss->sequence_used >= ss->sequence_allowed)
2600 {
2601 // GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2602 // "Skipping ss because no acks to use.\n");
2603 ss = ss->prev;
2604 continue;
2605 }
2606 if (ss->bytes_sent >= rekey_max_bytes)
2607 {
2608 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2609 "Skipping ss because rekey bytes reached.\n");
2610 // FIXME cleanup ss with too many bytes sent!
2611 ss_tmp = ss->prev;
2612 secret_destroy (ss);
2613 ss = ss_tmp;
2614 continue;
2615 }
2616 if (ss->bytes_sent > rekey_max_bytes * 0.7)
2617 {
2618 if (ss->rekey_initiated == GNUNET_NO)
2619 {
2620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2621 "Injecting rekey for ss with byte sent %lu\n",
2622 (unsigned long) ss->bytes_sent);
2623 create_rekey (receiver, ss, &rekey);
2624 inject_rekey = GNUNET_YES;
2625 payload_len += sizeof (rekey);
2626 ss->rekey_initiated = GNUNET_YES;
2627 }
2628 }
2629 if (0 < ss->sequence_used)
2630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2631 "Trying to send UDPBox with shared secrect %s sequence_used %u and ss->sequence_allowed %u\n",
2632 GNUNET_h2s (&ss->master),
2633 ss->sequence_used,
2634 ss->sequence_allowed);
2635
2636 char dgram[payload_len];
2637 struct UDPBox *box;
2638 gcry_cipher_hd_t out_cipher;
2639 size_t dpos;
2640
2641 box = (struct UDPBox *) dgram;
2642 ss->sequence_used++;
2643 get_kid (&ss->master, ss->sequence_used, &box->kid);
2644 setup_cipher (&ss->master, ss->sequence_used, &out_cipher);
2645 /* Append encrypted payload to dgram */
2646 dpos = sizeof(struct UDPBox);
2647 if (GNUNET_YES == inject_rekey)
2648 {
2649 GNUNET_assert (
2650 0 == gcry_cipher_encrypt (out_cipher, &dgram[dpos], sizeof (rekey),
2651 &rekey, sizeof (rekey)));
2652 dpos += sizeof (rekey);
2653 }
2654 GNUNET_assert (
2655 0 == gcry_cipher_encrypt (out_cipher, &dgram[dpos], msize, msg, msize));
2656 dpos += msize;
2657 do_pad (out_cipher, &dgram[dpos], sizeof(dgram) - dpos);
2658 GNUNET_assert (0 == gcry_cipher_gettag (out_cipher,
2659 box->gcm_tag,
2660 sizeof(box->gcm_tag)));
2661 gcry_cipher_close (out_cipher);
2662
2663 if (-1 == GNUNET_NETWORK_socket_sendto (udp_sock,
2664 dgram,
2665 payload_len, // FIXME why always send sizeof dgram?
2666 receiver->address,
2667 receiver->address_len))
2668 {
2669 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "send");
2670 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2671 "Sending UDPBox to %s family %d failed sock %p failed\n",
2672 GNUNET_a2s (receiver->address,
2673 receiver->address_len),
2674 receiver->address->sa_family,
2675 udp_sock);
2676 receiver_destroy (receiver);
2677 return;
2678 }
2679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2680 "Sending UDPBox with payload size %u, %u acks left, %lu bytes sent\n",
2681 msize,
2682 receiver->acks_available,
2683 (unsigned long) ss->bytes_sent);
2684 ss->bytes_sent += sizeof (dgram);
2685 receiver->acks_available--;
2686 GNUNET_MQ_impl_send_continue (mq);
2687 return;
2688 }
2689 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2690 "No suitable ss found, sending as KX...\n");
2691 send_msg_with_kx (msg, receiver, mq);
2692}
2693
2694
2695/**
2696 * Signature of functions implementing the destruction of a message
2697 * queue. Implementations must not free @a mq, but should take care
2698 * of @a impl_state.
2699 *
2700 * @param mq the message queue to destroy
2701 * @param impl_state our `struct ReceiverAddress`
2702 */
2703static void
2704mq_destroy_d (struct GNUNET_MQ_Handle *mq, void *impl_state)
2705{
2706 struct ReceiverAddress *receiver = impl_state;
2707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2708 "Default MQ destroyed\n");
2709 if (mq == receiver->d_mq)
2710 {
2711 receiver->d_mq = NULL;
2712 if (GNUNET_YES != receiver->receiver_destroy_called)
2713 receiver_destroy (receiver);
2714 }
2715}
2716
2717
2718/**
2719 * Signature of functions implementing the destruction of a message
2720 * queue. Implementations must not free @a mq, but should take care
2721 * of @a impl_state.
2722 *
2723 * @param mq the message queue to destroy
2724 * @param impl_state our `struct ReceiverAddress`
2725 */
2726static void
2727mq_destroy_kx (struct GNUNET_MQ_Handle *mq, void *impl_state)
2728{
2729 struct ReceiverAddress *receiver = impl_state;
2730 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2731 "KX MQ destroyed\n");
2732 if (mq == receiver->kx_mq)
2733 {
2734 receiver->kx_mq = NULL;
2735 if (GNUNET_YES != receiver->receiver_destroy_called)
2736 receiver_destroy (receiver);
2737 }
2738}
2739
2740
2741/**
2742 * Implementation function that cancels the currently sent message.
2743 *
2744 * @param mq message queue
2745 * @param impl_state our `struct RecvierAddress`
2746 */
2747static void
2748mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
2749{
2750 /* Cancellation is impossible with UDP; bail */
2751 GNUNET_assert (0);
2752}
2753
2754
2755/**
2756 * Generic error handler, called with the appropriate
2757 * error code and the same closure specified at the creation of
2758 * the message queue.
2759 * Not every message queue implementation supports an error handler.
2760 *
2761 * @param cls our `struct ReceiverAddress`
2762 * @param error error code
2763 */
2764static void
2765mq_error (void *cls, enum GNUNET_MQ_Error error)
2766{
2767 struct ReceiverAddress *receiver = cls;
2768
2769 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2770 "MQ error in queue to %s: %d\n",
2771 GNUNET_i2s (&receiver->target),
2772 (int) error);
2773 receiver_destroy (receiver);
2774}
2775
2776
2777/**
2778 * Setup the MQ for the @a receiver. If a queue exists,
2779 * the existing one is destroyed. Then the MTU is
2780 * recalculated and a fresh queue is initialized.
2781 *
2782 * @param receiver receiver to setup MQ for
2783 */
2784static void
2785setup_receiver_mq (struct ReceiverAddress *receiver)
2786{
2787 size_t base_mtu;
2788
2789 switch (receiver->address->sa_family)
2790 {
2791 case AF_INET:
2792 base_mtu = 1480 /* Ethernet MTU, 1500 - Ethernet header - VLAN tag */
2793 - sizeof(struct GNUNET_TUN_IPv4Header) /* 20 */
2794 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
2795 break;
2796
2797 case AF_INET6:
2798 base_mtu = 1280 /* Minimum MTU required by IPv6 */
2799 - sizeof(struct GNUNET_TUN_IPv6Header) /* 40 */
2800 - sizeof(struct GNUNET_TUN_UdpHeader) /* 8 */;
2801 break;
2802
2803 default:
2804 GNUNET_assert (0);
2805 break;
2806 }
2807 /* MTU based on full KX messages */
2808 receiver->kx_mtu = base_mtu - sizeof(struct InitialKX) /* 48 */
2809 - sizeof(struct UDPConfirmation); /* 104 */
2810 /* MTU based on BOXed messages */
2811 receiver->d_mtu = base_mtu - sizeof(struct UDPBox);
2812
2813 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2814 "Setting up MQs and QHs\n");
2815 /* => Effective MTU for CORE will range from 1080 (IPv6 + KX) to
2816 1404 (IPv4 + Box) bytes, depending on circumstances... */
2817 if (NULL == receiver->kx_mq)
2818 receiver->kx_mq = GNUNET_MQ_queue_for_callbacks (&mq_send_kx,
2819 &mq_destroy_kx,
2820 &mq_cancel,
2821 receiver,
2822 NULL,
2823 &mq_error,
2824 receiver);
2825 if (NULL == receiver->d_mq)
2826 receiver->d_mq = GNUNET_MQ_queue_for_callbacks (&mq_send_d,
2827 &mq_destroy_d,
2828 &mq_cancel,
2829 receiver,
2830 NULL,
2831 &mq_error,
2832 receiver);
2833
2834 receiver->kx_qh =
2835 GNUNET_TRANSPORT_communicator_mq_add (ch,
2836 &receiver->target,
2837 receiver->foreign_addr,
2838 receiver->kx_mtu,
2839 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
2840 0, /* Priority */
2841 receiver->nt,
2842 GNUNET_TRANSPORT_CS_OUTBOUND,
2843 receiver->kx_mq);
2844}
2845
2846
2847/**
2848 * Function called by the transport service to initialize a
2849 * message queue given address information about another peer.
2850 * If and when the communication channel is established, the
2851 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
2852 * to notify the service that the channel is now up. It is
2853 * the responsibility of the communicator to manage sane
2854 * retries and timeouts for any @a peer/@a address combination
2855 * provided by the transport service. Timeouts and retries
2856 * do not need to be signalled to the transport service.
2857 *
2858 * @param cls closure
2859 * @param peer identity of the other peer
2860 * @param address where to send the message, human-readable
2861 * communicator-specific format, 0-terminated, UTF-8
2862 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is
2863 * invalid
2864 */
2865static int
2866mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
2867{
2868 struct ReceiverAddress *receiver;
2869 struct GNUNET_HashContext *hsh;
2870 struct GNUNET_HashCode receiver_key;
2871 const char *path;
2872 struct sockaddr *in;
2873 socklen_t in_len;
2874
2875 if (0 != strncmp (address,
2876 COMMUNICATOR_ADDRESS_PREFIX "-",
2877 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
2878 {
2879 GNUNET_break_op (0);
2880 return GNUNET_SYSERR;
2881 }
2882 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
2883 in = udp_address_to_sockaddr (path, &in_len);
2884
2885 if (NULL == in)
2886 {
2887 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
2888 "Failed to setup UDP socket address\n");
2889 return GNUNET_SYSERR;
2890 }
2891 if ((AF_INET6 == in->sa_family) &&
2892 (GNUNET_YES == disable_v6))
2893 {
2894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2895 "IPv6 disabled, skipping %s\n", address);
2896 GNUNET_free (in);
2897 return GNUNET_SYSERR;
2898 }
2899
2900 hsh = GNUNET_CRYPTO_hash_context_start ();
2901 GNUNET_CRYPTO_hash_context_read (hsh, in, in_len);
2902 GNUNET_CRYPTO_hash_context_read (hsh, peer, sizeof(*peer));
2903 GNUNET_CRYPTO_hash_context_finish (hsh, &receiver_key);
2904
2905 receiver = GNUNET_CONTAINER_multihashmap_get (receivers, &receiver_key);
2906 if (NULL != receiver)
2907 {
2908 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2909 "receiver %s already exist or is being connected to\n",
2910 address);
2911 GNUNET_free (in);
2912 return GNUNET_NO;
2913 }
2914
2915 receiver = GNUNET_new (struct ReceiverAddress);
2916 receiver->key = receiver_key;
2917 receiver->address = in;
2918 receiver->address_len = in_len;
2919 receiver->target = *peer;
2920 receiver->nt = GNUNET_NT_scanner_get_type (is, in, in_len);
2921 (void) GNUNET_CONTAINER_multihashmap_put (
2922 receivers,
2923 &receiver->key,
2924 receiver,
2925 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
2926 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
2927 "Added %s to receivers\n",
2928 GNUNET_i2s_full (&receiver->target));
2929 receiver->timeout =
2930 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
2931 receiver->hn = GNUNET_CONTAINER_heap_insert (receivers_heap,
2932 receiver,
2933 receiver->timeout.abs_value_us);
2934 GNUNET_STATISTICS_set (stats,
2935 "# receivers active",
2936 GNUNET_CONTAINER_multihashmap_size (receivers),
2937 GNUNET_NO);
2938 receiver->foreign_addr =
2939 sockaddr_to_udpaddr_string (receiver->address, receiver->address_len);
2940 setup_receiver_mq (receiver);
2941 if (NULL == timeout_task)
2942 timeout_task = GNUNET_SCHEDULER_add_now (&check_timeouts, NULL);
2943 return GNUNET_OK;
2944}
2945
2946
2947/**
2948 * Iterator over all receivers to clean up.
2949 *
2950 * @param cls NULL
2951 * @param target unused
2952 * @param value the queue to destroy
2953 * @return #GNUNET_OK to continue to iterate
2954 */
2955static int
2956get_receiver_delete_it (void *cls,
2957 const struct GNUNET_HashCode *target,
2958 void *value)
2959{
2960 struct ReceiverAddress *receiver = value;
2961
2962 (void) cls;
2963 (void) target;
2964 receiver_destroy (receiver);
2965 return GNUNET_OK;
2966}
2967
2968
2969/**
2970 * Iterator over all senders to clean up.
2971 *
2972 * @param cls NULL
2973 * @param target unused
2974 * @param value the queue to destroy
2975 * @return #GNUNET_OK to continue to iterate
2976 */
2977static int
2978get_sender_delete_it (void *cls,
2979 const struct GNUNET_HashCode *target,
2980 void *value)
2981{
2982 struct SenderAddress *sender = value;
2983
2984 (void) cls;
2985 (void) target;
2986
2987
2988 sender_destroy (sender);
2989 return GNUNET_OK;
2990}
2991
2992
2993/**
2994 * Shutdown the UNIX communicator.
2995 *
2996 * @param cls NULL (always)
2997 */
2998static void
2999do_shutdown (void *cls)
3000{
3001 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3002 "do_shutdown\n");
3003 if (NULL != nat)
3004 {
3005 GNUNET_NAT_unregister (nat);
3006 nat = NULL;
3007 }
3008 while (NULL != bi_head)
3009 bi_destroy (bi_head);
3010 if (NULL != broadcast_task)
3011 {
3012 GNUNET_SCHEDULER_cancel (broadcast_task);
3013 broadcast_task = NULL;
3014 }
3015 if (NULL != timeout_task)
3016 {
3017 GNUNET_SCHEDULER_cancel (timeout_task);
3018 timeout_task = NULL;
3019 }
3020 if (NULL != read_task)
3021 {
3022 GNUNET_SCHEDULER_cancel (read_task);
3023 read_task = NULL;
3024 }
3025 if (NULL != udp_sock)
3026 {
3027 GNUNET_break (GNUNET_OK ==
3028 GNUNET_NETWORK_socket_close (udp_sock));
3029 udp_sock = NULL;
3030 }
3031 GNUNET_CONTAINER_multihashmap_iterate (receivers,
3032 &get_receiver_delete_it,
3033 NULL);
3034 GNUNET_CONTAINER_multihashmap_destroy (receivers);
3035 GNUNET_CONTAINER_multihashmap_iterate (senders,
3036 &get_sender_delete_it,
3037 NULL);
3038 GNUNET_CONTAINER_multihashmap_destroy (senders);
3039 GNUNET_CONTAINER_multishortmap_destroy (key_cache);
3040 GNUNET_CONTAINER_heap_destroy (senders_heap);
3041 GNUNET_CONTAINER_heap_destroy (receivers_heap);
3042 if (NULL != timeout_task)
3043 {
3044 GNUNET_SCHEDULER_cancel (timeout_task);
3045 timeout_task = NULL;
3046 }
3047 if (NULL != ch)
3048 {
3049 GNUNET_TRANSPORT_communicator_disconnect (ch);
3050 ch = NULL;
3051 }
3052 if (NULL != ah)
3053 {
3054 GNUNET_TRANSPORT_application_done (ah);
3055 ah = NULL;
3056 }
3057 if (NULL != stats)
3058 {
3059 GNUNET_STATISTICS_destroy (stats, GNUNET_YES);
3060 stats = NULL;
3061 }
3062 if (NULL != my_private_key)
3063 {
3064 GNUNET_free (my_private_key);
3065 my_private_key = NULL;
3066 }
3067 if (NULL != is)
3068 {
3069 GNUNET_NT_scanner_done (is);
3070 is = NULL;
3071 }
3072 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3073 "do_shutdown finished\n");
3074}
3075
3076
3077struct AckInfo
3078{
3079 const struct UDPAck *ack;
3080
3081 const struct GNUNET_PeerIdentity *sender;
3082};
3083
3084static int
3085handle_ack_by_sender (void *cls, const struct GNUNET_HashCode *key, void *value)
3086{
3087 struct ReceiverAddress *receiver = value;
3088 struct AckInfo *ai = cls;
3089
3090 if (0 != GNUNET_memcmp (ai->sender, &receiver->target))
3091 {
3092 return GNUNET_YES;
3093 }
3094 handle_ack ((void*) ai->ack, key, receiver);
3095 return GNUNET_YES;
3096}
3097
3098
3099/**
3100 * Function called when the transport service has received a
3101 * backchannel message for this communicator (!) via a different return
3102 * path. Should be an acknowledgement.
3103 *
3104 * @param cls closure, NULL
3105 * @param sender which peer sent the notification
3106 * @param msg payload
3107 */
3108static void
3109enc_notify_cb (void *cls,
3110 const struct GNUNET_PeerIdentity *sender,
3111 const struct GNUNET_MessageHeader *msg)
3112{
3113 struct AckInfo ai;
3114
3115 (void) cls;
3116 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3117 "Storing UDPAck received from backchannel from %s\n",
3118 GNUNET_i2s_full (sender));
3119 if ((ntohs (msg->type) != GNUNET_MESSAGE_TYPE_COMMUNICATOR_UDP_ACK) ||
3120 (ntohs (msg->size) != sizeof(struct UDPAck)))
3121 {
3122 GNUNET_break_op (0);
3123 return;
3124 }
3125 ai.ack = (const struct UDPAck *) msg;
3126 ai.sender = sender;
3127 GNUNET_CONTAINER_multihashmap_iterate (receivers,
3128 &handle_ack_by_sender,
3129 &ai);
3130}
3131
3132
3133/**
3134 * Signature of the callback passed to #GNUNET_NAT_register() for
3135 * a function to call whenever our set of 'valid' addresses changes.
3136 *
3137 * @param cls closure
3138 * @param app_ctx[in,out] location where the app can store stuff
3139 * on add and retrieve it on remove
3140 * @param add_remove #GNUNET_YES to add a new public IP address,
3141 * #GNUNET_NO to remove a previous (now invalid) one
3142 * @param ac address class the address belongs to
3143 * @param addr either the previous or the new public IP address
3144 * @param addrlen actual length of the @a addr
3145 */
3146static void
3147nat_address_cb (void *cls,
3148 void **app_ctx,
3149 int add_remove,
3150 enum GNUNET_NAT_AddressClass ac,
3151 const struct sockaddr *addr,
3152 socklen_t addrlen)
3153{
3154 char *my_addr;
3155 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
3156
3157 if (GNUNET_YES == add_remove)
3158 {
3159 enum GNUNET_NetworkType nt;
3160
3161 GNUNET_asprintf (&my_addr,
3162 "%s-%s",
3163 COMMUNICATOR_ADDRESS_PREFIX,
3164 GNUNET_a2s (addr, addrlen));
3165 nt = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3166 ai =
3167 GNUNET_TRANSPORT_communicator_address_add (ch,
3168 my_addr,
3169 nt,
3170 GNUNET_TIME_UNIT_FOREVER_REL);
3171 GNUNET_free (my_addr);
3172 *app_ctx = ai;
3173 }
3174 else
3175 {
3176 ai = *app_ctx;
3177 GNUNET_TRANSPORT_communicator_address_remove (ai);
3178 *app_ctx = NULL;
3179 }
3180}
3181
3182
3183/**
3184 * Broadcast our presence on one of our interfaces.
3185 *
3186 * @param cls a `struct BroadcastInterface`
3187 */
3188static void
3189ifc_broadcast (void *cls)
3190{
3191 struct BroadcastInterface *bi = cls;
3192 struct GNUNET_TIME_Relative delay;
3193
3194 delay = BROADCAST_FREQUENCY;
3195 delay.rel_value_us =
3196 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, delay.rel_value_us);
3197 bi->broadcast_task =
3198 GNUNET_SCHEDULER_add_delayed (delay, &ifc_broadcast, bi);
3199
3200 switch (bi->sa->sa_family)
3201 {
3202 case AF_INET: {
3203 static int yes = 1;
3204 static int no = 0;
3205 ssize_t sent;
3206
3207 if (GNUNET_OK !=
3208 GNUNET_NETWORK_socket_setsockopt (udp_sock,
3209 SOL_SOCKET,
3210 SO_BROADCAST,
3211 &yes,
3212 sizeof(int)))
3213 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3214 "setsockopt");
3215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3216 "creating UDPBroadcast from %s\n",
3217 GNUNET_i2s (&(bi->bcm.sender)));
3218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3219 "sending UDPBroadcast to add %s\n",
3220 GNUNET_a2s (bi->ba, bi->salen));
3221 sent = GNUNET_NETWORK_socket_sendto (udp_sock,
3222 &bi->bcm,
3223 sizeof(bi->bcm),
3224 bi->ba,
3225 bi->salen);
3226 if (-1 == sent)
3227 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3228 "sendto");
3229 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
3230 SOL_SOCKET,
3231 SO_BROADCAST,
3232 &no,
3233 sizeof(int)))
3234 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING,
3235 "setsockopt");
3236 break;
3237 }
3238
3239 case AF_INET6: {
3240 ssize_t sent;
3241 struct sockaddr_in6 dst;
3242
3243 dst.sin6_family = AF_INET6;
3244 dst.sin6_port = htons (my_port);
3245 dst.sin6_addr = bi->mcreq.ipv6mr_multiaddr;
3246 dst.sin6_scope_id = ((struct sockaddr_in6 *) bi->ba)->sin6_scope_id;
3247
3248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3249 "sending UDPBroadcast\n");
3250 sent = GNUNET_NETWORK_socket_sendto (udp_sock,
3251 &bi->bcm,
3252 sizeof(bi->bcm),
3253 (const struct sockaddr *) &dst,
3254 sizeof(dst));
3255 if (-1 == sent)
3256 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "sendto");
3257 break;
3258 }
3259
3260 default:
3261 GNUNET_break (0);
3262 break;
3263 }
3264}
3265
3266
3267/**
3268 * Callback function invoked for each interface found.
3269 * Activates/deactivates broadcast interfaces.
3270 *
3271 * @param cls NULL
3272 * @param name name of the interface (can be NULL for unknown)
3273 * @param isDefault is this presumably the default interface
3274 * @param addr address of this interface (can be NULL for unknown or unassigned)
3275 * @param broadcast_addr the broadcast address (can be NULL for unknown or
3276 * unassigned)
3277 * @param netmask the network mask (can be NULL for unknown or unassigned)
3278 * @param addrlen length of the address
3279 * @return #GNUNET_OK to continue iteration, #GNUNET_SYSERR to abort
3280 */
3281static int
3282iface_proc (void *cls,
3283 const char *name,
3284 int isDefault,
3285 const struct sockaddr *addr,
3286 const struct sockaddr *broadcast_addr,
3287 const struct sockaddr *netmask,
3288 socklen_t addrlen)
3289{
3290 struct BroadcastInterface *bi;
3291 enum GNUNET_NetworkType network;
3292 struct UdpBroadcastSignature ubs;
3293
3294 (void) cls;
3295 (void) netmask;
3296 if (NULL == addr)
3297 return GNUNET_YES; /* need to know our address! */
3298 network = GNUNET_NT_scanner_get_type (is, addr, addrlen);
3299 if (GNUNET_NT_LOOPBACK == network)
3300 {
3301 /* Broadcasting on loopback does not make sense */
3302 return GNUNET_YES;
3303 }
3304 for (bi = bi_head; NULL != bi; bi = bi->next)
3305 {
3306 if ((bi->salen == addrlen) && (0 == memcmp (addr, bi->sa, addrlen)))
3307 {
3308 bi->found = GNUNET_YES;
3309 return GNUNET_OK;
3310 }
3311 }
3312
3313 if ((AF_INET6 == addr->sa_family) && (NULL == broadcast_addr))
3314 return GNUNET_OK; /* broadcast_addr is required for IPv6! */
3315 if ((AF_INET6 == addr->sa_family) && (GNUNET_YES != have_v6_socket))
3316 return GNUNET_OK; /* not using IPv6 */
3317
3318 bi = GNUNET_new (struct BroadcastInterface);
3319 bi->sa = GNUNET_memdup (addr,
3320 addrlen);
3321 if ( (NULL != broadcast_addr) &&
3322 (addrlen == sizeof (struct sockaddr_in)) )
3323 {
3324 struct sockaddr_in *ba;
3325
3326 ba = GNUNET_memdup (broadcast_addr,
3327 addrlen);
3328 ba->sin_port = htons (2086); /* always GNUnet port, ignore configuration! */
3329 bi->ba = (struct sockaddr *) ba;
3330 }
3331 bi->salen = addrlen;
3332 bi->found = GNUNET_YES;
3333 bi->bcm.sender = my_identity;
3334 ubs.purpose.purpose = htonl (
3335 GNUNET_SIGNATURE_PURPOSE_COMMUNICATOR_UDP_BROADCAST);
3336 ubs.purpose.size = htonl (sizeof(ubs));
3337 ubs.sender = my_identity;
3338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3339 "creating UDPBroadcastSignature for %s\n",
3340 GNUNET_a2s (addr, addrlen));
3341 GNUNET_CRYPTO_hash (addr, addrlen, &ubs.h_address);
3342 GNUNET_CRYPTO_eddsa_sign (my_private_key,
3343 &ubs,
3344 &bi->bcm.sender_sig);
3345 if (NULL != bi->ba)
3346 {
3347 bi->broadcast_task = GNUNET_SCHEDULER_add_now (&ifc_broadcast, bi);
3348 GNUNET_CONTAINER_DLL_insert (bi_head, bi_tail, bi);
3349 }
3350 if ((AF_INET6 == addr->sa_family) && (NULL != broadcast_addr))
3351 {
3352 /* Create IPv6 multicast request */
3353 const struct sockaddr_in6 *s6 =
3354 (const struct sockaddr_in6 *) broadcast_addr;
3355
3356 GNUNET_assert (
3357 1 == inet_pton (AF_INET6, "FF05::13B", &bi->mcreq.ipv6mr_multiaddr));
3358
3359 /* http://tools.ietf.org/html/rfc2553#section-5.2:
3360 *
3361 * IPV6_JOIN_GROUP
3362 *
3363 * Join a multicast group on a specified local interface. If the
3364 * interface index is specified as 0, the kernel chooses the local
3365 * interface. For example, some kernels look up the multicast
3366 * group in the normal IPv6 routing table and using the resulting
3367 * interface; we do this for each interface, so no need to use
3368 * zero (anymore...).
3369 */
3370 bi->mcreq.ipv6mr_interface = s6->sin6_scope_id;
3371
3372 /* Join the multicast group */
3373 if (GNUNET_OK != GNUNET_NETWORK_socket_setsockopt (udp_sock,
3374 IPPROTO_IPV6,
3375 IPV6_JOIN_GROUP,
3376 &bi->mcreq,
3377 sizeof(bi->mcreq)))
3378 {
3379 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "setsockopt");
3380 }
3381 }
3382 return GNUNET_OK;
3383}
3384
3385
3386/**
3387 * Scan interfaces to broadcast our presence on the LAN.
3388 *
3389 * @param cls NULL, unused
3390 */
3391static void
3392do_broadcast (void *cls)
3393{
3394 struct BroadcastInterface *bin;
3395
3396 (void) cls;
3397 for (struct BroadcastInterface *bi = bi_head; NULL != bi; bi = bi->next)
3398 bi->found = GNUNET_NO;
3399 GNUNET_OS_network_interfaces_list (&iface_proc, NULL);
3400 for (struct BroadcastInterface *bi = bi_head; NULL != bi; bi = bin)
3401 {
3402 bin = bi->next;
3403 if (GNUNET_NO == bi->found)
3404 bi_destroy (bi);
3405 }
3406 broadcast_task = GNUNET_SCHEDULER_add_delayed (INTERFACE_SCAN_FREQUENCY,
3407 &do_broadcast,
3408 NULL);
3409}
3410
3411
3412static void
3413try_connection_reversal (void *cls,
3414 const struct sockaddr *addr,
3415 socklen_t addrlen)
3416{
3417 /* FIXME: support reversal: #5529 */
3418 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
3419 "No connection reversal implemented!");
3420}
3421
3422
3423/**
3424 * Setup communicator and launch network interactions.
3425 *
3426 * @param cls NULL (always)
3427 * @param args remaining command-line arguments
3428 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
3429 * @param c configuration
3430 */
3431static void
3432run (void *cls,
3433 char *const *args,
3434 const char *cfgfile,
3435 const struct GNUNET_CONFIGURATION_Handle *c)
3436{
3437 char *bindto;
3438 struct sockaddr *in;
3439 socklen_t in_len;
3440 struct sockaddr_storage in_sto;
3441 socklen_t sto_len;
3442
3443 (void) cls;
3444 cfg = c;
3445 if (GNUNET_OK !=
3446 GNUNET_CONFIGURATION_get_value_string (cfg,
3447 COMMUNICATOR_CONFIG_SECTION,
3448 "BINDTO",
3449 &bindto))
3450 {
3451 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
3452 COMMUNICATOR_CONFIG_SECTION,
3453 "BINDTO");
3454 return;
3455 }
3456
3457 if (GNUNET_OK !=
3458 GNUNET_CONFIGURATION_get_value_time (cfg,
3459 COMMUNICATOR_CONFIG_SECTION,
3460 "REKEY_INTERVAL",
3461 &rekey_interval))
3462 rekey_interval = DEFAULT_REKEY_TIME_INTERVAL;
3463
3464 if (GNUNET_OK !=
3465 GNUNET_CONFIGURATION_get_value_size (cfg,
3466 COMMUNICATOR_CONFIG_SECTION,
3467 "REKEY_MAX_BYTES",
3468 &rekey_max_bytes))
3469 {
3470 rekey_max_bytes = DEFAULT_REKEY_MAX_BYTES;
3471 }
3472 disable_v6 = GNUNET_NO;
3473 if ((GNUNET_NO == GNUNET_NETWORK_test_pf (PF_INET6)) ||
3474 (GNUNET_YES ==
3475 GNUNET_CONFIGURATION_get_value_yesno (cfg,
3476 COMMUNICATOR_CONFIG_SECTION,
3477 "DISABLE_V6")))
3478 {
3479 disable_v6 = GNUNET_YES;
3480 }
3481
3482 in = udp_address_to_sockaddr (bindto, &in_len);
3483 if (NULL == in)
3484 {
3485 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3486 "Failed to setup UDP socket address with path `%s'\n",
3487 bindto);
3488 GNUNET_free (bindto);
3489 return;
3490 }
3491 udp_sock =
3492 GNUNET_NETWORK_socket_create (in->sa_family,
3493 SOCK_DGRAM,
3494 IPPROTO_UDP);
3495 if (NULL == udp_sock)
3496 {
3497 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
3498 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3499 "Failed to create socket for %s family %d\n",
3500 GNUNET_a2s (in,
3501 in_len),
3502 in->sa_family);
3503 GNUNET_free (in);
3504 GNUNET_free (bindto);
3505 return;
3506 }
3507 if (AF_INET6 == in->sa_family)
3508 have_v6_socket = GNUNET_YES;
3509 if (GNUNET_OK !=
3510 GNUNET_NETWORK_socket_bind (udp_sock,
3511 in,
3512 in_len))
3513 {
3514 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR,
3515 "bind",
3516 bindto);
3517 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
3518 "Failed to bind socket for %s family %d sock %p\n",
3519 GNUNET_a2s (in,
3520 in_len),
3521 in->sa_family,
3522 udp_sock);
3523 GNUNET_NETWORK_socket_close (udp_sock);
3524 udp_sock = NULL;
3525 GNUNET_free (in);
3526 GNUNET_free (bindto);
3527 return;
3528 }
3529
3530 /* We might have bound to port 0, allowing the OS to figure it out;
3531 thus, get the real IN-address from the socket */
3532 sto_len = sizeof(in_sto);
3533 if (0 != getsockname (GNUNET_NETWORK_get_fd (udp_sock),
3534 (struct sockaddr *) &in_sto,
3535 &sto_len))
3536 {
3537 memcpy (&in_sto, in, in_len);
3538 sto_len = in_len;
3539 }
3540 GNUNET_free (in);
3541 GNUNET_free (bindto);
3542 in = (struct sockaddr *) &in_sto;
3543 in_len = sto_len;
3544 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_INFO,
3545 "transport",
3546 "Bound to `%s' sock %p\n",
3547 GNUNET_a2s ((const struct sockaddr *) &in_sto,
3548 sto_len),
3549 udp_sock);
3550 switch (in->sa_family)
3551 {
3552 case AF_INET:
3553 my_port = ntohs (((struct sockaddr_in *) in)->sin_port);
3554 break;
3555
3556 case AF_INET6:
3557 my_port = ntohs (((struct sockaddr_in6 *) in)->sin6_port);
3558 break;
3559
3560 default:
3561 GNUNET_break (0);
3562 my_port = 0;
3563 }
3564 stats = GNUNET_STATISTICS_create ("communicator-udp", cfg);
3565 senders = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
3566 receivers = GNUNET_CONTAINER_multihashmap_create (32, GNUNET_YES);
3567 senders_heap = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3568 receivers_heap =
3569 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
3570 key_cache = GNUNET_CONTAINER_multishortmap_create (1024, GNUNET_YES);
3571 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
3572 is = GNUNET_NT_scanner_init ();
3573 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
3574 if (NULL == my_private_key)
3575 {
3576 GNUNET_log (
3577 GNUNET_ERROR_TYPE_ERROR,
3578 _ (
3579 "Transport service is lacking key configuration settings. Exiting.\n"));
3580 GNUNET_SCHEDULER_shutdown ();
3581 return;
3582 }
3583 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
3584 /* start reading */
3585 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
3586 udp_sock,
3587 &sock_read,
3588 NULL);
3589 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
3590 COMMUNICATOR_CONFIG_SECTION,
3591 COMMUNICATOR_ADDRESS_PREFIX,
3592 GNUNET_TRANSPORT_CC_UNRELIABLE,
3593 &mq_init,
3594 NULL,
3595 &enc_notify_cb,
3596 NULL);
3597 if (NULL == ch)
3598 {
3599 GNUNET_break (0);
3600 GNUNET_SCHEDULER_shutdown ();
3601 return;
3602 }
3603 ah = GNUNET_TRANSPORT_application_init (cfg);
3604 if (NULL == ah)
3605 {
3606 GNUNET_break (0);
3607 GNUNET_SCHEDULER_shutdown ();
3608 return;
3609 }
3610 /* start broadcasting */
3611 if (GNUNET_YES !=
3612 GNUNET_CONFIGURATION_get_value_yesno (cfg,
3613 COMMUNICATOR_CONFIG_SECTION,
3614 "DISABLE_BROADCAST"))
3615 {
3616 broadcast_task = GNUNET_SCHEDULER_add_now (&do_broadcast, NULL);
3617 }
3618 nat = GNUNET_NAT_register (cfg,
3619 COMMUNICATOR_CONFIG_SECTION,
3620 IPPROTO_UDP,
3621 1 /* one address */,
3622 (const struct sockaddr **) &in,
3623 &in_len,
3624 &nat_address_cb,
3625 try_connection_reversal,
3626 NULL /* closure */);
3627}
3628
3629
3630/**
3631 * The main function for the UNIX communicator.
3632 *
3633 * @param argc number of arguments from the command line
3634 * @param argv command line arguments
3635 * @return 0 ok, 1 on error
3636 */
3637int
3638main (int argc, char *const *argv)
3639{
3640 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
3641 GNUNET_GETOPT_OPTION_END
3642 };
3643 int ret;
3644
3645 GNUNET_log_from_nocheck (GNUNET_ERROR_TYPE_DEBUG,
3646 "transport",
3647 "Starting udp communicator\n");
3648 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
3649 return 2;
3650
3651 ret = (GNUNET_OK == GNUNET_PROGRAM_run (argc,
3652 argv,
3653 "gnunet-communicator-udp",
3654 _ ("GNUnet UDP communicator"),
3655 options,
3656 &run,
3657 NULL))
3658 ? 0
3659 : 1;
3660 GNUNET_free_nz ((void *) argv);
3661 return ret;
3662}
3663
3664
3665/* end of gnunet-communicator-udp.c */
diff --git a/src/service/transport/gnunet-communicator-unix.c b/src/service/transport/gnunet-communicator-unix.c
new file mode 100644
index 000000000..1cdc85b8a
--- /dev/null
+++ b/src/service/transport/gnunet-communicator-unix.c
@@ -0,0 +1,1166 @@
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_statistics_service.h"
34#include "gnunet_transport_communication_service.h"
35
36/**
37 * How many messages do we keep at most in the queue to the
38 * transport service before we start to drop (default,
39 * can be changed via the configuration file).
40 * Should be _below_ the level of the communicator API, as
41 * otherwise we may read messages just to have them dropped
42 * by the communicator API.
43 */
44#define DEFAULT_MAX_QUEUE_LENGTH 8000
45
46/**
47 * Address prefix used by the communicator.
48 */
49#define COMMUNICATOR_ADDRESS_PREFIX "unix"
50
51/**
52 * Configuration section used by the communicator.
53 */
54#define COMMUNICATOR_CONFIG_SECTION "communicator-unix"
55
56/**
57 * Our MTU.
58 */
59#ifndef DARWIN
60#define UNIX_MTU UINT16_MAX
61#else
62#define UNIX_MTU 2048
63#endif
64
65GNUNET_NETWORK_STRUCT_BEGIN
66
67/**
68 * UNIX Message-Packet header.
69 */
70struct UNIXMessage
71{
72 /**
73 * Message header.
74 */
75 struct GNUNET_MessageHeader header;
76
77 /**
78 * What is the identity of the sender (GNUNET_hash of public key)
79 */
80 struct GNUNET_PeerIdentity sender;
81};
82
83GNUNET_NETWORK_STRUCT_END
84
85
86/**
87 * Handle for a queue.
88 */
89struct Queue
90{
91 /**
92 * Queues with pending messages (!) are kept in a DLL.
93 */
94 struct Queue *next;
95
96 /**
97 * Queues with pending messages (!) are kept in a DLL.
98 */
99 struct Queue *prev;
100
101 /**
102 * To whom are we talking to.
103 */
104 struct GNUNET_PeerIdentity target;
105
106 /**
107 * Address of the other peer.
108 */
109 struct sockaddr_un *address;
110
111 /**
112 * Length of the address.
113 */
114 socklen_t address_len;
115
116 /**
117 * Message currently scheduled for transmission, non-NULL if and only
118 * if this queue is in the #queue_head DLL.
119 */
120 struct UNIXMessage *msg;
121
122 /**
123 * Message queue we are providing for the #ch.
124 */
125 struct GNUNET_MQ_Handle *mq;
126
127 /**
128 * handle for this queue with the #ch.
129 */
130 struct GNUNET_TRANSPORT_QueueHandle *qh;
131
132 /**
133 * Number of bytes we currently have in our write queue.
134 */
135 unsigned long long bytes_in_queue;
136
137 /**
138 * Timeout for this queue.
139 */
140 struct GNUNET_TIME_Absolute timeout;
141
142 /**
143 * Queue timeout task.
144 */
145 struct GNUNET_SCHEDULER_Task *timeout_task;
146};
147
148/**
149 * My Peer Identity
150 */
151static struct GNUNET_PeerIdentity my_identity;
152
153/**
154 * ID of read task
155 */
156static struct GNUNET_SCHEDULER_Task *read_task;
157
158/**
159 * ID of write task
160 */
161static struct GNUNET_SCHEDULER_Task *write_task;
162
163/**
164 * Number of messages we currently have in our queues towards the transport service.
165 */
166static unsigned long long delivering_messages;
167
168/**
169 * Maximum queue length before we stop reading towards the transport service.
170 */
171static unsigned long long max_queue_length;
172
173/**
174 * For logging statistics.
175 */
176static struct GNUNET_STATISTICS_Handle *stats;
177
178/**
179 * Our environment.
180 */
181static struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
182
183/**
184 * Queues (map from peer identity to `struct Queue`)
185 */
186static struct GNUNET_CONTAINER_MultiPeerMap *queue_map;
187
188/**
189 * Head of queue of messages to transmit.
190 */
191static struct Queue *queue_head;
192
193/**
194 * Tail of queue of messages to transmit.
195 */
196static struct Queue *queue_tail;
197
198/**
199 * socket that we transmit all data with
200 */
201static struct GNUNET_NETWORK_Handle *unix_sock;
202
203/**
204 * Handle to the operation that publishes our address.
205 */
206static struct GNUNET_TRANSPORT_AddressIdentifier *ai;
207
208
209/**
210 * Functions with this signature are called whenever we need
211 * to close a queue due to a disconnect or failure to
212 * establish a connection.
213 *
214 * @param queue queue to close down
215 */
216static void
217queue_destroy (struct Queue *queue)
218{
219 struct GNUNET_MQ_Handle *mq;
220
221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
222 "Disconnecting queue for peer `%s'\n",
223 GNUNET_i2s (&queue->target));
224 if (0 != queue->bytes_in_queue)
225 {
226 GNUNET_CONTAINER_DLL_remove (queue_head, queue_tail, queue);
227 queue->bytes_in_queue = 0;
228 }
229 if (NULL != (mq = queue->mq))
230 {
231 queue->mq = NULL;
232 GNUNET_MQ_destroy (mq);
233 }
234 GNUNET_assert (
235 GNUNET_YES ==
236 GNUNET_CONTAINER_multipeermap_remove (queue_map, &queue->target, queue));
237 GNUNET_STATISTICS_set (stats,
238 "# queues active",
239 GNUNET_CONTAINER_multipeermap_size (queue_map),
240 GNUNET_NO);
241 if (NULL != queue->timeout_task)
242 {
243 GNUNET_SCHEDULER_cancel (queue->timeout_task);
244 queue->timeout_task = NULL;
245 }
246 GNUNET_free (queue->address);
247 GNUNET_free (queue);
248}
249
250
251/**
252 * Queue was idle for too long, so disconnect it
253 *
254 * @param cls the `struct Queue *` to disconnect
255 */
256static void
257queue_timeout (void *cls)
258{
259 struct Queue *queue = cls;
260 struct GNUNET_TIME_Relative left;
261
262 queue->timeout_task = NULL;
263 left = GNUNET_TIME_absolute_get_remaining (queue->timeout);
264 if (0 != left.rel_value_us)
265 {
266 /* not actually our turn yet, but let's at least update
267 the monitor, it may think we're about to die ... */
268 queue->timeout_task =
269 GNUNET_SCHEDULER_add_delayed (left, &queue_timeout, queue);
270 return;
271 }
272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
273 "Queue %p was idle for %s, disconnecting\n",
274 queue,
275 GNUNET_STRINGS_relative_time_to_string (
276 GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
277 GNUNET_YES));
278 queue_destroy (queue);
279}
280
281
282/**
283 * Increment queue timeout due to activity. We do not immediately
284 * notify the monitor here as that might generate excessive
285 * signalling.
286 *
287 * @param queue queue for which the timeout should be rescheduled
288 */
289static void
290reschedule_queue_timeout (struct Queue *queue)
291{
292 GNUNET_assert (NULL != queue->timeout_task);
293 queue->timeout =
294 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
295}
296
297
298/**
299 * Convert unix path to a `struct sockaddr_un *`
300 *
301 * @param unixpath path to convert
302 * @param[out] sock_len set to the length of the address
303 * @param is_abstract is this an abstract @a unixpath
304 * @return converted unix path
305 */
306static struct sockaddr_un *
307unix_address_to_sockaddr (const char *unixpath, socklen_t *sock_len)
308{
309 struct sockaddr_un *un;
310 size_t slen;
311
312 GNUNET_assert (0 < strlen (unixpath)); /* sanity check */
313 un = GNUNET_new (struct sockaddr_un);
314 un->sun_family = AF_UNIX;
315 slen = strlen (unixpath);
316 if (slen >= sizeof(un->sun_path))
317 slen = sizeof(un->sun_path) - 1;
318 GNUNET_memcpy (un->sun_path, unixpath, slen);
319 un->sun_path[slen] = '\0';
320 slen = sizeof(struct sockaddr_un);
321#if HAVE_SOCKADDR_UN_SUN_LEN
322 un->sun_len = (u_char) slen;
323#endif
324 (*sock_len) = slen;
325 if ('@' == un->sun_path[0])
326 un->sun_path[0] = '\0';
327 return un;
328}
329
330
331/**
332 * Closure to #lookup_queue_it().
333 */
334struct LookupCtx
335{
336 /**
337 * Location to store the queue, if found.
338 */
339 struct Queue *res;
340
341 /**
342 * Address we are looking for.
343 */
344 const struct sockaddr_un *un;
345
346 /**
347 * Number of bytes in @a un
348 */
349 socklen_t un_len;
350};
351
352
353/**
354 * Function called to find a queue by address.
355 *
356 * @param cls the `struct LookupCtx *`
357 * @param key peer we are looking for (unused)
358 * @param value a queue
359 * @return #GNUNET_YES if not found (continue looking), #GNUNET_NO on success
360 */
361static int
362lookup_queue_it (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
363{
364 struct LookupCtx *lctx = cls;
365 struct Queue *queue = value;
366
367 if ((queue->address_len == lctx->un_len) &&
368 (0 == memcmp (lctx->un, queue->address, queue->address_len)))
369 {
370 lctx->res = queue;
371 return GNUNET_NO;
372 }
373 return GNUNET_YES;
374}
375
376
377/**
378 * Find an existing queue by address.
379 *
380 * @param plugin the plugin
381 * @param address the address to find
382 * @return NULL if queue was not found
383 */
384static struct Queue *
385lookup_queue (const struct GNUNET_PeerIdentity *peer,
386 const struct sockaddr_un *un,
387 socklen_t un_len)
388{
389 struct LookupCtx lctx;
390
391 lctx.un = un;
392 lctx.un_len = un_len;
393 lctx.res = NULL;
394 GNUNET_CONTAINER_multipeermap_get_multiple (queue_map,
395 peer,
396 &lookup_queue_it,
397 &lctx);
398 return lctx.res;
399}
400
401
402/**
403 * We have been notified that our socket is ready to write.
404 * Then reschedule this function to be called again once more is available.
405 *
406 * @param cls NULL
407 */
408static void
409select_write_cb (void *cls)
410{
411 struct Queue *queue = queue_tail;
412 const struct GNUNET_MessageHeader *msg = &queue->msg->header;
413 size_t msg_size = ntohs (msg->size);
414 ssize_t sent;
415
416 /* take queue of the ready list */
417 write_task = NULL;
418resend:
419 /* Send the data */
420 sent = GNUNET_NETWORK_socket_sendto (unix_sock,
421 msg,
422 msg_size,
423 (const struct sockaddr *) queue->address,
424 queue->address_len);
425 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
426 "UNIX transmitted message to %s (%d/%u: %s)\n",
427 GNUNET_i2s (&queue->target),
428 (int) sent,
429 (unsigned int) msg_size,
430 (sent < 0) ? strerror (errno) : "ok");
431 if (-1 != sent)
432 {
433 GNUNET_CONTAINER_DLL_remove (queue_head, queue_tail, queue);
434 if (NULL != queue_head)
435 write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
436 unix_sock,
437 &select_write_cb,
438 NULL);
439
440 /* send 'msg' */
441 GNUNET_free (queue->msg);
442 queue->msg = NULL;
443 GNUNET_MQ_impl_send_continue (queue->mq);
444 GNUNET_STATISTICS_update (stats,
445 "# bytes sent",
446 (long long) sent,
447 GNUNET_NO);
448 reschedule_queue_timeout (queue);
449 return; /* all good */
450 }
451 GNUNET_STATISTICS_update (stats,
452 "# network transmission failures",
453 1,
454 GNUNET_NO);
455 write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
456 unix_sock,
457 &select_write_cb,
458 NULL);
459 switch (errno)
460 {
461 case EAGAIN:
462 case ENOBUFS:
463 /* We should retry later... */
464 GNUNET_log_strerror (GNUNET_ERROR_TYPE_DEBUG, "send");
465 return;
466
467 case EMSGSIZE: {
468 socklen_t size = 0;
469 socklen_t len = sizeof(size);
470
471 GNUNET_NETWORK_socket_getsockopt (unix_sock,
472 SOL_SOCKET,
473 SO_SNDBUF,
474 &size,
475 &len);
476 if (size > ntohs (msg->size))
477 {
478 /* Buffer is bigger than message: error, no retry
479 * This should never happen!*/
480 GNUNET_break (0);
481 return;
482 }
483 GNUNET_log (
484 GNUNET_ERROR_TYPE_WARNING,
485 "Trying to increase socket buffer size from %u to %u for message size %u\n",
486 (unsigned int) size,
487 (unsigned int) ((msg_size / 1000) + 2) * 1000,
488 (unsigned int) msg_size);
489 size = ((msg_size / 1000) + 2) * 1000;
490 if (GNUNET_OK == GNUNET_NETWORK_socket_setsockopt (unix_sock,
491 SOL_SOCKET,
492 SO_SNDBUF,
493 &size,
494 sizeof(size)))
495 goto resend; /* Increased buffer size, retry sending */
496 /* Ok, then just try very modest increase */
497 size = msg_size;
498 if (GNUNET_OK == GNUNET_NETWORK_socket_setsockopt (unix_sock,
499 SOL_SOCKET,
500 SO_SNDBUF,
501 &size,
502 sizeof(size)))
503 goto resend; /* Increased buffer size, retry sending */
504 /* Could not increase buffer size: error, no retry */
505 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
506 return;
507 }
508
509 default:
510 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "send");
511 return;
512 }
513}
514
515
516/**
517 * Signature of functions implementing the sending functionality of a
518 * message queue.
519 *
520 * @param mq the message queue
521 * @param msg the message to send
522 * @param impl_state our `struct Queue`
523 */
524static void
525mq_send (struct GNUNET_MQ_Handle *mq,
526 const struct GNUNET_MessageHeader *msg,
527 void *impl_state)
528{
529 struct Queue *queue = impl_state;
530 size_t msize = ntohs (msg->size);
531
532 GNUNET_assert (mq == queue->mq);
533 GNUNET_assert (NULL == queue->msg);
534 // Convert to UNIXMessage
535 queue->msg = GNUNET_malloc (msize + sizeof (struct UNIXMessage));
536 queue->msg->header.size = htons (msize + sizeof (struct UNIXMessage));
537 queue->msg->sender = my_identity;
538 memcpy (&queue->msg[1], msg, msize);
539 GNUNET_CONTAINER_DLL_insert (queue_head, queue_tail, queue);
540 GNUNET_assert (NULL != unix_sock);
541 if (NULL == write_task)
542 write_task = GNUNET_SCHEDULER_add_write_net (GNUNET_TIME_UNIT_FOREVER_REL,
543 unix_sock,
544 &select_write_cb,
545 NULL);
546}
547
548
549/**
550 * Signature of functions implementing the destruction of a message
551 * queue. Implementations must not free @a mq, but should take care
552 * of @a impl_state.
553 *
554 * @param mq the message queue to destroy
555 * @param impl_state our `struct Queue`
556 */
557static void
558mq_destroy (struct GNUNET_MQ_Handle *mq, void *impl_state)
559{
560 struct Queue *queue = impl_state;
561
562 if (mq == queue->mq)
563 {
564 queue->mq = NULL;
565 queue_destroy (queue);
566 }
567}
568
569
570/**
571 * Implementation function that cancels the currently sent message.
572 *
573 * @param mq message queue
574 * @param impl_state our `struct Queue`
575 */
576static void
577mq_cancel (struct GNUNET_MQ_Handle *mq, void *impl_state)
578{
579 struct Queue *queue = impl_state;
580
581 GNUNET_assert (NULL != queue->msg);
582 queue->msg = NULL;
583 GNUNET_CONTAINER_DLL_remove (queue_head, queue_tail, queue);
584 GNUNET_assert (NULL != write_task);
585 if (NULL == queue_head)
586 {
587 GNUNET_SCHEDULER_cancel (write_task);
588 write_task = NULL;
589 }
590}
591
592
593/**
594 * Generic error handler, called with the appropriate
595 * error code and the same closure specified at the creation of
596 * the message queue.
597 * Not every message queue implementation supports an error handler.
598 *
599 * @param cls our `struct Queue`
600 * @param error error code
601 */
602static void
603mq_error (void *cls, enum GNUNET_MQ_Error error)
604{
605 struct Queue *queue = cls;
606
607 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
608 "UNIX MQ error in queue to %s: %d\n",
609 GNUNET_i2s (&queue->target),
610 (int) error);
611 queue_destroy (queue);
612}
613
614
615/**
616 * Creates a new outbound queue the transport service will use to send
617 * data to another peer.
618 *
619 * @param peer the target peer
620 * @param cs inbound or outbound queue
621 * @param un the address
622 * @param un_len number of bytes in @a un
623 * @return the queue or NULL of max connections exceeded
624 */
625static struct Queue *
626setup_queue (const struct GNUNET_PeerIdentity *target,
627 enum GNUNET_TRANSPORT_ConnectionStatus cs,
628 const struct sockaddr_un *un,
629 socklen_t un_len)
630{
631 struct Queue *queue;
632
633 queue = GNUNET_new (struct Queue);
634 queue->target = *target;
635 queue->address = GNUNET_memdup (un, un_len);
636 queue->address_len = un_len;
637 (void) GNUNET_CONTAINER_multipeermap_put (
638 queue_map,
639 &queue->target,
640 queue,
641 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
642 GNUNET_STATISTICS_set (stats,
643 "# queues active",
644 GNUNET_CONTAINER_multipeermap_size (queue_map),
645 GNUNET_NO);
646 queue->timeout =
647 GNUNET_TIME_relative_to_absolute (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
648 queue->timeout_task =
649 GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
650 &queue_timeout,
651 queue);
652 queue->mq = GNUNET_MQ_queue_for_callbacks (&mq_send,
653 &mq_destroy,
654 &mq_cancel,
655 queue,
656 NULL,
657 &mq_error,
658 queue);
659 {
660 char *foreign_addr;
661
662 if ('\0' == un->sun_path[0])
663 GNUNET_asprintf (&foreign_addr,
664 "%s-@%s",
665 COMMUNICATOR_ADDRESS_PREFIX,
666 &un->sun_path[1]);
667 else
668 GNUNET_asprintf (&foreign_addr,
669 "%s-%s",
670 COMMUNICATOR_ADDRESS_PREFIX,
671 un->sun_path);
672 queue->qh = GNUNET_TRANSPORT_communicator_mq_add (ch,
673 &queue->target,
674 foreign_addr,
675 UNIX_MTU - sizeof (struct
676 UNIXMessage),
677 GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED,
678 0,
679 GNUNET_NT_LOOPBACK,
680 cs,
681 queue->mq);
682 GNUNET_free (foreign_addr);
683 }
684 return queue;
685}
686
687
688/**
689 * We have been notified that our socket has something to read. Do the
690 * read and reschedule this function to be called again once more is
691 * available.
692 *
693 * @param cls NULL
694 */
695static void
696select_read_cb (void *cls);
697
698
699/**
700 * Function called when message was successfully passed to
701 * transport service. Continue read activity.
702 *
703 * @param cls NULL
704 * @param success #GNUNET_OK on success
705 */
706static void
707receive_complete_cb (void *cls, int success)
708{
709 (void) cls;
710 delivering_messages--;
711 if (GNUNET_OK != success)
712 GNUNET_STATISTICS_update (stats,
713 "# transport transmission failures",
714 1,
715 GNUNET_NO);
716 if ((NULL == read_task) && (delivering_messages < max_queue_length) &&
717 (NULL != unix_sock))
718 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
719 unix_sock,
720 &select_read_cb,
721 NULL);
722}
723
724
725/**
726 * We have been notified that our socket has something to read. Do the
727 * read and reschedule this function to be called again once more is
728 * available.
729 *
730 * @param cls NULL
731 */
732static void
733select_read_cb (void *cls)
734{
735 char buf[65536] GNUNET_ALIGN;
736 struct Queue *queue;
737 const struct UNIXMessage *msg;
738 struct sockaddr_un un;
739 socklen_t addrlen;
740 ssize_t ret;
741 uint16_t msize;
742
743 GNUNET_assert (NULL != unix_sock);
744 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
745 unix_sock,
746 &select_read_cb,
747 NULL);
748 addrlen = sizeof(un);
749 memset (&un, 0, sizeof(un));
750 ret = GNUNET_NETWORK_socket_recvfrom (unix_sock,
751 buf,
752 sizeof(buf),
753 (struct sockaddr *) &un,
754 &addrlen);
755 if ((-1 == ret) && ((EAGAIN == errno) || (ENOBUFS == errno)))
756 return;
757 if (-1 == ret)
758 {
759 GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
760 return;
761 }
762 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
763 "Read %d bytes from socket %s\n",
764 (int) ret,
765 un.sun_path);
766 GNUNET_assert (AF_UNIX == (un.sun_family));
767 msg = (struct UNIXMessage *) buf;
768 msize = ntohs (msg->header.size);
769 if ((msize < sizeof(struct UNIXMessage)) || (msize > ret))
770 {
771 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
772 "Wrong message size: %d bytes\n",
773 msize);
774 GNUNET_break_op (0);
775 return;
776 }
777 queue = lookup_queue (&msg->sender, &un, addrlen);
778 if (NULL == queue)
779 queue =
780 setup_queue (&msg->sender, GNUNET_TRANSPORT_CS_INBOUND, &un, addrlen);
781 else
782 reschedule_queue_timeout (queue);
783 if (NULL == queue)
784 {
785 GNUNET_log (
786 GNUNET_ERROR_TYPE_ERROR,
787 _ (
788 "Maximum number of UNIX connections exceeded, dropping incoming message\n"));
789 return;
790 }
791
792 {
793 uint16_t tsize = msize - sizeof(struct UNIXMessage);
794
795 const struct GNUNET_MessageHeader *currhdr;
796 struct GNUNET_MessageHeader al_hdr;
797
798 currhdr = (const struct GNUNET_MessageHeader *) &msg[1];
799 /* ensure aligned access */
800 memcpy (&al_hdr, currhdr, sizeof(al_hdr));
801 if ((tsize < sizeof(struct GNUNET_MessageHeader)) ||
802 (tsize != ntohs (al_hdr.size)))
803 {
804 GNUNET_break_op (0);
805 return;
806 }
807 ret = GNUNET_TRANSPORT_communicator_receive (ch,
808 &msg->sender,
809 currhdr,
810 GNUNET_TIME_UNIT_FOREVER_REL,
811 &receive_complete_cb,
812 NULL);
813 if (GNUNET_SYSERR == ret)
814 {
815 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
816 "Transport not up!\n");
817 return; /* transport not up */
818 }
819 if (GNUNET_NO == ret)
820 {
821 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
822 "Error sending message to transport\n");
823 return;
824 }
825 delivering_messages++;
826 }
827 if (delivering_messages >= max_queue_length)
828 {
829 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
830 "Back pressure %llu\n", delivering_messages);
831
832 /* we should try to apply 'back pressure' */
833 GNUNET_SCHEDULER_cancel (read_task);
834 read_task = NULL;
835 }
836}
837
838
839/**
840 * Function called by the transport service to initialize a
841 * message queue given address information about another peer.
842 * If and when the communication channel is established, the
843 * communicator must call #GNUNET_TRANSPORT_communicator_mq_add()
844 * to notify the service that the channel is now up. It is
845 * the responsibility of the communicator to manage sane
846 * retries and timeouts for any @a peer/@a address combination
847 * provided by the transport service. Timeouts and retries
848 * do not need to be signalled to the transport service.
849 *
850 * @param cls closure
851 * @param peer identity of the other peer
852 * @param address where to send the message, human-readable
853 * communicator-specific format, 0-terminated, UTF-8
854 * @return #GNUNET_OK on success, #GNUNET_SYSERR if the provided address is invalid
855 */
856static int
857mq_init (void *cls, const struct GNUNET_PeerIdentity *peer, const char *address)
858{
859 struct Queue *queue;
860 const char *path;
861 struct sockaddr_un *un;
862 socklen_t un_len;
863
864 (void) cls;
865 if (0 != strncmp (address,
866 COMMUNICATOR_ADDRESS_PREFIX "-",
867 strlen (COMMUNICATOR_ADDRESS_PREFIX "-")))
868 {
869 GNUNET_break_op (0);
870 return GNUNET_SYSERR;
871 }
872 path = &address[strlen (COMMUNICATOR_ADDRESS_PREFIX "-")];
873 un = unix_address_to_sockaddr (path, &un_len);
874 queue = lookup_queue (peer, un, un_len);
875 if (NULL != queue)
876 {
877 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
878 "Address `%s' for %s ignored, queue exists\n",
879 path,
880 GNUNET_i2s (peer));
881 GNUNET_free (un);
882 return GNUNET_OK;
883 }
884 queue = setup_queue (peer, GNUNET_TRANSPORT_CS_OUTBOUND, un, un_len);
885 GNUNET_free (un);
886 if (NULL == queue)
887 {
888 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
889 "Failed to setup queue to %s at `%s'\n",
890 GNUNET_i2s (peer),
891 path);
892 return GNUNET_NO;
893 }
894 return GNUNET_OK;
895}
896
897
898/**
899 * Iterator over all message queues to clean up.
900 *
901 * @param cls NULL
902 * @param target unused
903 * @param value the queue to destroy
904 * @return #GNUNET_OK to continue to iterate
905 */
906static int
907get_queue_delete_it (void *cls,
908 const struct GNUNET_PeerIdentity *target,
909 void *value)
910{
911 struct Queue *queue = value;
912
913 (void) cls;
914 (void) target;
915 queue_destroy (queue);
916 return GNUNET_OK;
917}
918
919
920/**
921 * Shutdown the UNIX communicator.
922 *
923 * @param cls NULL (always)
924 */
925static void
926do_shutdown (void *cls)
927{
928 if (NULL != read_task)
929 {
930 GNUNET_SCHEDULER_cancel (read_task);
931 read_task = NULL;
932 }
933 if (NULL != write_task)
934 {
935 GNUNET_SCHEDULER_cancel (write_task);
936 write_task = NULL;
937 }
938 if (NULL != unix_sock)
939 {
940 GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (unix_sock));
941 unix_sock = NULL;
942 }
943 GNUNET_CONTAINER_multipeermap_iterate (queue_map, &get_queue_delete_it, NULL);
944 GNUNET_CONTAINER_multipeermap_destroy (queue_map);
945 if (NULL != ai)
946 {
947 GNUNET_TRANSPORT_communicator_address_remove (ai);
948 ai = NULL;
949 }
950 if (NULL != ch)
951 {
952 GNUNET_TRANSPORT_communicator_disconnect (ch);
953 ch = NULL;
954 }
955 if (NULL != stats)
956 {
957 GNUNET_STATISTICS_destroy (stats, GNUNET_NO);
958 stats = NULL;
959 }
960}
961
962
963/**
964 * Function called when the transport service has received an
965 * acknowledgement for this communicator (!) via a different return
966 * path.
967 *
968 * Not applicable for UNIX.
969 *
970 * @param cls closure
971 * @param sender which peer sent the notification
972 * @param msg payload
973 */
974static void
975enc_notify_cb (void *cls,
976 const struct GNUNET_PeerIdentity *sender,
977 const struct GNUNET_MessageHeader *msg)
978{
979 (void) cls;
980 (void) sender;
981 (void) msg;
982 GNUNET_break_op (0);
983}
984
985
986/**
987 * Setup communicator and launch network interactions.
988 *
989 * @param cls NULL (always)
990 * @param args remaining command-line arguments
991 * @param cfgfile name of the configuration file used (for saving, can be NULL!)
992 * @param cfg configuration
993 */
994static void
995run (void *cls,
996 char *const *args,
997 const char *cfgfile,
998 const struct GNUNET_CONFIGURATION_Handle *cfg)
999{
1000 char *unix_socket_path;
1001 struct sockaddr_un *un;
1002 socklen_t un_len;
1003 char *my_addr;
1004 struct GNUNET_CRYPTO_EddsaPrivateKey *my_private_key;
1005
1006 (void) cls;
1007 delivering_messages = 0;
1008
1009 my_private_key = GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg);
1010 if (NULL == my_private_key)
1011 {
1012 GNUNET_log (
1013 GNUNET_ERROR_TYPE_ERROR,
1014 _ (
1015 "UNIX communicator is lacking key configuration settings. Exiting.\n"));
1016 GNUNET_SCHEDULER_shutdown ();
1017 return;
1018 }
1019 GNUNET_CRYPTO_eddsa_key_get_public (my_private_key, &my_identity.public_key);
1020
1021 if (GNUNET_OK !=
1022 GNUNET_CONFIGURATION_get_value_filename (cfg,
1023 COMMUNICATOR_CONFIG_SECTION,
1024 "UNIXPATH",
1025 &unix_socket_path))
1026 {
1027 GNUNET_log_config_missing (GNUNET_ERROR_TYPE_ERROR,
1028 COMMUNICATOR_CONFIG_SECTION,
1029 "UNIXPATH");
1030 return;
1031 }
1032 if (GNUNET_OK !=
1033 GNUNET_CONFIGURATION_get_value_number (cfg,
1034 COMMUNICATOR_CONFIG_SECTION,
1035 "MAX_QUEUE_LENGTH",
1036 &max_queue_length))
1037 max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
1038
1039 un = unix_address_to_sockaddr (unix_socket_path, &un_len);
1040 if (NULL == un)
1041 {
1042 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1043 "Failed to setup UNIX domain socket address with path `%s'\n",
1044 unix_socket_path);
1045 GNUNET_free (unix_socket_path);
1046 return;
1047 }
1048 unix_sock = GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
1049 if (NULL == unix_sock)
1050 {
1051 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
1052 GNUNET_free (un);
1053 GNUNET_free (unix_socket_path);
1054 return;
1055 }
1056 if (('\0' != un->sun_path[0]) &&
1057 (GNUNET_OK != GNUNET_DISK_directory_create_for_file (un->sun_path)))
1058 {
1059 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1060 _ ("Cannot create path to `%s'\n"),
1061 un->sun_path);
1062 GNUNET_NETWORK_socket_close (unix_sock);
1063 unix_sock = NULL;
1064 GNUNET_free (un);
1065 GNUNET_free (unix_socket_path);
1066 return;
1067 }
1068 if (GNUNET_OK != GNUNET_NETWORK_socket_bind (unix_sock,
1069 (const struct sockaddr *) un,
1070 un_len))
1071 {
1072 GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "bind", un->sun_path);
1073 GNUNET_NETWORK_socket_close (unix_sock);
1074 unix_sock = NULL;
1075 GNUNET_free (un);
1076 GNUNET_free (unix_socket_path);
1077 return;
1078 }
1079 GNUNET_free (un);
1080 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Bound to `%s'\n", unix_socket_path);
1081 stats = GNUNET_STATISTICS_create ("C-UNIX", cfg);
1082 GNUNET_SCHEDULER_add_shutdown (&do_shutdown, NULL);
1083 read_task = GNUNET_SCHEDULER_add_read_net (GNUNET_TIME_UNIT_FOREVER_REL,
1084 unix_sock,
1085 &select_read_cb,
1086 NULL);
1087 queue_map = GNUNET_CONTAINER_multipeermap_create (10, GNUNET_NO);
1088 ch = GNUNET_TRANSPORT_communicator_connect (cfg,
1089 COMMUNICATOR_CONFIG_SECTION,
1090 COMMUNICATOR_ADDRESS_PREFIX,
1091 GNUNET_TRANSPORT_CC_RELIABLE,
1092 &mq_init,
1093 NULL,
1094 &enc_notify_cb,
1095 NULL);
1096 if (NULL == ch)
1097 {
1098 GNUNET_break (0);
1099 GNUNET_SCHEDULER_shutdown ();
1100 GNUNET_free (unix_socket_path);
1101 return;
1102 }
1103 GNUNET_asprintf (&my_addr,
1104 "%s-%s",
1105 COMMUNICATOR_ADDRESS_PREFIX,
1106 unix_socket_path);
1107 GNUNET_free (unix_socket_path);
1108 ai = GNUNET_TRANSPORT_communicator_address_add (ch,
1109 my_addr,
1110 GNUNET_NT_LOOPBACK,
1111 GNUNET_TIME_UNIT_FOREVER_REL);
1112 GNUNET_free (my_addr);
1113}
1114
1115
1116/**
1117 * The main function for the UNIX communicator.
1118 *
1119 * @param argc number of arguments from the command line
1120 * @param argv command line arguments
1121 * @return 0 ok, 1 on error
1122 */
1123int
1124main (int argc, char *const *argv)
1125{
1126 static const struct GNUNET_GETOPT_CommandLineOption options[] = {
1127 GNUNET_GETOPT_OPTION_END
1128 };
1129 int ret;
1130
1131 if (GNUNET_OK != GNUNET_STRINGS_get_utf8_args (argc, argv, &argc, &argv))
1132 return 2;
1133
1134 ret = (GNUNET_OK ==
1135 GNUNET_PROGRAM_run (argc,
1136 argv,
1137 "gnunet-communicator-unix",
1138 _ ("GNUnet UNIX domain socket communicator"),
1139 options,
1140 &run,
1141 NULL))
1142 ? 0
1143 : 1;
1144 GNUNET_free_nz ((void *) argv);
1145 return ret;
1146}
1147
1148
1149#if defined(__linux__) && defined(__GLIBC__)
1150#include <malloc.h>
1151
1152/**
1153 * MINIMIZE heap size (way below 128k) since this process doesn't need much.
1154 */
1155void __attribute__ ((constructor))
1156GNUNET_TRANSPORT_communicator_unix_memory_init ()
1157{
1158 mallopt (M_TRIM_THRESHOLD, 4 * 1024);
1159 mallopt (M_TOP_PAD, 1 * 1024);
1160 malloc_trim (0);
1161}
1162
1163
1164#endif
1165
1166/* end of gnunet-communicator-unix.c */
diff --git a/src/service/transport/gnunet-service-transport.c b/src/service/transport/gnunet-service-transport.c
new file mode 100644
index 000000000..17013ce8f
--- /dev/null
+++ b/src/service/transport/gnunet-service-transport.c
@@ -0,0 +1,12664 @@
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-transport.c
22 * @brief main for gnunet-service-transport
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_nat_service.h"
81#include "gnunet_hello_uri_lib.h"
82#include "gnunet_signatures.h"
83#include "transport.h"
84
85/**
86 * Size of ring buffer to cache CORE and forwarded DVBox messages.
87 */
88#define RING_BUFFER_SIZE 16
89
90/**
91 * Maximum number of FC retransmissions for a running retransmission task.
92 */
93#define MAX_FC_RETRANSMIT_COUNT 1000
94
95/**
96 * Maximum number of messages we acknowledge together in one
97 * cumulative ACK. Larger values may save a bit of bandwidth.
98 */
99#define MAX_CUMMULATIVE_ACKS 64
100
101/**
102 * What is the 1:n chance that we send a Flow control response when
103 * receiving a flow control message that did not change anything for
104 * us? Basically, this is used in the case where both peers are stuck
105 * on flow control (no window changes), but one might continue sending
106 * flow control messages to the other peer as the first FC message
107 * when things stalled got lost, and then subsequently the other peer
108 * does *usually* not respond as nothing changed. So to ensure that
109 * eventually the FC messages stop, we do send with 1/8th probability
110 * an FC message even if nothing changed. That prevents one peer
111 * being stuck in sending (useless) FC messages "forever".
112 */
113#define FC_NO_CHANGE_REPLY_PROBABILITY 8
114
115/**
116 * What is the size we assume for a read operation in the
117 * absence of an MTU for the purpose of flow control?
118 */
119#define IN_PACKET_SIZE_WITHOUT_MTU 128
120
121/**
122 * Number of slots we keep of historic data for computation of
123 * goodput / message loss ratio.
124 */
125#define GOODPUT_AGING_SLOTS 4
126
127/**
128 * How big is the flow control window size by default;
129 * limits per-neighbour RAM utilization.
130 */
131#define DEFAULT_WINDOW_SIZE (128 * 1024)
132
133/**
134 * For how many incoming connections do we try to create a
135 * virtual link for (at the same time!). This does NOT
136 * limit the number of incoming connections, just the number
137 * for which we are actively trying to find working addresses
138 * in the absence (!) of our own applications wanting the
139 * link to go up.
140 */
141#define MAX_INCOMING_REQUEST 16
142
143/**
144 * Maximum number of peers we select for forwarding DVInit
145 * messages at the same time (excluding initiator).
146 */
147#define MAX_DV_DISCOVERY_SELECTION 16
148
149/**
150 * Window size. How many messages to the same target do we pass
151 * to CORE without a RECV_OK in between? Small values limit
152 * thoughput, large values will increase latency.
153 *
154 * FIXME-OPTIMIZE: find out what good values are experimentally,
155 * maybe set adaptively (i.e. to observed available bandwidth).
156 */
157#define RECV_WINDOW_SIZE 4
158
159/**
160 * Minimum number of hops we should forward DV learn messages
161 * even if they are NOT useful for us in hope of looping
162 * back to the initiator?
163 *
164 * FIXME: allow initiator some control here instead?
165 */
166#define MIN_DV_PATH_LENGTH_FOR_INITIATOR 3
167
168/**
169 * Maximum DV distance allowed ever.
170 */
171#define MAX_DV_HOPS_ALLOWED 16
172
173/**
174 * Maximum number of DV learning activities we may
175 * have pending at the same time.
176 */
177#define MAX_DV_LEARN_PENDING 64
178
179/**
180 * Maximum number of DV paths we keep simultaneously to the same target.
181 */
182#define MAX_DV_PATHS_TO_TARGET 3
183
184/**
185 * If a queue delays the next message by more than this number
186 * of seconds we log a warning. Note: this is for testing,
187 * the value chosen here might be too aggressively low!
188 */
189#define DELAY_WARN_THRESHOLD \
190 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
191
192/**
193 * If a DVBox could not be forwarded after this number of
194 * seconds we drop it.
195 */
196#define DV_FORWARD_TIMEOUT \
197 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
198
199/**
200 * Default value for how long we wait for reliability ack.
201 */
202#define DEFAULT_ACK_WAIT_DURATION \
203 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
204
205/**
206 * We only consider queues as "quality" connections when
207 * suppressing the generation of DV initiation messages if
208 * the latency of the queue is below this threshold.
209 */
210#define DV_QUALITY_RTT_THRESHOLD \
211 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
212
213/**
214 * How long do we consider a DV path valid if we see no
215 * further updates on it? Note: the value chosen here might be too low!
216 */
217#define DV_PATH_VALIDITY_TIMEOUT \
218 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
219
220/**
221 * How long do we cache backchannel (struct Backtalker) information
222 * after a backchannel goes inactive?
223 */
224#define BACKCHANNEL_INACTIVITY_TIMEOUT \
225 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
226
227/**
228 * How long before paths expire would we like to (re)discover DV paths? Should
229 * be below #DV_PATH_VALIDITY_TIMEOUT.
230 */
231#define DV_PATH_DISCOVERY_FREQUENCY \
232 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
233
234/**
235 * How long are ephemeral keys valid?
236 */
237#define EPHEMERAL_VALIDITY \
238 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
239
240/**
241 * How long do we keep partially reassembled messages around before giving up?
242 */
243#define REASSEMBLY_EXPIRATION \
244 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 4)
245
246/**
247 * What is the fastest rate at which we send challenges *if* we keep learning
248 * an address (gossip, DHT, etc.)?
249 */
250#define FAST_VALIDATION_CHALLENGE_FREQ \
251 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
252
253/**
254 * What is the slowest rate at which we send challenges?
255 */
256#define MAX_VALIDATION_CHALLENGE_FREQ \
257 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_DAYS, 1)
258
259/**
260 * How long until we forget about historic accumulators and thus
261 * reset the ACK counter? Should exceed the maximum time an
262 * active connection experiences without an ACK.
263 */
264#define ACK_CUMMULATOR_TIMEOUT \
265 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
266
267/**
268 * What is the non-randomized base frequency at which we
269 * would initiate DV learn messages?
270 */
271#define DV_LEARN_BASE_FREQUENCY GNUNET_TIME_UNIT_MINUTES
272
273/**
274 * How many good connections (confirmed, bi-directional, not DV)
275 * do we need to have to suppress initiating DV learn messages?
276 */
277#define DV_LEARN_QUALITY_THRESHOLD 100
278
279/**
280 * When do we forget an invalid address for sure?
281 */
282#define MAX_ADDRESS_VALID_UNTIL \
283 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MONTHS, 1)
284
285/**
286 * How long do we consider an address valid if we just checked?
287 */
288#define ADDRESS_VALIDATION_LIFETIME \
289 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4)
290
291/**
292 * What is the maximum frequency at which we do address validation?
293 * A random value between 0 and this value is added when scheduling
294 * the #validation_task (both to ensure we do not validate too often,
295 * and to randomize a bit).
296 */
297#define MIN_DELAY_ADDRESS_VALIDATION GNUNET_TIME_UNIT_MILLISECONDS
298
299/**
300 * How many network RTTs before an address validation expires should we begin
301 * trying to revalidate? (Note that the RTT used here is the one that we
302 * experienced during the last validation, not necessarily the latest RTT
303 * observed).
304 */
305#define VALIDATION_RTT_BUFFER_FACTOR 3
306
307/**
308 * How many messages can we have pending for a given communicator
309 * process before we start to throttle that communicator?
310 *
311 * Used if a communicator might be CPU-bound and cannot handle the traffic.
312 */
313#define COMMUNICATOR_TOTAL_QUEUE_LIMIT 512
314
315/**
316 * How many messages can we have pending for a given queue (queue to
317 * a particular peer via a communicator) process before we start to
318 * throttle that queue?
319 */
320#define QUEUE_LENGTH_LIMIT 32
321
322/**
323 *
324 */
325#define QUEUE_ENTRY_TIMEOUT \
326 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
327
328
329GNUNET_NETWORK_STRUCT_BEGIN
330
331/**
332 * Unique identifier we attach to a message.
333 */
334struct MessageUUIDP
335{
336 /**
337 * Unique value, generated by incrementing the
338 * `message_uuid_ctr` of `struct Neighbour`.
339 */
340 uint64_t uuid GNUNET_PACKED;
341};
342
343
344/**
345 * Unique identifier to map an acknowledgement to a transmission.
346 */
347struct AcknowledgementUUIDP
348{
349 /**
350 * The UUID value.
351 */
352 struct GNUNET_Uuid value;
353};
354
355/**
356 * Outer layer of an encapsulated backchannel message.
357 */
358struct TransportBackchannelEncapsulationMessage
359{
360 /**
361 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION.
362 */
363 struct GNUNET_MessageHeader header;
364
365 /* Followed by *another* message header which is the message to
366 the communicator */
367
368 /* Followed by a 0-terminated name of the communicator */
369};
370
371
372/**
373 * Body by which a peer confirms that it is using an ephemeral key.
374 */
375struct EphemeralConfirmationPS
376{
377 /**
378 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
379 */
380 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
381
382 /**
383 * How long is this signature over the ephemeral key valid?
384 *
385 * Note that the receiver MUST IGNORE the absolute time, and only interpret
386 * the value as a mononic time and reject "older" values than the last one
387 * observed. This is necessary as we do not want to require synchronized
388 * clocks and may not have a bidirectional communication channel.
389 *
390 * Even with this, there is no real guarantee against replay achieved here,
391 * unless the latest timestamp is persisted. While persistence should be
392 * provided via PEERSTORE, we do not consider the mechanism reliable! Thus,
393 * communicators must protect against replay attacks when using backchannel
394 * communication!
395 */
396 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time;
397
398 /**
399 * Target's peer identity.
400 */
401 struct GNUNET_PeerIdentity target;
402
403 /**
404 * Ephemeral key setup by the sender for @e target, used
405 * to encrypt the payload.
406 */
407 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
408};
409
410
411/**
412 * Plaintext of the variable-size payload that is encrypted
413 * within a `struct TransportBackchannelEncapsulationMessage`
414 */
415struct TransportDVBoxPayloadP
416{
417 /**
418 * Sender's peer identity.
419 */
420 struct GNUNET_PeerIdentity sender;
421
422 /**
423 * Signature of the sender over an
424 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL.
425 */
426 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
427
428 /**
429 * Current monotonic time of the sending transport service. Used to
430 * detect replayed messages. Note that the receiver should remember
431 * a list of the recently seen timestamps and only reject messages
432 * if the timestamp is in the list, or the list is "full" and the
433 * timestamp is smaller than the lowest in the list.
434 *
435 * Like the @e ephemeral_validity, the list of timestamps per peer should be
436 * persisted to guard against replays after restarts.
437 */
438 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
439
440 /* Followed by a `struct GNUNET_MessageHeader` with a message
441 for the target peer */
442};
443
444
445/**
446 * Outer layer of an encapsulated unfragmented application message sent
447 * over an unreliable channel.
448 */
449struct TransportReliabilityBoxMessage
450{
451 /**
452 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX
453 */
454 struct GNUNET_MessageHeader header;
455
456 /**
457 * Number of messages still to be sent before a commulative
458 * ACK is requested. Zero if an ACK is requested immediately.
459 * In NBO. Note that the receiver may send the ACK faster
460 * if it believes that is reasonable.
461 */
462 uint32_t ack_countdown GNUNET_PACKED;
463
464 /**
465 * Unique ID of the message used for signalling receipt of
466 * messages sent over possibly unreliable channels. Should
467 * be a random.
468 */
469 struct AcknowledgementUUIDP ack_uuid;
470};
471
472
473/**
474 * Acknowledgement payload.
475 */
476struct TransportCummulativeAckPayloadP
477{
478 /**
479 * How long was the ACK delayed for generating cumulative ACKs?
480 * Used to calculate the correct network RTT by taking the receipt
481 * time of the ack minus the transmission time of the sender minus
482 * this value.
483 */
484 struct GNUNET_TIME_RelativeNBO ack_delay;
485
486 /**
487 * UUID of a message being acknowledged.
488 */
489 struct AcknowledgementUUIDP ack_uuid;
490};
491
492
493/**
494 * Confirmation that the receiver got a
495 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX. Note that the
496 * confirmation may be transmitted over a completely different queue,
497 * so ACKs are identified by a combination of PID of sender and
498 * message UUID, without the queue playing any role!
499 */
500struct TransportReliabilityAckMessage
501{
502 /**
503 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK
504 */
505 struct GNUNET_MessageHeader header;
506
507 /**
508 * Counter of ACKs transmitted by the sender to us. Incremented
509 * by one for each ACK, used to detect how many ACKs were lost.
510 */
511 uint32_t ack_counter GNUNET_PACKED;
512
513 /* followed by any number of `struct TransportCummulativeAckPayloadP`
514 messages providing ACKs */
515};
516
517
518/**
519 * Outer layer of an encapsulated fragmented application message.
520 */
521struct TransportFragmentBoxMessage
522{
523 /**
524 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT
525 */
526 struct GNUNET_MessageHeader header;
527
528 /**
529 * Offset of this fragment in the overall message.
530 */
531 uint16_t frag_off GNUNET_PACKED;
532
533 /**
534 * Total size of the message that is being fragmented.
535 */
536 uint16_t msg_size GNUNET_PACKED;
537
538 /**
539 * Unique ID of this fragment (and fragment transmission!). Will
540 * change even if a fragment is retransmitted to make each
541 * transmission attempt unique! If a client receives a duplicate
542 * fragment (same @e frag_off for same @a msg_uuid, it must send
543 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK immediately.
544 */
545 struct AcknowledgementUUIDP ack_uuid;
546
547 /**
548 * Original message ID for of the message that all the fragments
549 * belong to. Must be the same for all fragments.
550 */
551 struct MessageUUIDP msg_uuid;
552};
553
554
555/**
556 * Content signed by the initator during DV learning.
557 *
558 * The signature is required to prevent DDoS attacks. A peer sending out this
559 * message is potentially generating a lot of traffic that will go back to the
560 * initator, as peers receiving this message will try to let the initiator
561 * know that they got the message.
562 *
563 * Without this signature, an attacker could abuse this mechanism for traffic
564 * amplification, sending a lot of traffic to a peer by putting out this type
565 * of message with the victim's peer identity.
566 *
567 * Even with just a signature, traffic amplification would be possible via
568 * replay attacks. The @e monotonic_time limits such replay attacks, as every
569 * potential amplificator will check the @e monotonic_time and only respond
570 * (at most) once per message.
571 */
572struct DvInitPS
573{
574 /**
575 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
576 */
577 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
578
579 /**
580 * Time at the initiator when generating the signature.
581 *
582 * Note that the receiver MUST IGNORE the absolute time, and only interpret
583 * the value as a mononic time and reject "older" values than the last one
584 * observed. This is necessary as we do not want to require synchronized
585 * clocks and may not have a bidirectional communication channel.
586 *
587 * Even with this, there is no real guarantee against replay achieved here,
588 * unless the latest timestamp is persisted. Persistence should be
589 * provided via PEERSTORE if possible.
590 */
591 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
592
593 /**
594 * Challenge value used by the initiator to re-identify the path.
595 */
596 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
597};
598
599
600/**
601 * Content signed by each peer during DV learning.
602 *
603 * This assues the initiator of the DV learning operation that the hop from @e
604 * pred via the signing peer to @e succ actually exists. This makes it
605 * impossible for an adversary to supply the network with bogus routes.
606 *
607 * The @e challenge is included to provide replay protection for the
608 * initiator. This way, the initiator knows that the hop existed after the
609 * original @e challenge was first transmitted, providing a freshness metric.
610 *
611 * Peers other than the initiator that passively learn paths by observing
612 * these messages do NOT benefit from this. Here, an adversary may indeed
613 * replay old messages. Thus, passively learned paths should always be
614 * immediately marked as "potentially stale".
615 */
616struct DvHopPS
617{
618 /**
619 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
620 */
621 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
622
623 /**
624 * Identity of the previous peer on the path.
625 */
626 struct GNUNET_PeerIdentity pred;
627
628 /**
629 * Identity of the next peer on the path.
630 */
631 struct GNUNET_PeerIdentity succ;
632
633 /**
634 * Challenge value used by the initiator to re-identify the path.
635 */
636 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
637};
638
639
640/**
641 * An entry describing a peer on a path in a
642 * `struct TransportDVLearnMessage` message.
643 */
644struct DVPathEntryP
645{
646 /**
647 * Identity of a peer on the path.
648 */
649 struct GNUNET_PeerIdentity hop;
650
651 /**
652 * Signature of this hop over the path, of purpose
653 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP
654 */
655 struct GNUNET_CRYPTO_EddsaSignature hop_sig;
656};
657
658
659/**
660 * Internal message used by transport for distance vector learning.
661 * If @e num_hops does not exceed the threshold, peers should append
662 * themselves to the peer list and flood the message (possibly only
663 * to a subset of their neighbours to limit discoverability of the
664 * network topology). To the extend that the @e bidirectional bits
665 * are set, peers may learn the inverse paths even if they did not
666 * initiate.
667 *
668 * Unless received on a bidirectional queue and @e num_hops just
669 * zero, peers that can forward to the initator should always try to
670 * forward to the initiator.
671 */
672struct TransportDVLearnMessage
673{
674 /**
675 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN
676 */
677 struct GNUNET_MessageHeader header;
678
679 /**
680 * Number of hops this messages has travelled, in NBO. Zero if
681 * sent by initiator.
682 */
683 uint16_t num_hops GNUNET_PACKED;
684
685 /**
686 * Bitmask of the last 16 hops indicating whether they are confirmed
687 * available (without DV) in both directions or not, in NBO. Used
688 * to possibly instantly learn a path in both directions. Each peer
689 * should shift this value by one to the left, and then set the
690 * lowest bit IF the current sender can be reached from it (without
691 * DV routing).
692 */
693 uint16_t bidirectional GNUNET_PACKED;
694
695 /**
696 * Peers receiving this message and delaying forwarding to other
697 * peers for any reason should increment this value by the non-network
698 * delay created by the peer.
699 */
700 struct GNUNET_TIME_RelativeNBO non_network_delay;
701
702 /**
703 * Time at the initiator when generating the signature.
704 *
705 * Note that the receiver MUST IGNORE the absolute time, and only interpret
706 * the value as a mononic time and reject "older" values than the last one
707 * observed. This is necessary as we do not want to require synchronized
708 * clocks and may not have a bidirectional communication channel.
709 *
710 * Even with this, there is no real guarantee against replay achieved here,
711 * unless the latest timestamp is persisted. Persistence should be
712 * provided via PEERSTORE if possible.
713 */
714 struct GNUNET_TIME_AbsoluteNBO monotonic_time;
715
716 /**
717 * Signature of this hop over the path, of purpose
718 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
719 */
720 struct GNUNET_CRYPTO_EddsaSignature init_sig;
721
722 /**
723 * Identity of the peer that started this learning activity.
724 */
725 struct GNUNET_PeerIdentity initiator;
726
727 /**
728 * Challenge value used by the initiator to re-identify the path.
729 */
730 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
731
732 /* Followed by @e num_hops `struct DVPathEntryP` values,
733 excluding the initiator of the DV trace; the last entry is the
734 current sender; the current peer must not be included. */
735};
736
737
738/**
739 * Outer layer of an encapsulated message send over multiple hops.
740 * The path given only includes the identities of the subsequent
741 * peers, i.e. it will be empty if we are the receiver. Each
742 * forwarding peer should scan the list from the end, and if it can,
743 * forward to the respective peer. The list should then be shortened
744 * by all the entries up to and including that peer. Each hop should
745 * also increment @e total_hops to allow the receiver to get a precise
746 * estimate on the number of hops the message travelled. Senders must
747 * provide a learned path that thus should work, but intermediaries
748 * know of a shortcut, they are allowed to send the message via that
749 * shortcut.
750 *
751 * If a peer finds itself still on the list, it must drop the message.
752 *
753 * The payload of the box can only be decrypted and verified by the
754 * ultimate receiver. Intermediaries do not learn the sender's
755 * identity and the path the message has taken. However, the first
756 * hop does learn the sender as @e total_hops would be zero and thus
757 * the predecessor must be the origin (so this is not really useful
758 * for anonymization).
759 */
760struct TransportDVBoxMessage
761{
762 /**
763 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX
764 */
765 struct GNUNET_MessageHeader header;
766
767 /**
768 * Flag if the payload is a control message. In NBO.
769 */
770 unsigned int without_fc;
771
772 /**
773 * Number of total hops this messages travelled. In NBO.
774 * @e origin sets this to zero, to be incremented at
775 * each hop. Peers should limit the @e total_hops value
776 * they accept from other peers.
777 */
778 uint16_t total_hops GNUNET_PACKED;
779
780 /**
781 * Number of hops this messages includes. In NBO. Reduced by one
782 * or more at each hop. Peers should limit the @e num_hops value
783 * they accept from other peers.
784 */
785 uint16_t num_hops GNUNET_PACKED;
786
787 /**
788 * Ephemeral key setup by the sender for target, used to encrypt the
789 * payload. Intermediaries must not change this value.
790 */
791 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
792
793 /**
794 * We use an IV here as the @e ephemeral_key is re-used for
795 * #EPHEMERAL_VALIDITY time to avoid re-signing it all the time.
796 * Intermediaries must not change this value.
797 */
798 struct GNUNET_ShortHashCode iv;
799
800 /**
801 * HMAC over the ciphertext of the encrypted, variable-size body
802 * that follows. Verified via DH of target and @e ephemeral_key.
803 * Intermediaries must not change this value.
804 */
805 struct GNUNET_HashCode hmac;
806
807 /**
808 * Size this msg had initially. This is needed to calculate the hmac at the target.
809 * The header size can not be used for that, because the box size is getting smaller at each hop.
810 *
811 */
812 uint16_t orig_size GNUNET_PACKED;
813
814 /* Followed by @e num_hops `struct GNUNET_PeerIdentity` values;
815 excluding the @e origin and the current peer, the last must be
816 the ultimate target; if @e num_hops is zero, the receiver of this
817 message is the ultimate target. */
818
819 /* Followed by encrypted, variable-size payload, which
820 must begin with a `struct TransportDVBoxPayloadP` */
821
822 /* Followed by the actual message, which itself must not be a
823 a DV_LEARN or DV_BOX message! */
824};
825
826
827/**
828 * Message send to another peer to validate that it can indeed
829 * receive messages at a particular address.
830 */
831struct TransportValidationChallengeMessage
832{
833 /**
834 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE
835 */
836 struct GNUNET_MessageHeader header;
837
838 /**
839 * Always zero.
840 */
841 uint32_t reserved GNUNET_PACKED;
842
843 /**
844 * Challenge to be signed by the receiving peer.
845 */
846 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
847
848 /**
849 * Timestamp of the sender, to be copied into the reply to allow
850 * sender to calculate RTT. Must be monotonically increasing!
851 */
852 struct GNUNET_TIME_AbsoluteNBO sender_time;
853};
854
855
856/**
857 * Message signed by a peer to confirm that it can indeed
858 * receive messages at a particular address.
859 */
860struct TransportValidationPS
861{
862 /**
863 * Purpose is #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE
864 */
865 struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
866
867 /**
868 * How long does the sender believe the address on
869 * which the challenge was received to remain valid?
870 */
871 struct GNUNET_TIME_RelativeNBO validity_duration;
872
873 /**
874 * Challenge signed by the receiving peer.
875 */
876 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
877};
878
879
880/**
881 * Message send to a peer to respond to a
882 * #GNUNET_MESSAGE_TYPE_ADDRESS_VALIDATION_CHALLENGE
883 */
884struct TransportValidationResponseMessage
885{
886 /**
887 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE
888 */
889 struct GNUNET_MessageHeader header;
890
891 /**
892 * Always zero.
893 */
894 uint32_t reserved GNUNET_PACKED;
895
896 /**
897 * The peer's signature matching the
898 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE purpose.
899 */
900 struct GNUNET_CRYPTO_EddsaSignature signature;
901
902 /**
903 * The challenge that was signed by the receiving peer.
904 */
905 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
906
907 /**
908 * Original timestamp of the sender (was @code{sender_time}),
909 * copied into the reply to allow sender to calculate RTT.
910 */
911 struct GNUNET_TIME_AbsoluteNBO origin_time;
912
913 /**
914 * How long does the sender believe this address to remain
915 * valid?
916 */
917 struct GNUNET_TIME_RelativeNBO validity_duration;
918};
919
920struct TransportGlobalNattedAddress
921{
922 /**
923 * Length of the address following the struct in NBO.
924 */
925 unsigned int address_length;
926
927 /* Followed by @e address_length bytes of the address. */
928};
929
930/**
931 * Message for Transport-to-Transport Flow control. Specifies the size
932 * of the flow control window, including how much we believe to have
933 * consumed (at transmission time), how much we believe to be allowed
934 * (at transmission time), and how much the other peer is allowed to
935 * send to us, and how much data we already received from the other
936 * peer.
937 */
938struct TransportFlowControlMessage
939{
940 /**
941 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL
942 */
943 struct GNUNET_MessageHeader header;
944
945 /**
946 * Sequence number of the flow control message. Incremented by one
947 * for each message. Starts at zero when a virtual link goes up.
948 * Used to detect one-sided connection drops. On wrap-around, the
949 * flow control counters will be reset as if the connection had
950 * dropped.
951 */
952 uint32_t seq GNUNET_PACKED;
953
954 /**
955 * Flow control window size in bytes, in NBO.
956 * The receiver can send this many bytes at most.
957 */
958 uint64_t inbound_window_size GNUNET_PACKED;
959
960 /**
961 * How many bytes has the sender sent that count for flow control at
962 * this time. Used to allow the receiver to estimate the packet
963 * loss rate.
964 */
965 uint64_t outbound_sent GNUNET_PACKED;
966
967 /**
968 * Latest flow control window size we learned from the other peer,
969 * in bytes, in NBO. We are limited to sending at most this many
970 * bytes to the other peer. May help the other peer detect when
971 * flow control messages were lost and should thus be retransmitted.
972 * In particular, if the delta to @e outbound_sent is too small,
973 * this signals that we are stalled.
974 */
975 uint64_t outbound_window_size GNUNET_PACKED;
976
977 /**
978 * Timestamp of the sender. Must be monotonically increasing!
979 * Used to enable receiver to ignore out-of-order packets in
980 * combination with the @e seq. Note that @e seq will go down
981 * (back to zero) whenever either side believes the connection
982 * was dropped, allowing the peers to detect that they need to
983 * reset the counters for the number of bytes sent!
984 */
985 struct GNUNET_TIME_AbsoluteNBO sender_time;
986
987
988 /**
989 * Number of TransportGlobalNattedAddress following the struct.
990 */
991 unsigned int number_of_addresses;
992
993 /**
994 * Size of all the addresses attached to all TransportGlobalNattedAddress.
995 */
996 size_t size_of_addresses;
997
998 /* Followed by @e number_of_addresses struct TransportGlobalNattedAddress. */
999};
1000
1001GNUNET_NETWORK_STRUCT_END
1002
1003
1004/**
1005 * What type of client is the `struct TransportClient` about?
1006 */
1007enum ClientType
1008{
1009 /**
1010 * We do not know yet (client is fresh).
1011 */
1012 CT_NONE = 0,
1013
1014 /**
1015 * Is the CORE service, we need to forward traffic to it.
1016 */
1017 CT_CORE = 1,
1018
1019 /**
1020 * It is a monitor, forward monitor data.
1021 */
1022 CT_MONITOR = 2,
1023
1024 /**
1025 * It is a communicator, use for communication.
1026 */
1027 CT_COMMUNICATOR = 3,
1028
1029 /**
1030 * "Application" telling us where to connect (i.e. TOPOLOGY, DHT or CADET).
1031 */
1032 CT_APPLICATION = 4
1033};
1034
1035
1036/**
1037 * Which transmission options are allowable for transmission?
1038 * Interpreted bit-wise!
1039 */
1040enum RouteMessageOptions
1041{
1042 /**
1043 * Only confirmed, non-DV direct neighbours.
1044 */
1045 RMO_NONE = 0,
1046
1047 /**
1048 * We are allowed to use DV routing for this @a hdr
1049 */
1050 RMO_DV_ALLOWED = 1,
1051
1052 /**
1053 * We are allowed to use unconfirmed queues or DV routes for this message
1054 */
1055 RMO_UNCONFIRMED_ALLOWED = 2,
1056
1057 /**
1058 * Reliable and unreliable, DV and non-DV are all acceptable.
1059 */
1060 RMO_ANYTHING_GOES = (RMO_DV_ALLOWED | RMO_UNCONFIRMED_ALLOWED),
1061
1062 /**
1063 * If we have multiple choices, it is OK to send this message
1064 * over multiple channels at the same time to improve loss tolerance.
1065 * (We do at most 2 transmissions.)
1066 */
1067 RMO_REDUNDANT = 4
1068};
1069
1070
1071/**
1072 * When did we launch this DV learning activity?
1073 */
1074struct LearnLaunchEntry
1075{
1076 /**
1077 * Kept (also) in a DLL sorted by launch time.
1078 */
1079 struct LearnLaunchEntry *prev;
1080
1081 /**
1082 * Kept (also) in a DLL sorted by launch time.
1083 */
1084 struct LearnLaunchEntry *next;
1085
1086 /**
1087 * Challenge that uniquely identifies this activity.
1088 */
1089 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
1090
1091 /**
1092 * When did we transmit the DV learn message (used to calculate RTT) and
1093 * determine freshness of paths learned via this operation.
1094 */
1095 struct GNUNET_TIME_Absolute launch_time;
1096};
1097
1098
1099/**
1100 * Information we keep per #GOODPUT_AGING_SLOTS about historic
1101 * (or current) transmission performance.
1102 */
1103struct TransmissionHistoryEntry
1104{
1105 /**
1106 * Number of bytes actually sent in the interval.
1107 */
1108 uint64_t bytes_sent;
1109
1110 /**
1111 * Number of bytes received and acknowledged by the other peer in
1112 * the interval.
1113 */
1114 uint64_t bytes_received;
1115};
1116
1117
1118/**
1119 * Performance data for a transmission possibility.
1120 */
1121struct PerformanceData
1122{
1123 /**
1124 * Weighted average for the RTT.
1125 */
1126 struct GNUNET_TIME_Relative aged_rtt;
1127
1128 /**
1129 * Historic performance data, using a ring buffer of#GOODPUT_AGING_SLOTS
1130 * entries.
1131 */
1132 struct TransmissionHistoryEntry the[GOODPUT_AGING_SLOTS];
1133
1134 /**
1135 * What was the last age when we wrote to @e the? Used to clear
1136 * old entries when the age advances.
1137 */
1138 unsigned int last_age;
1139};
1140
1141
1142/**
1143 * Client connected to the transport service.
1144 */
1145struct TransportClient;
1146
1147/**
1148 * A neighbour that at least one communicator is connected to.
1149 */
1150struct Neighbour;
1151
1152/**
1153 * Entry in our #dv_routes table, representing a (set of) distance
1154 * vector routes to a particular peer.
1155 */
1156struct DistanceVector;
1157
1158/**
1159 * A queue is a message queue provided by a communicator
1160 * via which we can reach a particular neighbour.
1161 */
1162struct Queue;
1163
1164/**
1165 * Message awaiting transmission. See detailed comments below.
1166 */
1167struct PendingMessage;
1168
1169/**
1170 * One possible hop towards a DV target.
1171 */
1172struct DistanceVectorHop;
1173
1174/**
1175 * A virtual link is another reachable peer that is known to CORE. It
1176 * can be either a `struct Neighbour` with at least one confirmed
1177 * `struct Queue`, or a `struct DistanceVector` with at least one
1178 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1179 * data that is per neighbour that is not specific to how the
1180 * connectivity is established.
1181 */
1182struct VirtualLink;
1183
1184
1185/**
1186 * Context from #handle_incoming_msg(). Closure for many
1187 * message handlers below.
1188 */
1189struct CommunicatorMessageContext
1190{
1191 /**
1192 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1193 * flow control to unchoke.
1194 */
1195 struct CommunicatorMessageContext *next;
1196
1197 /**
1198 * Kept in a DLL of `struct VirtualLink` if waiting for CORE
1199 * flow control to unchoke.
1200 */
1201 struct CommunicatorMessageContext *prev;
1202
1203 /**
1204 * Which communicator provided us with the message.
1205 */
1206 struct TransportClient *tc;
1207
1208 /**
1209 * Additional information for flow control and about the sender.
1210 */
1211 struct GNUNET_TRANSPORT_IncomingMessage im;
1212
1213 /**
1214 * The message to demultiplex.
1215 */
1216 const struct GNUNET_MessageHeader *mh;
1217
1218 /**
1219 * Number of hops the message has travelled (if DV-routed).
1220 * FIXME: make use of this in ACK handling!
1221 */
1222 uint16_t total_hops;
1223
1224 /**
1225 * Did we already call GNUNET_SERVICE_client_continue and send ACK to communicator?
1226 */
1227 unsigned int continue_send;
1228};
1229
1230
1231/**
1232 * Entry for the ring buffer caching messages send to core, when virtual link is avaliable.
1233 **/
1234struct RingBufferEntry
1235{
1236 /**
1237 * Communicator context for this ring buffer entry.
1238 **/
1239 struct CommunicatorMessageContext *cmc;
1240
1241 /**
1242 * The message in this entry.
1243 **/
1244 struct GNUNET_MessageHeader *mh;
1245};
1246
1247
1248/**
1249 * Closure for #core_env_sent_cb.
1250 */
1251struct CoreSentContext
1252{
1253 /**
1254 * Kept in a DLL to clear @e vl in case @e vl is lost.
1255 */
1256 struct CoreSentContext *next;
1257
1258 /**
1259 * Kept in a DLL to clear @e vl in case @e vl is lost.
1260 */
1261 struct CoreSentContext *prev;
1262
1263 /**
1264 * Virtual link this is about.
1265 */
1266 struct VirtualLink *vl;
1267
1268 /**
1269 * How big was the message.
1270 */
1271 uint16_t size;
1272
1273 /**
1274 * By how much should we increment @e vl's
1275 * incoming_fc_window_size_used once we are done sending to CORE?
1276 * Use to ensure we do not increment twice if there is more than one
1277 * CORE client.
1278 */
1279 uint16_t isize;
1280};
1281
1282
1283/**
1284 * Information we keep for a message that we are reassembling.
1285 */
1286struct ReassemblyContext
1287{
1288 /**
1289 * Original message ID for of the message that all the fragments
1290 * belong to.
1291 */
1292 struct MessageUUIDP msg_uuid;
1293
1294 /**
1295 * Which neighbour is this context for?
1296 */
1297 struct VirtualLink *virtual_link;
1298
1299 /**
1300 * Entry in the reassembly heap (sorted by expiration).
1301 */
1302 struct GNUNET_CONTAINER_HeapNode *hn;
1303
1304 /**
1305 * Bitfield with @e msg_size bits representing the positions
1306 * where we have received fragments. When we receive a fragment,
1307 * we check the bits in @e bitfield before incrementing @e msg_missing.
1308 *
1309 * Allocated after the reassembled message.
1310 */
1311 uint8_t *bitfield;
1312
1313 /**
1314 * At what time will we give up reassembly of this message?
1315 */
1316 struct GNUNET_TIME_Absolute reassembly_timeout;
1317
1318 /**
1319 * Time we received the last fragment. @e avg_ack_delay must be
1320 * incremented by now - @e last_frag multiplied by @e num_acks.
1321 */
1322 struct GNUNET_TIME_Absolute last_frag;
1323
1324 /**
1325 * How big is the message we are reassembling in total?
1326 */
1327 uint16_t msg_size;
1328
1329 /**
1330 * How many bytes of the message are still missing? Defragmentation
1331 * is complete when @e msg_missing == 0.
1332 */
1333 uint16_t msg_missing;
1334
1335 /* Followed by @e msg_size bytes of the (partially) defragmented original
1336 * message */
1337
1338 /* Followed by @e bitfield data */
1339};
1340
1341
1342/**
1343 * A virtual link is another reachable peer that is known to CORE. It
1344 * can be either a `struct Neighbour` with at least one confirmed
1345 * `struct Queue`, or a `struct DistanceVector` with at least one
1346 * confirmed `struct DistanceVectorHop`. With a virtual link we track
1347 * data that is per neighbour that is not specific to how the
1348 * connectivity is established.
1349 */
1350struct VirtualLink
1351{
1352 /**
1353 * Identity of the peer at the other end of the link.
1354 */
1355 struct GNUNET_PeerIdentity target;
1356
1357 /**
1358 * Map with `struct ReassemblyContext` structs for fragments under
1359 * reassembly. May be NULL if we currently have no fragments from
1360 * this @e pid (lazy initialization).
1361 */
1362 struct GNUNET_CONTAINER_MultiHashMap32 *reassembly_map;
1363
1364 /**
1365 * Heap with `struct ReassemblyContext` structs for fragments under
1366 * reassembly. May be NULL if we currently have no fragments from
1367 * this @e pid (lazy initialization).
1368 */
1369 struct GNUNET_CONTAINER_Heap *reassembly_heap;
1370
1371 /**
1372 * Task to free old entries from the @e reassembly_heap and @e reassembly_map.
1373 */
1374 struct GNUNET_SCHEDULER_Task *reassembly_timeout_task;
1375
1376 /**
1377 * Communicators blocked for receiving on @e target as we are waiting
1378 * on the @e core_recv_window to increase.
1379 */
1380 struct CommunicatorMessageContext *cmc_head;
1381
1382 /**
1383 * Communicators blocked for receiving on @e target as we are waiting
1384 * on the @e core_recv_window to increase.
1385 */
1386 struct CommunicatorMessageContext *cmc_tail;
1387
1388 /**
1389 * Head of list of messages pending for this VL.
1390 */
1391 struct PendingMessage *pending_msg_head;
1392
1393 /**
1394 * Tail of list of messages pending for this VL.
1395 */
1396 struct PendingMessage *pending_msg_tail;
1397
1398 /**
1399 * Kept in a DLL to clear @e vl in case @e vl is lost.
1400 */
1401 struct CoreSentContext *csc_tail;
1402
1403 /**
1404 * Kept in a DLL to clear @e vl in case @e vl is lost.
1405 */
1406 struct CoreSentContext *csc_head;
1407
1408 /**
1409 * Task scheduled to possibly notfiy core that this peer is no
1410 * longer counting as confirmed. Runs the #core_visibility_check(),
1411 * which checks that some DV-path or a queue exists that is still
1412 * considered confirmed.
1413 */
1414 struct GNUNET_SCHEDULER_Task *visibility_task;
1415
1416 /**
1417 * Task scheduled to periodically retransmit FC messages (in
1418 * case one got lost).
1419 */
1420 struct GNUNET_SCHEDULER_Task *fc_retransmit_task;
1421
1422 /**
1423 * Number of FC retransmissions for this running task.
1424 */
1425 unsigned int fc_retransmit_count;
1426
1427 /**
1428 * Is this VirtualLink confirmed.
1429 * A unconfirmed VirtualLink might exist, if we got a FC from that target.
1430 */
1431 unsigned int confirmed;
1432
1433 /**
1434 * Neighbour used by this virtual link, NULL if @e dv is used.
1435 */
1436 struct Neighbour *n;
1437
1438 /**
1439 * Distance vector used by this virtual link, NULL if @e n is used.
1440 */
1441 struct DistanceVector *dv;
1442
1443 /**
1444 * Sender timestamp of @e n_challenge, used to generate out-of-order
1445 * challenges (as sender's timestamps must be monotonically
1446 * increasing). FIXME: where do we need this?
1447 */
1448 struct GNUNET_TIME_Absolute n_challenge_time;
1449
1450 /**
1451 * When did we last send a
1452 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message?
1453 * Used to determine whether it is time to re-transmit the message.
1454 */
1455 struct GNUNET_TIME_Absolute last_fc_transmission;
1456
1457 /**
1458 * Sender timestamp of the last
1459 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1460 * received. Note that we do not persist this monotonic time as we
1461 * do not really have to worry about ancient flow control window
1462 * sizes after restarts.
1463 */
1464 struct GNUNET_TIME_Absolute last_fc_timestamp;
1465
1466 /**
1467 * Expected RTT from the last FC transmission. (Zero if the last
1468 * attempt failed, but could theoretically be zero even on success.)
1469 */
1470 struct GNUNET_TIME_Relative last_fc_rtt;
1471
1472 /**
1473 * Used to generate unique UUIDs for messages that are being
1474 * fragmented.
1475 */
1476 uint64_t message_uuid_ctr;
1477
1478 /**
1479 * Memory allocated for this virtual link. Expresses how much RAM
1480 * we are willing to allocate to this virtual link. OPTIMIZE-ME:
1481 * Can be adapted to dedicate more RAM to links that need it, while
1482 * sticking to some overall RAM limit. For now, set to
1483 * #DEFAULT_WINDOW_SIZE.
1484 */
1485 uint64_t available_fc_window_size;
1486
1487 /**
1488 * Memory actually used to buffer packets on this virtual link.
1489 * Expresses how much RAM we are currently using for virtual link.
1490 * Note that once CORE is done with a packet, we decrement the value
1491 * here.
1492 */
1493 uint64_t incoming_fc_window_size_ram;
1494
1495 /**
1496 * Last flow control window size we provided to the other peer, in
1497 * bytes. We are allowing the other peer to send this
1498 * many bytes.
1499 */
1500 uint64_t incoming_fc_window_size;
1501
1502 /**
1503 * How much of the window did the other peer successfully use (and
1504 * we already passed it on to CORE)? Must be below @e
1505 * incoming_fc_window_size. We should effectively signal the
1506 * other peer that the window is this much bigger at the next
1507 * opportunity / challenge.
1508 */
1509 uint64_t incoming_fc_window_size_used;
1510
1511 /**
1512 * What is our current estimate on the message loss rate for the sender?
1513 * Based on the difference between how much the sender sent according
1514 * to the last #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message
1515 * (@e outbound_sent field) and how much we actually received at that
1516 * time (@e incoming_fc_window_size_used). This delta is then
1517 * added onto the @e incoming_fc_window_size when determining the
1518 * @e outbound_window_size we send to the other peer. Initially zero.
1519 * May be negative if we (due to out-of-order delivery) actually received
1520 * more than the sender claims to have sent in its last FC message.
1521 */
1522 int64_t incoming_fc_window_size_loss;
1523
1524 /**
1525 * Our current flow control window size in bytes. We
1526 * are allowed to transmit this many bytes to @a n.
1527 */
1528 uint64_t outbound_fc_window_size;
1529
1530 /**
1531 * How much of our current flow control window size have we
1532 * used (in bytes). Must be below
1533 * @e outbound_fc_window_size.
1534 */
1535 uint64_t outbound_fc_window_size_used;
1536
1537 /**
1538 * What is the most recent FC window the other peer sent us
1539 * in `outbound_window_size`? This is basically the window
1540 * size value the other peer has definitively received from
1541 * us. If it matches @e incoming_fc_window_size, we should
1542 * not send a FC message to increase the FC window. However,
1543 * we may still send an FC message to notify the other peer
1544 * that we received the other peer's FC message.
1545 */
1546 uint64_t last_outbound_window_size_received;
1547
1548 /**
1549 * Generator for the sequence numbers of
1550 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL messages we send.
1551 */
1552 uint32_t fc_seq_gen;
1553
1554 /**
1555 * Last sequence number of a
1556 * #GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL message we have
1557 * received.
1558 */
1559 uint32_t last_fc_seq;
1560
1561 /**
1562 * How many more messages can we send to CORE before we exhaust
1563 * the receive window of CORE for this peer? If this hits zero,
1564 * we must tell communicators to stop providing us more messages
1565 * for this peer. In fact, the window can go negative as we
1566 * have multiple communicators, so per communicator we can go
1567 * down by one into the negative range. Furthermore, we count
1568 * delivery per CORE client, so if we had multiple cores, that
1569 * might also cause a negative window size here (as one message
1570 * would decrement the window by one per CORE client).
1571 */
1572 int core_recv_window;
1573};
1574
1575
1576/**
1577 * Data structure kept when we are waiting for an acknowledgement.
1578 */
1579struct PendingAcknowledgement
1580{
1581 /**
1582 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1583 * is kept in relation to its pending message.
1584 */
1585 struct PendingAcknowledgement *next_pm;
1586
1587 /**
1588 * If @e pm is non-NULL, this is the DLL in which this acknowledgement
1589 * is kept in relation to its pending message.
1590 */
1591 struct PendingAcknowledgement *prev_pm;
1592
1593 /**
1594 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1595 * is kept in relation to the queue that was used to transmit the
1596 * @a pm.
1597 */
1598 struct PendingAcknowledgement *next_queue;
1599
1600 /**
1601 * If @e queue is non-NULL, this is the DLL in which this acknowledgement
1602 * is kept in relation to the queue that was used to transmit the
1603 * @a pm.
1604 */
1605 struct PendingAcknowledgement *prev_queue;
1606
1607 /**
1608 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1609 * is kept in relation to the DVH that was used to transmit the
1610 * @a pm.
1611 */
1612 struct PendingAcknowledgement *next_dvh;
1613
1614 /**
1615 * If @e dvh is non-NULL, this is the DLL in which this acknowledgement
1616 * is kept in relation to the DVH that was used to transmit the
1617 * @a pm.
1618 */
1619 struct PendingAcknowledgement *prev_dvh;
1620
1621 /**
1622 * Pointers for the DLL of all pending acknowledgements.
1623 * This list is sorted by @e transmission time. If the list gets too
1624 * long, the oldest entries are discarded.
1625 */
1626 struct PendingAcknowledgement *next_pa;
1627
1628 /**
1629 * Pointers for the DLL of all pending acknowledgements.
1630 * This list is sorted by @e transmission time. If the list gets too
1631 * long, the oldest entries are discarded.
1632 */
1633 struct PendingAcknowledgement *prev_pa;
1634
1635 /**
1636 * Unique identifier for this transmission operation.
1637 */
1638 struct AcknowledgementUUIDP ack_uuid;
1639
1640 /**
1641 * Message that was transmitted, may be NULL if the message was ACKed
1642 * via another channel.
1643 */
1644 struct PendingMessage *pm;
1645
1646 /**
1647 * Distance vector path chosen for this transmission, NULL if transmission
1648 * was to a direct neighbour OR if the path was forgotten in the meantime.
1649 */
1650 struct DistanceVectorHop *dvh;
1651
1652 /**
1653 * Queue used for transmission, NULL if the queue has been destroyed
1654 * (which may happen before we get an acknowledgement).
1655 */
1656 struct Queue *queue;
1657
1658 /**
1659 * Time of the transmission, for RTT calculation.
1660 */
1661 struct GNUNET_TIME_Absolute transmission_time;
1662
1663 /**
1664 * Number of bytes of the original message (to calculate bandwidth).
1665 */
1666 uint16_t message_size;
1667
1668 /**
1669 * How often the PendingMessage was send via the Queue of this PendingAcknowledgement.
1670 */
1671 unsigned int num_send;
1672};
1673
1674
1675/**
1676 * One possible hop towards a DV target.
1677 */
1678struct DistanceVectorHop
1679{
1680 /**
1681 * Kept in a MDLL, sorted by @e timeout.
1682 */
1683 struct DistanceVectorHop *next_dv;
1684
1685 /**
1686 * Kept in a MDLL, sorted by @e timeout.
1687 */
1688 struct DistanceVectorHop *prev_dv;
1689
1690 /**
1691 * Kept in a MDLL.
1692 */
1693 struct DistanceVectorHop *next_neighbour;
1694
1695 /**
1696 * Kept in a MDLL.
1697 */
1698 struct DistanceVectorHop *prev_neighbour;
1699
1700 /**
1701 * Head of DLL of PAs that used our @a path.
1702 */
1703 struct PendingAcknowledgement *pa_head;
1704
1705 /**
1706 * Tail of DLL of PAs that used our @a path.
1707 */
1708 struct PendingAcknowledgement *pa_tail;
1709
1710 /**
1711 * What would be the next hop to @e target?
1712 */
1713 struct Neighbour *next_hop;
1714
1715 /**
1716 * Distance vector entry this hop belongs with.
1717 */
1718 struct DistanceVector *dv;
1719
1720 /**
1721 * Array of @e distance hops to the target, excluding @e next_hop.
1722 * NULL if the entire path is us to @e next_hop to `target`. Allocated
1723 * at the end of this struct. Excludes the target itself!
1724 */
1725 const struct GNUNET_PeerIdentity *path;
1726
1727 /**
1728 * At what time do we forget about this path unless we see it again
1729 * while learning?
1730 */
1731 struct GNUNET_TIME_Absolute timeout;
1732
1733 /**
1734 * For how long is the validation of this path considered
1735 * valid?
1736 * Set to ZERO if the path is learned by snooping on DV learn messages
1737 * initiated by other peers, and to the time at which we generated the
1738 * challenge for DV learn operations this peer initiated.
1739 */
1740 struct GNUNET_TIME_Absolute path_valid_until;
1741
1742 /**
1743 * Performance data for this transmission possibility.
1744 */
1745 struct PerformanceData pd;
1746
1747 /**
1748 * Number of hops in total to the `target` (excluding @e next_hop and `target`
1749 * itself). Thus 0 still means a distance of 2 hops (to @e next_hop and then
1750 * to `target`).
1751 */
1752 unsigned int distance;
1753};
1754
1755
1756/**
1757 * Entry in our #dv_routes table, representing a (set of) distance
1758 * vector routes to a particular peer.
1759 */
1760struct DistanceVector
1761{
1762 /**
1763 * To which peer is this a route?
1764 */
1765 struct GNUNET_PeerIdentity target;
1766
1767 /**
1768 * Known paths to @e target.
1769 */
1770 struct DistanceVectorHop *dv_head;
1771
1772 /**
1773 * Known paths to @e target.
1774 */
1775 struct DistanceVectorHop *dv_tail;
1776
1777 /**
1778 * Task scheduled to purge expired paths from @e dv_head MDLL.
1779 */
1780 struct GNUNET_SCHEDULER_Task *timeout_task;
1781
1782 /**
1783 * Do we have a confirmed working queue and are thus visible to
1784 * CORE? If so, this is the virtual link, otherwise NULL.
1785 */
1786 struct VirtualLink *vl;
1787
1788 /**
1789 * Signature affirming @e ephemeral_key of type
1790 * #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL
1791 */
1792 struct GNUNET_CRYPTO_EddsaSignature sender_sig;
1793
1794 /**
1795 * How long is @e sender_sig valid
1796 */
1797 struct GNUNET_TIME_Absolute ephemeral_validity;
1798
1799 /**
1800 * What time was @e sender_sig created
1801 */
1802 struct GNUNET_TIME_Absolute monotime;
1803
1804 /**
1805 * Our ephemeral key.
1806 */
1807 struct GNUNET_CRYPTO_EcdhePublicKey ephemeral_key;
1808
1809 /**
1810 * Master secret for the setup of the Key material for the backchannel.
1811 */
1812 struct GNUNET_HashCode *km;
1813};
1814
1815
1816/**
1817 * Entry identifying transmission in one of our `struct
1818 * Queue` which still awaits an ACK. This is used to
1819 * ensure we do not overwhelm a communicator and limit the number of
1820 * messages outstanding per communicator (say in case communicator is
1821 * CPU bound) and per queue (in case bandwidth allocation exceeds
1822 * what the communicator can actually provide towards a particular
1823 * peer/target).
1824 */
1825struct QueueEntry
1826{
1827 /**
1828 * Kept as a DLL.
1829 */
1830 struct QueueEntry *next;
1831
1832 /**
1833 * Kept as a DLL.
1834 */
1835 struct QueueEntry *prev;
1836
1837 /**
1838 * Queue this entry is queued with.
1839 */
1840 struct Queue *queue;
1841
1842 /**
1843 * Pending message this entry is for, or NULL for none.
1844 */
1845 struct PendingMessage *pm;
1846
1847 /**
1848 * Message ID used for this message with the queue used for transmission.
1849 */
1850 uint64_t mid;
1851
1852 /**
1853 * Timestamp this QueueEntry was created.
1854 */
1855 struct GNUNET_TIME_Absolute creation_timestamp;
1856};
1857
1858
1859/**
1860 * A queue is a message queue provided by a communicator
1861 * via which we can reach a particular neighbour.
1862 */
1863struct Queue
1864{
1865 /**
1866 * Kept in a MDLL.
1867 */
1868 struct Queue *next_neighbour;
1869
1870 /**
1871 * Kept in a MDLL.
1872 */
1873 struct Queue *prev_neighbour;
1874
1875 /**
1876 * Kept in a MDLL.
1877 */
1878 struct Queue *prev_client;
1879
1880 /**
1881 * Kept in a MDLL.
1882 */
1883 struct Queue *next_client;
1884
1885 /**
1886 * Head of DLL of PAs that used this queue.
1887 */
1888 struct PendingAcknowledgement *pa_head;
1889
1890 /**
1891 * Tail of DLL of PAs that used this queue.
1892 */
1893 struct PendingAcknowledgement *pa_tail;
1894
1895 /**
1896 * Head of DLL of unacked transmission requests.
1897 */
1898 struct QueueEntry *queue_head;
1899
1900 /**
1901 * End of DLL of unacked transmission requests.
1902 */
1903 struct QueueEntry *queue_tail;
1904
1905 /**
1906 * Which neighbour is this queue for?
1907 */
1908 struct Neighbour *neighbour;
1909
1910 /**
1911 * Which communicator offers this queue?
1912 */
1913 struct TransportClient *tc;
1914
1915 /**
1916 * Address served by the queue.
1917 */
1918 const char *address;
1919
1920 /**
1921 * Is this queue of unlimited length.
1922 */
1923 unsigned int unlimited_length;
1924
1925 /**
1926 * Task scheduled for the time when this queue can (likely) transmit the
1927 * next message.
1928 */
1929 struct GNUNET_SCHEDULER_Task *transmit_task;
1930
1931 /**
1932 * How long do *we* consider this @e address to be valid? In the past or
1933 * zero if we have not yet validated it. Can be updated based on
1934 * challenge-response validations (via address validation logic), or when we
1935 * receive ACKs that we can definitively map to transmissions via this
1936 * queue.
1937 */
1938 struct GNUNET_TIME_Absolute validated_until;
1939
1940 /**
1941 * Performance data for this queue.
1942 */
1943 struct PerformanceData pd;
1944
1945 /**
1946 * Handle for an operation to iterate through all hellos to compare the hello
1947 * addresses with @e address which might be a natted one.
1948 */
1949 struct GNUNET_PEERSTORE_Monitor *mo;
1950
1951 /**
1952 * Message ID generator for transmissions on this queue to the
1953 * communicator.
1954 */
1955 uint64_t mid_gen;
1956
1957 /**
1958 * Unique identifier of this queue with the communicator.
1959 */
1960 uint32_t qid;
1961
1962 /**
1963 * Maximum transmission unit supported by this queue.
1964 */
1965 uint32_t mtu;
1966
1967 /**
1968 * Messages pending.
1969 */
1970 uint32_t num_msg_pending;
1971
1972 /**
1973 * Bytes pending.
1974 */
1975 uint32_t num_bytes_pending;
1976
1977 /**
1978 * Length of the DLL starting at @e queue_head.
1979 */
1980 unsigned int queue_length;
1981
1982 /**
1983 * Capacity of the queue.
1984 */
1985 uint64_t q_capacity;
1986
1987 /**
1988 * Queue priority
1989 */
1990 uint32_t priority;
1991
1992 /**
1993 * Network type offered by this queue.
1994 */
1995 enum GNUNET_NetworkType nt;
1996
1997 /**
1998 * Connection status for this queue.
1999 */
2000 enum GNUNET_TRANSPORT_ConnectionStatus cs;
2001
2002 /**
2003 * Set to #GNUNET_YES if this queue is idle waiting for some
2004 * virtual link to give it a pending message.
2005 */
2006 int idle;
2007
2008 /**
2009 * Set to GNUNET_yes, if this queues address is not a global natted one.
2010 */
2011 enum GNUNET_GenericReturnValue is_global_natted;
2012};
2013
2014
2015/**
2016 * A neighbour that at least one communicator is connected to.
2017 */
2018struct Neighbour
2019{
2020 /**
2021 * Which peer is this about?
2022 */
2023 struct GNUNET_PeerIdentity pid;
2024
2025 /**
2026 * Head of MDLL of DV hops that have this neighbour as next hop. Must be
2027 * purged if this neighbour goes down.
2028 */
2029 struct DistanceVectorHop *dv_head;
2030
2031 /**
2032 * Tail of MDLL of DV hops that have this neighbour as next hop. Must be
2033 * purged if this neighbour goes down.
2034 */
2035 struct DistanceVectorHop *dv_tail;
2036
2037 /**
2038 * Head of DLL of queues to this peer.
2039 */
2040 struct Queue *queue_head;
2041
2042 /**
2043 * Tail of DLL of queues to this peer.
2044 */
2045 struct Queue *queue_tail;
2046
2047 /**
2048 * Handle for an operation to fetch @e last_dv_learn_monotime information from
2049 * the PEERSTORE, or NULL.
2050 */
2051 struct GNUNET_PEERSTORE_IterateContext *get;
2052
2053 /**
2054 * Handle to a PEERSTORE store operation to store this @e pid's @e
2055 * @e last_dv_learn_monotime. NULL if no PEERSTORE operation is pending.
2056 */
2057 struct GNUNET_PEERSTORE_StoreContext *sc;
2058
2059 /**
2060 * Do we have a confirmed working queue and are thus visible to
2061 * CORE? If so, this is the virtual link, otherwise NULL.
2062 */
2063 struct VirtualLink *vl;
2064
2065 /**
2066 * Latest DVLearn monotonic time seen from this peer. Initialized only
2067 * if @e dl_monotime_available is #GNUNET_YES.
2068 */
2069 struct GNUNET_TIME_Absolute last_dv_learn_monotime;
2070
2071 /**
2072 * Do we have the latest value for @e last_dv_learn_monotime from
2073 * PEERSTORE yet, or are we still waiting for a reply of PEERSTORE?
2074 */
2075 int dv_monotime_available;
2076
2077 /**
2078 * Map of struct TransportGlobalNattedAddress for this neighbour.
2079 */
2080 struct GNUNET_CONTAINER_MultiPeerMap *natted_addresses;
2081
2082 /**
2083 * Number of global natted addresses for this neighbour.
2084 */
2085 unsigned int number_of_addresses;
2086
2087 /**
2088 * Size of all global natted addresses for this neighbour.
2089 */
2090 size_t size_of_global_addresses;
2091
2092 /**
2093 * A queue of this neighbour has a global natted address.
2094 */
2095 enum GNUNET_GenericReturnValue is_global_natted;
2096};
2097
2098
2099/**
2100 * Another peer attempted to talk to us, we should try to establish
2101 * a connection in the other direction.
2102 */
2103struct IncomingRequest
2104{
2105 /**
2106 * Kept in a DLL.
2107 */
2108 struct IncomingRequest *next;
2109
2110 /**
2111 * Kept in a DLL.
2112 */
2113 struct IncomingRequest *prev;
2114
2115 /**
2116 * Notify context for new HELLOs.
2117 */
2118 struct GNUNET_PEERSTORE_Monitor *nc;
2119
2120 /**
2121 * Which peer is this about?
2122 */
2123 struct GNUNET_PeerIdentity pid;
2124};
2125
2126
2127/**
2128 * A peer that an application (client) would like us to talk to directly.
2129 */
2130struct PeerRequest
2131{
2132 /**
2133 * Which peer is this about?
2134 */
2135 struct GNUNET_PeerIdentity pid;
2136
2137 /**
2138 * Client responsible for the request.
2139 */
2140 struct TransportClient *tc;
2141
2142 /**
2143 * Notify context for new HELLOs.
2144 */
2145 struct GNUNET_PEERSTORE_Monitor *nc;
2146
2147 /**
2148 * What kind of performance preference does this @e tc have?
2149 *
2150 * TODO: use this!
2151 */
2152 enum GNUNET_MQ_PriorityPreferences pk;
2153
2154 /**
2155 * How much bandwidth would this @e tc like to see?
2156 */
2157 struct GNUNET_BANDWIDTH_Value32NBO bw;
2158};
2159
2160
2161/**
2162 * Types of different pending messages.
2163 */
2164enum PendingMessageType
2165{
2166 /**
2167 * Ordinary message received from the CORE service.
2168 */
2169 PMT_CORE = 0,
2170
2171 /**
2172 * Fragment box.
2173 */
2174 PMT_FRAGMENT_BOX = 1,
2175
2176 /**
2177 * Reliability box.
2178 */
2179 PMT_RELIABILITY_BOX = 2,
2180
2181 /**
2182 * Pending message created during #forward_dv_box().
2183 */
2184 PMT_DV_BOX = 3
2185};
2186
2187
2188/**
2189 * Transmission request that is awaiting delivery. The original
2190 * transmission requests from CORE may be too big for some queues.
2191 * In this case, a *tree* of fragments is created. At each
2192 * level of the tree, fragments are kept in a DLL ordered by which
2193 * fragment should be sent next (at the head). The tree is searched
2194 * top-down, with the original message at the root.
2195 *
2196 * To select a node for transmission, first it is checked if the
2197 * current node's message fits with the MTU. If it does not, we
2198 * either calculate the next fragment (based on @e frag_off) from the
2199 * current node, or, if all fragments have already been created,
2200 * descend to the @e head_frag. Even though the node was already
2201 * fragmented, the fragment may be too big if the fragment was
2202 * generated for a queue with a larger MTU. In this case, the node
2203 * may be fragmented again, thus creating a tree.
2204 *
2205 * When acknowledgements for fragments are received, the tree
2206 * must be pruned, removing those parts that were already
2207 * acknowledged. When fragments are sent over a reliable
2208 * channel, they can be immediately removed.
2209 *
2210 * If a message is ever fragmented, then the original "full" message
2211 * is never again transmitted (even if it fits below the MTU), and
2212 * only (remaining) fragments are sent.
2213 */
2214struct PendingMessage
2215{
2216 /**
2217 * Kept in a MDLL of messages for this @a vl.
2218 */
2219 struct PendingMessage *next_vl;
2220
2221 /**
2222 * Kept in a MDLL of messages for this @a vl.
2223 */
2224 struct PendingMessage *prev_vl;
2225
2226 /**
2227 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2228 */
2229 struct PendingMessage *next_client;
2230
2231 /**
2232 * Kept in a MDLL of messages from this @a client (if @e pmt is #PMT_CORE)
2233 */
2234 struct PendingMessage *prev_client;
2235
2236 /**
2237 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2238 * #PMT_FRAGMENT_BOx)
2239 */
2240 struct PendingMessage *next_frag;
2241
2242 /**
2243 * Kept in a MDLL of messages from this @a cpm (if @e pmt is
2244 * #PMT_FRAGMENT_BOX)
2245 */
2246 struct PendingMessage *prev_frag;
2247
2248 /**
2249 * Head of DLL of PAs for this pending message.
2250 */
2251 struct PendingAcknowledgement *pa_head;
2252
2253 /**
2254 * Tail of DLL of PAs for this pending message.
2255 */
2256 struct PendingAcknowledgement *pa_tail;
2257
2258 /**
2259 * This message, reliability *or* DV-boxed. Only possibly available
2260 * if @e pmt is #PMT_CORE.
2261 */
2262 struct PendingMessage *bpm;
2263
2264 /**
2265 * Target of the request (always the ultimate destination!).
2266 * Might be NULL in case of a forwarded DVBox we have no validated neighbour.
2267 */
2268 struct VirtualLink *vl;
2269
2270 /**
2271 * In case of a not validated neighbour, we store the target peer.
2272 **/
2273 struct GNUNET_PeerIdentity target;
2274
2275 /**
2276 * Set to non-NULL value if this message is currently being given to a
2277 * communicator and we are awaiting that communicator's acknowledgement.
2278 * Note that we must not retransmit a pending message while we're still
2279 * in the process of giving it to a communicator. If a pending message
2280 * is free'd while this entry is non-NULL, the @e qe reference to us
2281 * should simply be set to NULL.
2282 */
2283 struct QueueEntry *qe;
2284
2285 /**
2286 * Client that issued the transmission request, if @e pmt is #PMT_CORE.
2287 */
2288 struct TransportClient *client;
2289
2290 /**
2291 * Head of a MDLL of fragments created for this core message.
2292 */
2293 struct PendingMessage *head_frag;
2294
2295 /**
2296 * Tail of a MDLL of fragments created for this core message.
2297 */
2298 struct PendingMessage *tail_frag;
2299
2300 /**
2301 * Our parent in the fragmentation tree.
2302 */
2303 struct PendingMessage *frag_parent;
2304
2305 /**
2306 * At what time should we give up on the transmission (and no longer retry)?
2307 */
2308 struct GNUNET_TIME_Absolute timeout;
2309
2310 /**
2311 * What is the earliest time for us to retry transmission of this message?
2312 */
2313 struct GNUNET_TIME_Absolute next_attempt;
2314
2315 /**
2316 * UUID to use for this message (used for reassembly of fragments, only
2317 * initialized if @e msg_uuid_set is #GNUNET_YES).
2318 */
2319 struct MessageUUIDP msg_uuid;
2320
2321 /**
2322 * UUID we use to identify this message in our logs.
2323 * Generated by incrementing the "logging_uuid_gen".
2324 */
2325 uint64_t logging_uuid;
2326
2327 /**
2328 * Type of the pending message.
2329 */
2330 enum PendingMessageType pmt;
2331
2332 /**
2333 * Preferences for this message.
2334 * TODO: actually use this!
2335 */
2336 enum GNUNET_MQ_PriorityPreferences prefs;
2337
2338 /**
2339 * If pmt is of type PMT_DV_BOX we store the used path here.
2340 */
2341 struct DistanceVectorHop *used_dvh;
2342
2343 /**
2344 * Size of the original message.
2345 */
2346 uint16_t bytes_msg;
2347
2348 /**
2349 * Offset at which we should generate the next fragment.
2350 */
2351 uint16_t frag_off;
2352
2353 /**
2354 * Are we sending fragments at the moment?
2355 */
2356 uint32_t frags_in_flight;
2357
2358 /**
2359 * The round we are (re)-sending fragments.
2360 */
2361 uint32_t frags_in_flight_round;
2362
2363 /**
2364 * How many fragments do we have?
2365 **/
2366 uint16_t frag_count;
2367
2368 /**
2369 * #GNUNET_YES once @e msg_uuid was initialized
2370 */
2371 int16_t msg_uuid_set;
2372
2373 /* Followed by @e bytes_msg to transmit */
2374};
2375
2376
2377/**
2378 * Acknowledgement payload.
2379 */
2380struct TransportCummulativeAckPayload
2381{
2382 /**
2383 * When did we receive the message we are ACKing? Used to calculate
2384 * the delay we introduced by cummulating ACKs.
2385 */
2386 struct GNUNET_TIME_Absolute receive_time;
2387
2388 /**
2389 * UUID of a message being acknowledged.
2390 */
2391 struct AcknowledgementUUIDP ack_uuid;
2392};
2393
2394
2395/**
2396 * Data structure in which we track acknowledgements still to
2397 * be sent to the
2398 */
2399struct AcknowledgementCummulator
2400{
2401 /**
2402 * Target peer for which we are accumulating ACKs here.
2403 */
2404 struct GNUNET_PeerIdentity target;
2405
2406 /**
2407 * ACK data being accumulated. Only @e num_acks slots are valid.
2408 */
2409 struct TransportCummulativeAckPayload ack_uuids[MAX_CUMMULATIVE_ACKS];
2410
2411 /**
2412 * Task scheduled either to transmit the cumulative ACK message,
2413 * or to clean up this data structure after extended periods of
2414 * inactivity (if @e num_acks is zero).
2415 */
2416 struct GNUNET_SCHEDULER_Task *task;
2417
2418 /**
2419 * When is @e task run (only used if @e num_acks is non-zero)?
2420 */
2421 struct GNUNET_TIME_Absolute min_transmission_time;
2422
2423 /**
2424 * Counter to produce the `ack_counter` in the `struct
2425 * TransportReliabilityAckMessage`. Allows the receiver to detect
2426 * lost ACK messages. Incremented by @e num_acks upon transmission.
2427 */
2428 uint32_t ack_counter;
2429
2430 /**
2431 * Number of entries used in @e ack_uuids. Reset to 0 upon transmission.
2432 */
2433 unsigned int num_acks;
2434};
2435
2436
2437/**
2438 * One of the addresses of this peer.
2439 */
2440struct AddressListEntry
2441{
2442 /**
2443 * Kept in a DLL.
2444 */
2445 struct AddressListEntry *next;
2446
2447 /**
2448 * Kept in a DLL.
2449 */
2450 struct AddressListEntry *prev;
2451
2452 /**
2453 * Which communicator provides this address?
2454 */
2455 struct TransportClient *tc;
2456
2457 /**
2458 * Store hello handle
2459 */
2460 struct GNUNET_PEERSTORE_StoreHelloContext *shc;
2461
2462 /**
2463 * The actual address.
2464 */
2465 const char *address;
2466
2467 /**
2468 * Signed address
2469 */
2470 void *signed_address;
2471
2472 /**
2473 * Signed address length
2474 */
2475 size_t signed_address_len;
2476
2477 /**
2478 * Current context for storing this address in the peerstore.
2479 */
2480 struct GNUNET_PEERSTORE_StoreContext *sc;
2481
2482 /**
2483 * Task to periodically do @e st operation.
2484 */
2485 struct GNUNET_SCHEDULER_Task *st;
2486
2487 /**
2488 * What is a typical lifetime the communicator expects this
2489 * address to have? (Always from now.)
2490 */
2491 struct GNUNET_TIME_Relative expiration;
2492
2493 /**
2494 * Address identifier used by the communicator.
2495 */
2496 uint32_t aid;
2497
2498 /**
2499 * Network type offered by this address.
2500 */
2501 enum GNUNET_NetworkType nt;
2502};
2503
2504
2505/**
2506 * Client connected to the transport service.
2507 */
2508struct TransportClient
2509{
2510 /**
2511 * Kept in a DLL.
2512 */
2513 struct TransportClient *next;
2514
2515 /**
2516 * Kept in a DLL.
2517 */
2518 struct TransportClient *prev;
2519
2520 /**
2521 * Handle to the client.
2522 */
2523 struct GNUNET_SERVICE_Client *client;
2524
2525 /**
2526 * Message queue to the client.
2527 */
2528 struct GNUNET_MQ_Handle *mq;
2529
2530 /**
2531 * What type of client is this?
2532 */
2533 enum ClientType type;
2534
2535 union
2536 {
2537 /**
2538 * Information for @e type #CT_CORE.
2539 */
2540 struct
2541 {
2542 /**
2543 * Head of list of messages pending for this client, sorted by
2544 * transmission time ("next_attempt" + possibly internal prioritization).
2545 */
2546 struct PendingMessage *pending_msg_head;
2547
2548 /**
2549 * Tail of list of messages pending for this client.
2550 */
2551 struct PendingMessage *pending_msg_tail;
2552 } core;
2553
2554 /**
2555 * Information for @e type #CT_MONITOR.
2556 */
2557 struct
2558 {
2559 /**
2560 * Peer identity to monitor the addresses of.
2561 * Zero to monitor all neighbours. Valid if
2562 * @e type is #CT_MONITOR.
2563 */
2564 struct GNUNET_PeerIdentity peer;
2565
2566 /**
2567 * Is this a one-shot monitor?
2568 */
2569 int one_shot;
2570 } monitor;
2571
2572
2573 /**
2574 * Information for @e type #CT_COMMUNICATOR.
2575 */
2576 struct
2577 {
2578 /**
2579 * If @e type is #CT_COMMUNICATOR, this communicator
2580 * supports communicating using these addresses.
2581 */
2582 char *address_prefix;
2583
2584 /**
2585 * Head of DLL of queues offered by this communicator.
2586 */
2587 struct Queue *queue_head;
2588
2589 /**
2590 * Tail of DLL of queues offered by this communicator.
2591 */
2592 struct Queue *queue_tail;
2593
2594 /**
2595 * Head of list of the addresses of this peer offered by this
2596 * communicator.
2597 */
2598 struct AddressListEntry *addr_head;
2599
2600 /**
2601 * Tail of list of the addresses of this peer offered by this
2602 * communicator.
2603 */
2604 struct AddressListEntry *addr_tail;
2605
2606 /**
2607 * Number of queue entries in all queues to this communicator. Used
2608 * throttle sending to a communicator if we see that the communicator
2609 * is globally unable to keep up.
2610 */
2611 unsigned int total_queue_length;
2612
2613 /**
2614 * Task to check for timed out QueueEntry.
2615 */
2616 struct GNUNET_SCHEDULER_Task *free_queue_entry_task;
2617
2618 /**
2619 * Characteristics of this communicator.
2620 */
2621 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
2622 } communicator;
2623
2624 /**
2625 * Information for @e type #CT_APPLICATION
2626 */
2627 struct
2628 {
2629 /**
2630 * Map of requests for peers the given client application would like to
2631 * see connections for. Maps from PIDs to `struct PeerRequest`.
2632 */
2633 struct GNUNET_CONTAINER_MultiPeerMap *requests;
2634 } application;
2635 } details;
2636};
2637
2638
2639/**
2640 * State we keep for validation activities. Each of these
2641 * is both in the #validation_heap and the #validation_map.
2642 */
2643struct ValidationState
2644{
2645 /**
2646 * For which peer is @a address to be validated (or possibly valid)?
2647 * Serves as key in the #validation_map.
2648 */
2649 struct GNUNET_PeerIdentity pid;
2650
2651 /**
2652 * How long did the peer claim this @e address to be valid? Capped at
2653 * minimum of #MAX_ADDRESS_VALID_UNTIL relative to the time where we last
2654 * were told about the address and the value claimed by the other peer at
2655 * that time. May be updated similarly when validation succeeds.
2656 */
2657 struct GNUNET_TIME_Absolute valid_until;
2658
2659 /**
2660 * How long do *we* consider this @e address to be valid?
2661 * In the past or zero if we have not yet validated it.
2662 */
2663 struct GNUNET_TIME_Absolute validated_until;
2664
2665 /**
2666 * When did we FIRST use the current @e challenge in a message?
2667 * Used to sanity-check @code{origin_time} in the response when
2668 * calculating the RTT. If the @code{origin_time} is not in
2669 * the expected range, the response is discarded as malicious.
2670 */
2671 struct GNUNET_TIME_Absolute first_challenge_use;
2672
2673 /**
2674 * When did we LAST use the current @e challenge in a message?
2675 * Used to sanity-check @code{origin_time} in the response when
2676 * calculating the RTT. If the @code{origin_time} is not in
2677 * the expected range, the response is discarded as malicious.
2678 */
2679 struct GNUNET_TIME_Absolute last_challenge_use;
2680
2681 /**
2682 * Next time we will send the @e challenge to the peer, if this time is past
2683 * @e valid_until, this validation state is released at this time. If the
2684 * address is valid, @e next_challenge is set to @e validated_until MINUS @e
2685 * validation_delay * #VALIDATION_RTT_BUFFER_FACTOR, such that we will try
2686 * to re-validate before the validity actually expires.
2687 */
2688 struct GNUNET_TIME_Absolute next_challenge;
2689
2690 /**
2691 * Current backoff factor we're applying for sending the @a challenge.
2692 * Reset to 0 if the @a challenge is confirmed upon validation.
2693 * Reduced to minimum of #FAST_VALIDATION_CHALLENGE_FREQ and half of the
2694 * existing value if we receive an unvalidated address again over
2695 * another channel (and thus should consider the information "fresh").
2696 * Maximum is #MAX_VALIDATION_CHALLENGE_FREQ.
2697 */
2698 struct GNUNET_TIME_Relative challenge_backoff;
2699
2700 /**
2701 * Initially set to "forever". Once @e validated_until is set, this value is
2702 * set to the RTT that tells us how long it took to receive the validation.
2703 */
2704 struct GNUNET_TIME_Relative validation_rtt;
2705
2706 /**
2707 * The challenge we sent to the peer to get it to validate the address. Note
2708 * that we rotate the challenge whenever we update @e validated_until to
2709 * avoid attacks where a peer simply replays an old challenge in the future.
2710 * (We must not rotate more often as otherwise we may discard valid answers
2711 * due to packet losses, latency and reorderings on the network).
2712 */
2713 struct GNUNET_CRYPTO_ChallengeNonceP challenge;
2714
2715 /**
2716 * Hascode key to store state in a map.
2717 */
2718 struct GNUNET_HashCode hc;
2719
2720 /**
2721 * Task to revalidate this address.
2722 */
2723 struct GNUNET_SCHEDULER_Task *revalidation_task;
2724
2725 /**
2726 * Claimed address of the peer.
2727 */
2728 char *address;
2729
2730 /**
2731 * Entry in the #validation_heap, which is sorted by @e next_challenge. The
2732 * heap is used to figure out when the next validation activity should be
2733 * run.
2734 */
2735 struct GNUNET_CONTAINER_HeapNode *hn;
2736
2737 /**
2738 * Handle to a PEERSTORE store operation for this @e address. NULL if
2739 * no PEERSTORE operation is pending.
2740 */
2741 struct GNUNET_PEERSTORE_StoreContext *sc;
2742
2743 /**
2744 * Self-imposed limit on the previous flow control window. (May be zero,
2745 * if we never used data from the previous window or are establishing the
2746 * connection for the first time).
2747 */
2748 uint32_t last_window_consum_limit;
2749
2750 /**
2751 * We are technically ready to send the challenge, but we are waiting for
2752 * the respective queue to become available for transmission.
2753 */
2754 int awaiting_queue;
2755};
2756
2757
2758/**
2759 * A Backtalker is a peer sending us backchannel messages. We use this
2760 * struct to detect monotonic time violations, cache ephemeral key
2761 * material (to avoid repeatedly checking signatures), and to synchronize
2762 * monotonic time with the PEERSTORE.
2763 */
2764struct Backtalker
2765{
2766 /**
2767 * Peer this is about.
2768 */
2769 struct GNUNET_PeerIdentity pid;
2770
2771 /**
2772 * Last (valid) monotonic time received from this sender.
2773 */
2774 struct GNUNET_TIME_Absolute monotonic_time;
2775
2776 /**
2777 * When will this entry time out?
2778 */
2779 struct GNUNET_TIME_Absolute timeout;
2780
2781 /**
2782 * Last (valid) ephemeral key received from this sender.
2783 */
2784 struct GNUNET_CRYPTO_EcdhePublicKey last_ephemeral;
2785
2786 /**
2787 * Task associated with this backtalker. Can be for timeout,
2788 * or other asynchronous operations.
2789 */
2790 struct GNUNET_SCHEDULER_Task *task;
2791
2792 /**
2793 * Communicator context waiting on this backchannel's @e get, or NULL.
2794 */
2795 struct CommunicatorMessageContext *cmc;
2796
2797 /**
2798 * Handle for an operation to fetch @e monotonic_time information from the
2799 * PEERSTORE, or NULL.
2800 */
2801 struct GNUNET_PEERSTORE_IterateContext *get;
2802
2803 /**
2804 * Handle to a PEERSTORE store operation for this @e pid's @e
2805 * monotonic_time. NULL if no PEERSTORE operation is pending.
2806 */
2807 struct GNUNET_PEERSTORE_StoreContext *sc;
2808
2809 /**
2810 * Number of bytes of the original message body that follows after this
2811 * struct.
2812 */
2813 size_t body_size;
2814};
2815
2816/**
2817 * Ring buffer for a CORE message we did not deliver to CORE, because of missing virtual link to sender.
2818 */
2819static struct RingBufferEntry *ring_buffer[RING_BUFFER_SIZE];
2820
2821/**
2822 * Head of the ring buffer.
2823 */
2824static unsigned int ring_buffer_head;
2825
2826/**
2827 * Is the ring buffer filled up to RING_BUFFER_SIZE.
2828 */
2829static unsigned int is_ring_buffer_full;
2830
2831/**
2832 * Ring buffer for a forwarded DVBox message we did not deliver to the next hop, because of missing virtual link that hop.
2833 */
2834static struct PendingMessage *ring_buffer_dv[RING_BUFFER_SIZE];
2835
2836/**
2837 * Head of the ring buffer.
2838 */
2839static unsigned int ring_buffer_dv_head;
2840
2841/**
2842 * Is the ring buffer filled up to RING_BUFFER_SIZE.
2843 */
2844static unsigned int is_ring_buffer_dv_full;
2845
2846/**
2847 * Head of linked list of all clients to this service.
2848 */
2849static struct TransportClient *clients_head;
2850
2851/**
2852 * Tail of linked list of all clients to this service.
2853 */
2854static struct TransportClient *clients_tail;
2855
2856/**
2857 * Statistics handle.
2858 */
2859static struct GNUNET_STATISTICS_Handle *GST_stats;
2860
2861/**
2862 * Configuration handle.
2863 */
2864static const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
2865
2866/**
2867 * Our public key.
2868 */
2869static struct GNUNET_PeerIdentity GST_my_identity;
2870
2871/**
2872 * Our HELLO
2873 */
2874struct GNUNET_HELLO_Builder *GST_my_hello;
2875
2876/**
2877 * Our private key.
2878 */
2879static struct GNUNET_CRYPTO_EddsaPrivateKey *GST_my_private_key;
2880
2881/**
2882 * Map from PIDs to `struct Neighbour` entries. A peer is
2883 * a neighbour if we have an MQ to it from some communicator.
2884 */
2885static struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
2886
2887/**
2888 * Map from PIDs to `struct Backtalker` entries. A peer is
2889 * a backtalker if it recently send us backchannel messages.
2890 */
2891static struct GNUNET_CONTAINER_MultiPeerMap *backtalkers;
2892
2893/**
2894 * Map from PIDs to `struct AcknowledgementCummulator`s.
2895 * Here we track the cumulative ACKs for transmission.
2896 */
2897static struct GNUNET_CONTAINER_MultiPeerMap *ack_cummulators;
2898
2899/**
2900 * Map of pending acknowledgements, mapping `struct AcknowledgementUUID` to
2901 * a `struct PendingAcknowledgement`.
2902 */
2903static struct GNUNET_CONTAINER_MultiUuidmap *pending_acks;
2904
2905/**
2906 * Map from PIDs to `struct DistanceVector` entries describing
2907 * known paths to the peer.
2908 */
2909static struct GNUNET_CONTAINER_MultiPeerMap *dv_routes;
2910
2911/**
2912 * Map from PIDs to `struct ValidationState` entries describing
2913 * addresses we are aware of and their validity state.
2914 */
2915static struct GNUNET_CONTAINER_MultiPeerMap *validation_map;
2916
2917/**
2918 * Map from addresses to `struct ValidationState` entries describing
2919 * addresses we are aware of and their validity state.
2920 */
2921static struct GNUNET_CONTAINER_MultiHashMap *revalidation_map;
2922
2923/**
2924 * Map from PIDs to `struct VirtualLink` entries describing
2925 * links CORE knows to exist.
2926 */
2927static struct GNUNET_CONTAINER_MultiPeerMap *links;
2928
2929/**
2930 * Map from challenges to `struct LearnLaunchEntry` values.
2931 */
2932static struct GNUNET_CONTAINER_MultiShortmap *dvlearn_map;
2933
2934/**
2935 * Head of a DLL sorted by launch time.
2936 */
2937static struct LearnLaunchEntry *lle_head = NULL;
2938
2939/**
2940 * Tail of a DLL sorted by launch time.
2941 */
2942static struct LearnLaunchEntry *lle_tail = NULL;
2943
2944/**
2945 * MIN Heap sorted by "next_challenge" to `struct ValidationState` entries
2946 * sorting addresses we are aware of by when we should next try to (re)validate
2947 * (or expire) them.
2948 */
2949static struct GNUNET_CONTAINER_Heap *validation_heap;
2950
2951/**
2952 * Handle for connect to the NAT service.
2953 */
2954struct GNUNET_NAT_Handle *nh;
2955
2956/**
2957 * Database for peer's HELLOs.
2958 */
2959static struct GNUNET_PEERSTORE_Handle *peerstore;
2960
2961/**
2962 * Task run to initiate DV learning.
2963 */
2964static struct GNUNET_SCHEDULER_Task *dvlearn_task;
2965
2966/**
2967 * Task to run address validation.
2968 */
2969static struct GNUNET_SCHEDULER_Task *validation_task;
2970
2971/**
2972 * List of incoming connections where we are trying
2973 * to get a connection back established. Length
2974 * kept in #ir_total.
2975 */
2976static struct IncomingRequest *ir_head;
2977
2978/**
2979 * Tail of DLL starting at #ir_head.
2980 */
2981static struct IncomingRequest *ir_tail;
2982
2983/**
2984 * Length of the DLL starting at #ir_head.
2985 */
2986static unsigned int ir_total;
2987
2988/**
2989 * Generator of `logging_uuid` in `struct PendingMessage`.
2990 */
2991static unsigned long long logging_uuid_gen;
2992
2993/**
2994 * Monotonic time we use for HELLOs generated at this time. TODO: we
2995 * should increase this value from time to time (i.e. whenever a
2996 * `struct AddressListEntry` actually expires), but IF we do this, we
2997 * must also update *all* (remaining) addresses in the PEERSTORE at
2998 * that time! (So for now only increased when the peer is restarted,
2999 * which hopefully roughly matches whenever our addresses change.)
3000 */
3001static struct GNUNET_TIME_Absolute hello_mono_time;
3002
3003/**
3004 * Indication if we have received a shutdown signal
3005 * and are in the process of cleaning up.
3006 */
3007static int in_shutdown;
3008
3009/**
3010 * Get an offset into the transmission history buffer for `struct
3011 * PerformanceData`. Note that the caller must perform the required
3012 * modulo #GOODPUT_AGING_SLOTS operation before indexing into the
3013 * array!
3014 *
3015 * An 'age' lasts 15 minute slots.
3016 *
3017 * @return current age of the world
3018 */
3019static unsigned int
3020get_age ()
3021{
3022 struct GNUNET_TIME_Absolute now;
3023
3024 now = GNUNET_TIME_absolute_get ();
3025 return now.abs_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us / 15;
3026}
3027
3028
3029/**
3030 * Release @a ir data structure.
3031 *
3032 * @param ir data structure to release
3033 */
3034static void
3035free_incoming_request (struct IncomingRequest *ir)
3036{
3037 GNUNET_CONTAINER_DLL_remove (ir_head, ir_tail, ir);
3038 GNUNET_assert (ir_total > 0);
3039 ir_total--;
3040 if (NULL != ir->nc)
3041 GNUNET_PEERSTORE_monitor_stop (ir->nc);
3042 ir->nc = NULL;
3043 GNUNET_free (ir);
3044}
3045
3046
3047/**
3048 * Release @a pa data structure.
3049 *
3050 * @param pa data structure to release
3051 */
3052static void
3053free_pending_acknowledgement (struct PendingAcknowledgement *pa)
3054{
3055 struct Queue *q = pa->queue;
3056 struct PendingMessage *pm = pa->pm;
3057 struct DistanceVectorHop *dvh = pa->dvh;
3058
3059 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3060 "free_pending_acknowledgement\n");
3061 if (NULL != q)
3062 {
3063 GNUNET_CONTAINER_MDLL_remove (queue, q->pa_head, q->pa_tail, pa);
3064 pa->queue = NULL;
3065 }
3066 if (NULL != pm)
3067 {
3068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3069 "remove pa from message\n");
3070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3071 "remove pa from message %" PRIu64 "\n",
3072 pm->logging_uuid);
3073 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3074 "remove pa from message %u\n",
3075 pm->pmt);
3076 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3077 "remove pa from message %s\n",
3078 GNUNET_uuid2s (&pa->ack_uuid.value));
3079 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3080 pa->pm = NULL;
3081 }
3082 if (NULL != dvh)
3083 {
3084 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3085 pa->queue = NULL;
3086 }
3087 GNUNET_assert (GNUNET_YES ==
3088 GNUNET_CONTAINER_multiuuidmap_remove (pending_acks,
3089 &pa->ack_uuid.value,
3090 pa));
3091 GNUNET_free (pa);
3092}
3093
3094
3095/**
3096 * Free fragment tree below @e root, excluding @e root itself.
3097 * FIXME: this does NOT seem to have the intended semantics
3098 * based on how this is called. Seems we generally DO expect
3099 * @a root to be free'ed itself as well!
3100 *
3101 * @param root root of the tree to free
3102 */
3103static void
3104free_fragment_tree (struct PendingMessage *root)
3105{
3106 struct PendingMessage *frag;
3107
3108 while (NULL != (frag = root->head_frag))
3109 {
3110 struct PendingAcknowledgement *pa;
3111
3112 free_fragment_tree (frag);
3113 while (NULL != (pa = frag->pa_head))
3114 {
3115 GNUNET_CONTAINER_MDLL_remove (pm, frag->pa_head, frag->pa_tail, pa);
3116 pa->pm = NULL;
3117 }
3118 GNUNET_CONTAINER_MDLL_remove (frag, root->head_frag, root->tail_frag, frag);
3119 if (NULL != frag->qe)
3120 {
3121 GNUNET_assert (frag == frag->qe->pm);
3122 frag->qe->pm = NULL;
3123 }
3124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3125 "Free frag %p\n",
3126 frag);
3127 GNUNET_free (frag);
3128 }
3129}
3130
3131
3132/**
3133 * Release memory associated with @a pm and remove @a pm from associated
3134 * data structures. @a pm must be a top-level pending message and not
3135 * a fragment in the tree. The entire tree is freed (if applicable).
3136 *
3137 * @param pm the pending message to free
3138 */
3139static void
3140free_pending_message (struct PendingMessage *pm)
3141{
3142 struct TransportClient *tc = pm->client;
3143 struct VirtualLink *vl = pm->vl;
3144 struct PendingAcknowledgement *pa;
3145
3146 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3147 "Freeing pm %p\n",
3148 pm);
3149 if (NULL != tc)
3150 {
3151 GNUNET_CONTAINER_MDLL_remove (client,
3152 tc->details.core.pending_msg_head,
3153 tc->details.core.pending_msg_tail,
3154 pm);
3155 }
3156 if ((NULL != vl) && (NULL == pm->frag_parent))
3157 {
3158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3159 "Removing pm %" PRIu64 "\n",
3160 pm->logging_uuid);
3161 GNUNET_CONTAINER_MDLL_remove (vl,
3162 vl->pending_msg_head,
3163 vl->pending_msg_tail,
3164 pm);
3165 }
3166 else if (NULL != pm->frag_parent && PMT_DV_BOX != pm->pmt)
3167 {
3168 struct PendingMessage *root = pm->frag_parent;
3169
3170 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
3171 root = root->frag_parent;
3172
3173 root->frag_count--;
3174 }
3175 while (NULL != (pa = pm->pa_head))
3176 {
3177 if (NULL == pa)
3178 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3179 "free pending pa null\n");
3180 if (NULL == pm->pa_tail)
3181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3182 "free pending pa_tail null\n");
3183 if (NULL == pa->prev_pa)
3184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3185 "free pending pa prev null\n");
3186 if (NULL == pa->next_pa)
3187 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3188 "free pending pa next null\n");
3189 GNUNET_CONTAINER_MDLL_remove (pm, pm->pa_head, pm->pa_tail, pa);
3190 pa->pm = NULL;
3191 }
3192
3193 free_fragment_tree (pm);
3194 if (NULL != pm->qe)
3195 {
3196 GNUNET_assert (pm == pm->qe->pm);
3197 pm->qe->pm = NULL;
3198 }
3199 if (NULL != pm->bpm)
3200 {
3201 free_fragment_tree (pm->bpm);
3202 if (NULL != pm->bpm->qe)
3203 {
3204 struct QueueEntry *qe = pm->bpm->qe;
3205
3206 qe->pm = NULL;
3207 }
3208 GNUNET_free (pm->bpm);
3209 }
3210
3211 GNUNET_free (pm);
3212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3213 "Freeing pm done\n");
3214}
3215
3216
3217/**
3218 * Free @a rc
3219 *
3220 * @param rc data structure to free
3221 */
3222static void
3223free_reassembly_context (struct ReassemblyContext *rc)
3224{
3225 struct VirtualLink *vl = rc->virtual_link;
3226
3227 GNUNET_assert (rc == GNUNET_CONTAINER_heap_remove_node (rc->hn));
3228 GNUNET_assert (GNUNET_OK ==
3229 GNUNET_CONTAINER_multihashmap32_remove (vl->reassembly_map,
3230 rc->msg_uuid.uuid,
3231 rc));
3232 GNUNET_free (rc);
3233}
3234
3235
3236/**
3237 * Task run to clean up reassembly context of a neighbour that have expired.
3238 *
3239 * @param cls a `struct Neighbour`
3240 */
3241static void
3242reassembly_cleanup_task (void *cls)
3243{
3244 struct VirtualLink *vl = cls;
3245 struct ReassemblyContext *rc;
3246
3247 vl->reassembly_timeout_task = NULL;
3248 while (NULL != (rc = GNUNET_CONTAINER_heap_peek (vl->reassembly_heap)))
3249 {
3250 if (0 == GNUNET_TIME_absolute_get_remaining (rc->reassembly_timeout)
3251 .rel_value_us)
3252 {
3253 free_reassembly_context (rc);
3254 continue;
3255 }
3256 GNUNET_assert (NULL == vl->reassembly_timeout_task);
3257 vl->reassembly_timeout_task =
3258 GNUNET_SCHEDULER_add_at (rc->reassembly_timeout,
3259 &reassembly_cleanup_task,
3260 vl);
3261 return;
3262 }
3263}
3264
3265
3266/**
3267 * function called to #free_reassembly_context().
3268 *
3269 * @param cls NULL
3270 * @param key unused
3271 * @param value a `struct ReassemblyContext` to free
3272 * @return #GNUNET_OK (continue iteration)
3273 */
3274static int
3275free_reassembly_cb (void *cls, uint32_t key, void *value)
3276{
3277 struct ReassemblyContext *rc = value;
3278
3279 (void) cls;
3280 (void) key;
3281 free_reassembly_context (rc);
3282 return GNUNET_OK;
3283}
3284
3285
3286/**
3287 * Free virtual link.
3288 *
3289 * @param vl link data to free
3290 */
3291static void
3292free_virtual_link (struct VirtualLink *vl)
3293{
3294 struct PendingMessage *pm;
3295 struct CoreSentContext *csc;
3296
3297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3298 "free virtual link %p\n",
3299 vl);
3300
3301 if (NULL != vl->reassembly_map)
3302 {
3303 GNUNET_CONTAINER_multihashmap32_iterate (vl->reassembly_map,
3304 &free_reassembly_cb,
3305 NULL);
3306 GNUNET_CONTAINER_multihashmap32_destroy (vl->reassembly_map);
3307 vl->reassembly_map = NULL;
3308 GNUNET_CONTAINER_heap_destroy (vl->reassembly_heap);
3309 vl->reassembly_heap = NULL;
3310 }
3311 if (NULL != vl->reassembly_timeout_task)
3312 {
3313 GNUNET_SCHEDULER_cancel (vl->reassembly_timeout_task);
3314 vl->reassembly_timeout_task = NULL;
3315 }
3316 while (NULL != (pm = vl->pending_msg_head))
3317 free_pending_message (pm);
3318 GNUNET_assert (GNUNET_YES ==
3319 GNUNET_CONTAINER_multipeermap_remove (links, &vl->target, vl));
3320 if (NULL != vl->visibility_task)
3321 {
3322 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3323 vl->visibility_task = NULL;
3324 }
3325 if (NULL != vl->fc_retransmit_task)
3326 {
3327 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
3328 vl->fc_retransmit_task = NULL;
3329 }
3330 while (NULL != (csc = vl->csc_head))
3331 {
3332 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, csc);
3333 GNUNET_assert (vl == csc->vl);
3334 csc->vl = NULL;
3335 }
3336 GNUNET_break (NULL == vl->n);
3337 GNUNET_break (NULL == vl->dv);
3338 GNUNET_free (vl);
3339}
3340
3341
3342/**
3343 * Free validation state.
3344 *
3345 * @param vs validation state to free
3346 */
3347static void
3348free_validation_state (struct ValidationState *vs)
3349{
3350 if (NULL != vs->revalidation_task)
3351 {
3352 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
3353 vs->revalidation_task = NULL;
3354 }
3355 /*memcpy (&hkey,
3356 &hc,
3357 sizeof (hkey));*/
3358 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3359 "Remove key %s for address %s map size %u contains %u during freeing state\n",
3360 GNUNET_h2s (&vs->hc),
3361 vs->address,
3362 GNUNET_CONTAINER_multihashmap_size (revalidation_map),
3363 GNUNET_CONTAINER_multihashmap_contains (revalidation_map,
3364 &vs->hc));
3365 GNUNET_CONTAINER_multihashmap_remove (revalidation_map, &vs->hc, vs);
3366 GNUNET_assert (
3367 GNUNET_YES ==
3368 GNUNET_CONTAINER_multipeermap_remove (validation_map, &vs->pid, vs));
3369 GNUNET_CONTAINER_heap_remove_node (vs->hn);
3370 vs->hn = NULL;
3371 if (NULL != vs->sc)
3372 {
3373 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3374 "store cancel\n");
3375 GNUNET_PEERSTORE_store_cancel (vs->sc);
3376 vs->sc = NULL;
3377 }
3378 GNUNET_free (vs->address);
3379 GNUNET_free (vs);
3380}
3381
3382
3383/**
3384 * Lookup neighbour for peer @a pid.
3385 *
3386 * @param pid neighbour to look for
3387 * @return NULL if we do not have this peer as a neighbour
3388 */
3389static struct Neighbour *
3390lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
3391{
3392 return GNUNET_CONTAINER_multipeermap_get (neighbours, pid);
3393}
3394
3395
3396/**
3397 * Lookup virtual link for peer @a pid.
3398 *
3399 * @param pid virtual link to look for
3400 * @return NULL if we do not have this peer as a virtual link
3401 */
3402static struct VirtualLink *
3403lookup_virtual_link (const struct GNUNET_PeerIdentity *pid)
3404{
3405 return GNUNET_CONTAINER_multipeermap_get (links, pid);
3406}
3407
3408
3409/**
3410 * Details about what to notify monitors about.
3411 */
3412struct MonitorEvent
3413{
3414 /**
3415 * @deprecated To be discussed if we keep these...
3416 */
3417 struct GNUNET_TIME_Absolute last_validation;
3418 struct GNUNET_TIME_Absolute valid_until;
3419 struct GNUNET_TIME_Absolute next_validation;
3420
3421 /**
3422 * Current round-trip time estimate.
3423 */
3424 struct GNUNET_TIME_Relative rtt;
3425
3426 /**
3427 * Connection status.
3428 */
3429 enum GNUNET_TRANSPORT_ConnectionStatus cs;
3430
3431 /**
3432 * Messages pending.
3433 */
3434 uint32_t num_msg_pending;
3435
3436 /**
3437 * Bytes pending.
3438 */
3439 uint32_t num_bytes_pending;
3440};
3441
3442
3443/**
3444 * Free a @a dvh. Callers MAY want to check if this was the last path to the
3445 * `target`, and if so call #free_dv_route to also free the associated DV
3446 * entry in #dv_routes (if not, the associated scheduler job should eventually
3447 * take care of it).
3448 *
3449 * @param dvh hop to free
3450 */
3451static void
3452free_distance_vector_hop (struct DistanceVectorHop *dvh)
3453{
3454 struct Neighbour *n = dvh->next_hop;
3455 struct DistanceVector *dv = dvh->dv;
3456 struct PendingAcknowledgement *pa;
3457
3458 while (NULL != (pa = dvh->pa_head))
3459 {
3460 GNUNET_CONTAINER_MDLL_remove (dvh, dvh->pa_head, dvh->pa_tail, pa);
3461 pa->dvh = NULL;
3462 }
3463 GNUNET_CONTAINER_MDLL_remove (neighbour, n->dv_head, n->dv_tail, dvh);
3464 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, dvh);
3465 GNUNET_free (dvh);
3466}
3467
3468
3469/**
3470 * Task run to check whether the hops of the @a cls still
3471 * are validated, or if we need to core about disconnection.
3472 *
3473 * @param cls a `struct VirtualLink`
3474 */
3475static void
3476check_link_down (void *cls);
3477
3478
3479/**
3480 * Send message to CORE clients that we lost a connection.
3481 *
3482 * @param pid peer the connection was for
3483 */
3484static void
3485cores_send_disconnect_info (const struct GNUNET_PeerIdentity *pid)
3486{
3487 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3488 "Informing CORE clients about disconnect from %s\n",
3489 GNUNET_i2s (pid));
3490 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3491 {
3492 struct GNUNET_MQ_Envelope *env;
3493 struct DisconnectInfoMessage *dim;
3494
3495 if (CT_CORE != tc->type)
3496 continue;
3497 env = GNUNET_MQ_msg (dim, GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
3498 dim->peer = *pid;
3499 GNUNET_MQ_send (tc->mq, env);
3500 }
3501}
3502
3503
3504/**
3505 * Free entry in #dv_routes. First frees all hops to the target, and
3506 * if there are no entries left, frees @a dv as well.
3507 *
3508 * @param dv route to free
3509 */
3510static void
3511free_dv_route (struct DistanceVector *dv)
3512{
3513 struct DistanceVectorHop *dvh;
3514
3515 while (NULL != (dvh = dv->dv_head))
3516 free_distance_vector_hop (dvh);
3517 if (NULL == dv->dv_head)
3518 {
3519 struct VirtualLink *vl;
3520
3521 GNUNET_assert (
3522 GNUNET_YES ==
3523 GNUNET_CONTAINER_multipeermap_remove (dv_routes, &dv->target, dv));
3524 if (NULL != (vl = dv->vl))
3525 {
3526 GNUNET_assert (dv == vl->dv);
3527 vl->dv = NULL;
3528 if (NULL == vl->n)
3529 {
3530 cores_send_disconnect_info (&dv->target);
3531 free_virtual_link (vl);
3532 }
3533 else
3534 {
3535 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3536 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3537 }
3538 dv->vl = NULL;
3539 }
3540
3541 if (NULL != dv->timeout_task)
3542 {
3543 GNUNET_SCHEDULER_cancel (dv->timeout_task);
3544 dv->timeout_task = NULL;
3545 }
3546 GNUNET_free (dv->km);
3547 GNUNET_free (dv);
3548 }
3549}
3550
3551
3552/**
3553 * Notify monitor @a tc about an event. That @a tc
3554 * cares about the event has already been checked.
3555 *
3556 * Send @a tc information in @a me about a @a peer's status with
3557 * respect to some @a address to all monitors that care.
3558 *
3559 * @param tc monitor to inform
3560 * @param peer peer the information is about
3561 * @param address address the information is about
3562 * @param nt network type associated with @a address
3563 * @param me detailed information to transmit
3564 */
3565static void
3566notify_monitor (struct TransportClient *tc,
3567 const struct GNUNET_PeerIdentity *peer,
3568 const char *address,
3569 enum GNUNET_NetworkType nt,
3570 const struct MonitorEvent *me)
3571{
3572 struct GNUNET_MQ_Envelope *env;
3573 struct GNUNET_TRANSPORT_MonitorData *md;
3574 size_t addr_len = strlen (address) + 1;
3575
3576 env = GNUNET_MQ_msg_extra (md,
3577 addr_len,
3578 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA);
3579 md->nt = htonl ((uint32_t) nt);
3580 md->peer = *peer;
3581 md->last_validation = GNUNET_TIME_absolute_hton (me->last_validation);
3582 md->valid_until = GNUNET_TIME_absolute_hton (me->valid_until);
3583 md->next_validation = GNUNET_TIME_absolute_hton (me->next_validation);
3584 md->rtt = GNUNET_TIME_relative_hton (me->rtt);
3585 md->cs = htonl ((uint32_t) me->cs);
3586 md->num_msg_pending = htonl (me->num_msg_pending);
3587 md->num_bytes_pending = htonl (me->num_bytes_pending);
3588 memcpy (&md[1], address, addr_len);
3589 GNUNET_MQ_send (tc->mq, env);
3590}
3591
3592
3593/**
3594 * Send information in @a me about a @a peer's status with respect
3595 * to some @a address to all monitors that care.
3596 *
3597 * @param peer peer the information is about
3598 * @param address address the information is about
3599 * @param nt network type associated with @a address
3600 * @param me detailed information to transmit
3601 */
3602static void
3603notify_monitors (const struct GNUNET_PeerIdentity *peer,
3604 const char *address,
3605 enum GNUNET_NetworkType nt,
3606 const struct MonitorEvent *me)
3607{
3608 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3609 {
3610 if (CT_MONITOR != tc->type)
3611 continue;
3612 if (tc->details.monitor.one_shot)
3613 continue;
3614 if ((GNUNET_NO == GNUNET_is_zero (&tc->details.monitor.peer)) &&
3615 (0 != GNUNET_memcmp (&tc->details.monitor.peer, peer)))
3616 continue;
3617 notify_monitor (tc, peer, address, nt, me);
3618 }
3619}
3620
3621
3622/**
3623 * Called whenever a client connects. Allocates our
3624 * data structures associated with that client.
3625 *
3626 * @param cls closure, NULL
3627 * @param client identification of the client
3628 * @param mq message queue for the client
3629 * @return our `struct TransportClient`
3630 */
3631static void *
3632client_connect_cb (void *cls,
3633 struct GNUNET_SERVICE_Client *client,
3634 struct GNUNET_MQ_Handle *mq)
3635{
3636 struct TransportClient *tc;
3637
3638 (void) cls;
3639 tc = GNUNET_new (struct TransportClient);
3640 tc->client = client;
3641 tc->mq = mq;
3642 GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
3643 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3644 "Client %p of type %u connected\n",
3645 tc,
3646 tc->type);
3647 return tc;
3648}
3649
3650
3651static enum GNUNET_GenericReturnValue
3652remove_global_addresses (void *cls,
3653 const struct GNUNET_PeerIdentity *pid,
3654 void *value)
3655{
3656 (void) cls;
3657 struct TransportGlobalNattedAddress *tgna = value;
3658
3659 GNUNET_free (tgna);
3660}
3661
3662
3663/**
3664 * Release memory used by @a neighbour.
3665 *
3666 * @param neighbour neighbour entry to free
3667 */
3668static void
3669free_neighbour (struct Neighbour *neighbour)
3670{
3671 struct DistanceVectorHop *dvh;
3672 struct VirtualLink *vl;
3673
3674 GNUNET_assert (NULL == neighbour->queue_head);
3675 GNUNET_assert (GNUNET_YES ==
3676 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3677 &neighbour->pid,
3678 neighbour));
3679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3680 "Freeing neighbour\n");
3681 GNUNET_CONTAINER_multipeermap_iterate (neighbour->natted_addresses,
3682 &remove_global_addresses,
3683 NULL);
3684 GNUNET_CONTAINER_multipeermap_destroy (neighbour->natted_addresses);
3685 while (NULL != (dvh = neighbour->dv_head))
3686 {
3687 struct DistanceVector *dv = dvh->dv;
3688
3689 free_distance_vector_hop (dvh);
3690 if (NULL == dv->dv_head)
3691 free_dv_route (dv);
3692 }
3693 if (NULL != neighbour->get)
3694 {
3695 GNUNET_PEERSTORE_iteration_stop (neighbour->get);
3696 neighbour->get = NULL;
3697 }
3698 if (NULL != neighbour->sc)
3699 {
3700 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3701 "store cancel\n");
3702 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3703 neighbour->sc = NULL;
3704 }
3705 if (NULL != (vl = neighbour->vl))
3706 {
3707 GNUNET_assert (neighbour == vl->n);
3708 vl->n = NULL;
3709 if (NULL == vl->dv)
3710 {
3711 cores_send_disconnect_info (&vl->target);
3712 free_virtual_link (vl);
3713 }
3714 else
3715 {
3716 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3717 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3718 }
3719 neighbour->vl = NULL;
3720 }
3721 GNUNET_free (neighbour);
3722}
3723
3724
3725/**
3726 * Send message to CORE clients that we lost a connection.
3727 *
3728 * @param tc client to inform (must be CORE client)
3729 * @param pid peer the connection is for
3730 */
3731static void
3732core_send_connect_info (struct TransportClient *tc,
3733 const struct GNUNET_PeerIdentity *pid)
3734{
3735 struct GNUNET_MQ_Envelope *env;
3736 struct ConnectInfoMessage *cim;
3737
3738 GNUNET_assert (CT_CORE == tc->type);
3739 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3740 cim->id = *pid;
3741 GNUNET_MQ_send (tc->mq, env);
3742}
3743
3744
3745/**
3746 * Send message to CORE clients that we gained a connection
3747 *
3748 * @param pid peer the queue was for
3749 */
3750static void
3751cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3752{
3753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3754 "Informing CORE clients about connection to %s\n",
3755 GNUNET_i2s (pid));
3756 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3757 {
3758 if (CT_CORE != tc->type)
3759 continue;
3760 core_send_connect_info (tc, pid);
3761 }
3762}
3763
3764
3765/**
3766 * We believe we are ready to transmit a message on a queue. Gives the
3767 * message to the communicator for transmission (updating the tracker,
3768 * and re-scheduling itself if applicable).
3769 *
3770 * @param cls the `struct Queue` to process transmissions for
3771 */
3772static void
3773transmit_on_queue (void *cls);
3774
3775
3776/**
3777 * Check if the communicator has another queue with higher prio ready for sending.
3778 */
3779static unsigned int
3780check_for_queue_with_higher_prio (struct Queue *queue, struct Queue *queue_head)
3781{
3782 for (struct Queue *s = queue_head; NULL != s;
3783 s = s->next_client)
3784 {
3785 if (s->tc->details.communicator.address_prefix !=
3786 queue->tc->details.communicator.address_prefix)
3787 {
3788 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3789 "queue address %s qid %u compare with queue: address %s qid %u\n",
3790 queue->address,
3791 queue->qid,
3792 s->address,
3793 s->qid);
3794 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
3795 (QUEUE_LENGTH_LIMIT > s->queue_length) )
3796 return GNUNET_YES;
3797 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3798 "Lower prio\n");
3799 }
3800 }
3801 return GNUNET_NO;
3802}
3803
3804
3805/**
3806 * Called whenever something changed that might effect when we
3807 * try to do the next transmission on @a queue using #transmit_on_queue().
3808 *
3809 * @param queue the queue to do scheduling for
3810 * @param p task priority to use, if @a queue is scheduled
3811 */
3812static void
3813schedule_transmit_on_queue (struct GNUNET_TIME_Relative delay,
3814 struct Queue *queue,
3815 enum GNUNET_SCHEDULER_Priority p)
3816{
3817 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
3818
3819 if (queue->validated_until.abs_value_us < now.abs_value_us)
3820 return;
3821 if (check_for_queue_with_higher_prio (queue,
3822 queue->tc->details.communicator.
3823 queue_head))
3824 return;
3825
3826 if (queue->tc->details.communicator.total_queue_length >=
3827 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3828 {
3829 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3830 "Transmission on queue %s (QID %u) throttled due to communicator queue limit\n",
3831 queue->address,
3832 queue->qid);
3833 GNUNET_STATISTICS_update (
3834 GST_stats,
3835 "# Transmission throttled due to communicator queue limit",
3836 1,
3837 GNUNET_NO);
3838 queue->idle = GNUNET_NO;
3839 return;
3840 }
3841 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3842 {
3843 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3844 "Transmission on queue %s (QID %u) throttled due to communicator queue length limit\n",
3845 queue->address,
3846 queue->qid);
3847 GNUNET_STATISTICS_update (GST_stats,
3848 "# Transmission throttled due to queue queue limit",
3849 1,
3850 GNUNET_NO);
3851 queue->idle = GNUNET_NO;
3852 return;
3853 }
3854 if (0 == queue->q_capacity)
3855 {
3856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3857 "Transmission on queue %s (QID %u) throttled due to communicator message has capacity %"
3858 PRIu64 ".\n",
3859 queue->address,
3860 queue->qid,
3861 queue->q_capacity);
3862 GNUNET_STATISTICS_update (GST_stats,
3863 "# Transmission throttled due to message queue capacity",
3864 1,
3865 GNUNET_NO);
3866 queue->idle = GNUNET_NO;
3867 return;
3868 }
3869 /* queue might indeed be ready, schedule it */
3870 if (NULL != queue->transmit_task)
3871 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3872 queue->transmit_task =
3873 GNUNET_SCHEDULER_add_delayed_with_priority (delay, p, &transmit_on_queue,
3874 queue);
3875 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3876 "Considering transmission on queue `%s' QID %llu to %s\n",
3877 queue->address,
3878 (unsigned long long) queue->qid,
3879 GNUNET_i2s (&queue->neighbour->pid));
3880}
3881
3882
3883/**
3884 * Task run to check whether the hops of the @a cls still
3885 * are validated, or if we need to core about disconnection.
3886 *
3887 * @param cls a `struct VirtualLink`
3888 */
3889static void
3890check_link_down (void *cls)
3891{
3892 struct VirtualLink *vl = cls;
3893 struct DistanceVector *dv = vl->dv;
3894 struct Neighbour *n = vl->n;
3895 struct GNUNET_TIME_Absolute dvh_timeout;
3896 struct GNUNET_TIME_Absolute q_timeout;
3897
3898 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3899 "Checking if link is down\n");
3900 vl->visibility_task = NULL;
3901 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3902 if (NULL != dv)
3903 {
3904 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3905 pos = pos->next_dv)
3906 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
3907 pos->path_valid_until);
3908 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3909 {
3910 vl->dv->vl = NULL;
3911 vl->dv = NULL;
3912 }
3913 }
3914 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3915 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3916 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3917 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3918 {
3919 vl->n->vl = NULL;
3920 vl->n = NULL;
3921 }
3922 if ((NULL == vl->n) && (NULL == vl->dv))
3923 {
3924 cores_send_disconnect_info (&vl->target);
3925 free_virtual_link (vl);
3926 return;
3927 }
3928 vl->visibility_task =
3929 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3930 &check_link_down,
3931 vl);
3932}
3933
3934
3935/**
3936 * Free @a queue.
3937 *
3938 * @param queue the queue to free
3939 */
3940static void
3941free_queue (struct Queue *queue)
3942{
3943 struct Neighbour *neighbour = queue->neighbour;
3944 struct TransportClient *tc = queue->tc;
3945 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
3946 .rtt = GNUNET_TIME_UNIT_FOREVER_REL };
3947 struct QueueEntry *qe;
3948 int maxxed;
3949 struct PendingAcknowledgement *pa;
3950 struct VirtualLink *vl;
3951
3952 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3953 "Cleaning up queue %u\n", queue->qid);
3954 if (NULL != queue->mo)
3955 {
3956 GNUNET_PEERSTORE_monitor_stop (queue->mo);
3957 queue->mo = NULL;
3958 }
3959 if (NULL != queue->transmit_task)
3960 {
3961 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3962 queue->transmit_task = NULL;
3963 }
3964 while (NULL != (pa = queue->pa_head))
3965 {
3966 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3967 pa->queue = NULL;
3968 }
3969
3970 GNUNET_CONTAINER_MDLL_remove (neighbour,
3971 neighbour->queue_head,
3972 neighbour->queue_tail,
3973 queue);
3974 GNUNET_CONTAINER_MDLL_remove (client,
3975 tc->details.communicator.queue_head,
3976 tc->details.communicator.queue_tail,
3977 queue);
3978 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT <=
3979 tc->details.communicator.total_queue_length);
3980 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3981 "Cleaning up queue with length %u\n",
3982 queue->queue_length);
3983 while (NULL != (qe = queue->queue_head))
3984 {
3985 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3986 queue->queue_length--;
3987 tc->details.communicator.total_queue_length--;
3988 if (NULL != qe->pm)
3989 {
3990 GNUNET_assert (qe == qe->pm->qe);
3991 qe->pm->qe = NULL;
3992 }
3993 GNUNET_free (qe);
3994 }
3995 GNUNET_assert (0 == queue->queue_length);
3996 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
3997 tc->details.communicator.total_queue_length))
3998 {
3999 /* Communicator dropped below threshold, resume all _other_ queues */
4000 GNUNET_STATISTICS_update (
4001 GST_stats,
4002 "# Transmission throttled due to communicator queue limit",
4003 -1,
4004 GNUNET_NO);
4005 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
4006 s = s->next_client)
4007 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
4008 s,
4009 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
4010 }
4011 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
4012 GNUNET_free (queue);
4013
4014 vl = lookup_virtual_link (&neighbour->pid);
4015 if ((NULL != vl) && (neighbour == vl->n))
4016 {
4017 GNUNET_SCHEDULER_cancel (vl->visibility_task);
4018 check_link_down (vl);
4019 }
4020 if (NULL == neighbour->queue_head)
4021 {
4022 free_neighbour (neighbour);
4023 }
4024}
4025
4026
4027/**
4028 * Free @a ale
4029 *
4030 * @param ale address list entry to free
4031 */
4032static void
4033free_address_list_entry (struct AddressListEntry *ale)
4034{
4035 struct TransportClient *tc = ale->tc;
4036
4037 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
4038 tc->details.communicator.addr_tail,
4039 ale);
4040 if (NULL != ale->sc)
4041 {
4042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4043 "store cancel\n");
4044 GNUNET_PEERSTORE_store_cancel (ale->sc);
4045 ale->sc = NULL;
4046 }
4047 if (NULL != ale->st)
4048 {
4049 GNUNET_SCHEDULER_cancel (ale->st);
4050 ale->st = NULL;
4051 }
4052 if (NULL != ale->signed_address)
4053 GNUNET_free (ale->signed_address);
4054 GNUNET_free (ale);
4055}
4056
4057
4058/**
4059 * Stop the peer request in @a value.
4060 *
4061 * @param cls a `struct TransportClient` that no longer makes the request
4062 * @param pid the peer's identity
4063 * @param value a `struct PeerRequest`
4064 * @return #GNUNET_YES (always)
4065 */
4066static int
4067stop_peer_request (void *cls,
4068 const struct GNUNET_PeerIdentity *pid,
4069 void *value)
4070{
4071 struct TransportClient *tc = cls;
4072 struct PeerRequest *pr = value;
4073
4074 if (NULL != pr->nc)
4075 GNUNET_PEERSTORE_monitor_stop (pr->nc);
4076 pr->nc = NULL;
4077 GNUNET_assert (
4078 GNUNET_YES ==
4079 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
4080 pid,
4081 pr));
4082 GNUNET_free (pr);
4083
4084 return GNUNET_OK;
4085}
4086
4087
4088static void
4089do_shutdown (void *cls);
4090
4091/**
4092 * Called whenever a client is disconnected. Frees our
4093 * resources associated with that client.
4094 *
4095 * @param cls closure, NULL
4096 * @param client identification of the client
4097 * @param app_ctx our `struct TransportClient`
4098 */
4099static void
4100client_disconnect_cb (void *cls,
4101 struct GNUNET_SERVICE_Client *client,
4102 void *app_ctx)
4103{
4104 struct TransportClient *tc = app_ctx;
4105
4106 (void) cls;
4107 (void) client;
4108 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
4109 switch (tc->type)
4110 {
4111 case CT_NONE:
4112 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4113 "Unknown Client %p disconnected, cleaning up.\n",
4114 tc);
4115 break;
4116
4117 case CT_CORE: {
4118 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4119 "CORE Client %p disconnected, cleaning up.\n",
4120 tc);
4121
4122 struct PendingMessage *pm;
4123
4124 while (NULL != (pm = tc->details.core.pending_msg_head))
4125 {
4126 GNUNET_CONTAINER_MDLL_remove (client,
4127 tc->details.core.pending_msg_head,
4128 tc->details.core.pending_msg_tail,
4129 pm);
4130 pm->client = NULL;
4131 }
4132 }
4133 break;
4134
4135 case CT_MONITOR:
4136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4137 "MONITOR Client %p disconnected, cleaning up.\n",
4138 tc);
4139
4140 break;
4141
4142 case CT_COMMUNICATOR: {
4143 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4144 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
4145 tc);
4146
4147 struct Queue *q;
4148 struct AddressListEntry *ale;
4149
4150 if (NULL != tc->details.communicator.free_queue_entry_task)
4151 GNUNET_SCHEDULER_cancel (
4152 tc->details.communicator.free_queue_entry_task);
4153 while (NULL != (q = tc->details.communicator.queue_head))
4154 free_queue (q);
4155 while (NULL != (ale = tc->details.communicator.addr_head))
4156 free_address_list_entry (ale);
4157 GNUNET_free (tc->details.communicator.address_prefix);
4158 }
4159 break;
4160
4161 case CT_APPLICATION:
4162 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4163 "APPLICATION Client %p disconnected, cleaning up.\n",
4164 tc);
4165
4166 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
4167 &stop_peer_request,
4168 tc);
4169 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
4170 break;
4171 }
4172 GNUNET_free (tc);
4173 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
4174 {
4175 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4176 "Our last client disconnected\n");
4177 do_shutdown (cls);
4178 }
4179}
4180
4181
4182/**
4183 * Iterator telling new CORE client about all existing
4184 * connections to peers.
4185 *
4186 * @param cls the new `struct TransportClient`
4187 * @param pid a connected peer
4188 * @param value the `struct Neighbour` with more information
4189 * @return #GNUNET_OK (continue to iterate)
4190 */
4191static int
4192notify_client_connect_info (void *cls,
4193 const struct GNUNET_PeerIdentity *pid,
4194 void *value)
4195{
4196 struct TransportClient *tc = cls;
4197 struct VirtualLink *vl = value;
4198
4199 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4200 return GNUNET_OK;
4201
4202 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4203 "Telling new CORE client about existing connection to %s\n",
4204 GNUNET_i2s (pid));
4205 core_send_connect_info (tc, pid);
4206 return GNUNET_OK;
4207}
4208
4209
4210/**
4211 * Send ACK to communicator (if requested) and free @a cmc.
4212 *
4213 * @param cmc context for which we are done handling the message
4214 */
4215static void
4216finish_cmc_handling_with_continue (struct CommunicatorMessageContext *cmc,
4217 unsigned
4218 int free_cmc);
4219
4220static enum GNUNET_GenericReturnValue
4221resume_communicators (void *cls,
4222 const struct GNUNET_PeerIdentity *pid,
4223 void *value)
4224{
4225 struct VirtualLink *vl = value;
4226 struct CommunicatorMessageContext *cmc;
4227
4228 /* resume communicators */
4229 while (NULL != (cmc = vl->cmc_tail))
4230 {
4231 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4232 if (GNUNET_NO == cmc->continue_send)
4233 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
4234 }
4235 return GNUNET_OK;
4236}
4237
4238
4239/**
4240 * Initialize a "CORE" client. We got a start message from this
4241 * client, so add it to the list of clients for broadcasting of
4242 * inbound messages.
4243 *
4244 * @param cls the client
4245 * @param start the start message that was sent
4246 */
4247static void
4248handle_client_start (void *cls, const struct StartMessage *start)
4249{
4250 struct TransportClient *tc = cls;
4251 uint32_t options;
4252
4253 options = ntohl (start->options);
4254 if ((0 != (1 & options)) &&
4255 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
4256 {
4257 /* client thinks this is a different peer, reject */
4258 GNUNET_break (0);
4259 GNUNET_SERVICE_client_drop (tc->client);
4260 return;
4261 }
4262 if (CT_NONE != tc->type)
4263 {
4264 GNUNET_break (0);
4265 GNUNET_SERVICE_client_drop (tc->client);
4266 return;
4267 }
4268 tc->type = CT_CORE;
4269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4270 "New CORE client with PID %s registered\n",
4271 GNUNET_i2s (&start->self));
4272 GNUNET_CONTAINER_multipeermap_iterate (links,
4273 &notify_client_connect_info,
4274 tc);
4275 GNUNET_CONTAINER_multipeermap_iterate (links,
4276 &resume_communicators,
4277 NULL);
4278 GNUNET_SERVICE_client_continue (tc->client);
4279}
4280
4281
4282/**
4283 * Client asked for transmission to a peer. Process the request.
4284 *
4285 * @param cls the client
4286 * @param obm the send message that was sent
4287 */
4288static int
4289check_client_send (void *cls, const struct OutboundMessage *obm)
4290{
4291 struct TransportClient *tc = cls;
4292 uint16_t size;
4293 const struct GNUNET_MessageHeader *obmm;
4294
4295 if (CT_CORE != tc->type)
4296 {
4297 GNUNET_break (0);
4298 return GNUNET_SYSERR;
4299 }
4300 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
4301 if (size < sizeof(struct GNUNET_MessageHeader))
4302 {
4303 GNUNET_break (0);
4304 return GNUNET_SYSERR;
4305 }
4306 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4307 if (size != ntohs (obmm->size))
4308 {
4309 GNUNET_break (0);
4310 return GNUNET_SYSERR;
4311 }
4312 return GNUNET_OK;
4313}
4314
4315
4316/**
4317 * Send a response to the @a pm that we have processed a "send"
4318 * request. Sends a confirmation to the "core" client responsible for
4319 * the original request and free's @a pm.
4320 *
4321 * @param pm handle to the original pending message
4322 */
4323static void
4324client_send_response (struct PendingMessage *pm)
4325{
4326 struct TransportClient *tc = pm->client;
4327 struct VirtualLink *vl = pm->vl;
4328
4329 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4330 "client send response\n");
4331 if (NULL != tc)
4332 {
4333 struct GNUNET_MQ_Envelope *env;
4334 struct SendOkMessage *so_msg;
4335
4336 env = GNUNET_MQ_msg (so_msg, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
4337 so_msg->peer = vl->target;
4338 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4339 "Confirming transmission of <%" PRIu64 "> to %s\n",
4340 pm->logging_uuid,
4341 GNUNET_i2s (&vl->target));
4342 GNUNET_MQ_send (tc->mq, env);
4343 }
4344 free_pending_message (pm);
4345}
4346
4347
4348/**
4349 * Pick @a hops_array_length random DV paths satisfying @a options
4350 *
4351 * @param dv data structure to pick paths from
4352 * @param options constraints to satisfy
4353 * @param[out] hops_array set to the result
4354 * @param hops_array_length length of the @a hops_array
4355 * @return number of entries set in @a hops_array
4356 */
4357static unsigned int
4358pick_random_dv_hops (const struct DistanceVector *dv,
4359 enum RouteMessageOptions options,
4360 struct DistanceVectorHop **hops_array,
4361 unsigned int hops_array_length)
4362{
4363 uint64_t choices[hops_array_length];
4364 uint64_t num_dv;
4365 unsigned int dv_count;
4366
4367 /* Pick random vectors, but weighted by distance, giving more weight
4368 to shorter vectors */
4369 num_dv = 0;
4370 dv_count = 0;
4371 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4372 pos = pos->next_dv)
4373 {
4374 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4375 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4376 .rel_value_us == 0))
4377 continue; /* pos unconfirmed and confirmed required */
4378 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
4379 dv_count++;
4380 }
4381 if (0 == dv_count)
4382 return 0;
4383 if (dv_count <= hops_array_length)
4384 {
4385 dv_count = 0;
4386 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4387 pos = pos->next_dv)
4388 hops_array[dv_count++] = pos;
4389 return dv_count;
4390 }
4391 for (unsigned int i = 0; i < hops_array_length; i++)
4392 {
4393 int ok = GNUNET_NO;
4394 while (GNUNET_NO == ok)
4395 {
4396 choices[i] =
4397 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
4398 ok = GNUNET_YES;
4399 for (unsigned int j = 0; j < i; j++)
4400 if (choices[i] == choices[j])
4401 {
4402 ok = GNUNET_NO;
4403 break;
4404 }
4405 }
4406 }
4407 dv_count = 0;
4408 num_dv = 0;
4409 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4410 pos = pos->next_dv)
4411 {
4412 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
4413
4414 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4415 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4416 .rel_value_us == 0))
4417 continue; /* pos unconfirmed and confirmed required */
4418 for (unsigned int i = 0; i < hops_array_length; i++)
4419 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
4420 hops_array[dv_count++] = pos;
4421 num_dv += delta;
4422 }
4423 return dv_count;
4424}
4425
4426
4427/**
4428 * Communicator started. Test message is well-formed.
4429 *
4430 * @param cls the client
4431 * @param cam the send message that was sent
4432 */
4433static int
4434check_communicator_available (
4435 void *cls,
4436 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4437{
4438 struct TransportClient *tc = cls;
4439 uint16_t size;
4440
4441 if (CT_NONE != tc->type)
4442 {
4443 GNUNET_break (0);
4444 return GNUNET_SYSERR;
4445 }
4446 tc->type = CT_COMMUNICATOR;
4447 size = ntohs (cam->header.size) - sizeof(*cam);
4448 if (0 == size)
4449 return GNUNET_OK; /* receive-only communicator */
4450 GNUNET_MQ_check_zero_termination (cam);
4451 return GNUNET_OK;
4452}
4453
4454
4455/**
4456 * Send ACK to communicator (if requested) and free @a cmc.
4457 *
4458 * @param cmc context for which we are done handling the message
4459 */
4460static void
4461finish_cmc_handling_with_continue (struct CommunicatorMessageContext *cmc,
4462 unsigned
4463 int free_cmc)
4464{
4465 if (0 != ntohl (cmc->im.fc_on))
4466 {
4467 /* send ACK when done to communicator for flow control! */
4468 struct GNUNET_MQ_Envelope *env;
4469 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4470
4471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4472 "Acknowledge message with flow control id %" PRIu64 "\n",
4473 cmc->im.fc_id);
4474 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4475 ack->reserved = htonl (0);
4476 ack->fc_id = cmc->im.fc_id;
4477 ack->sender = cmc->im.neighbour_sender;
4478 GNUNET_MQ_send (cmc->tc->mq, env);
4479 }
4480
4481 GNUNET_SERVICE_client_continue (cmc->tc->client);
4482
4483 if (GNUNET_YES == free_cmc)
4484 {
4485 GNUNET_free (cmc);
4486 }
4487}
4488
4489
4490static void
4491finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4492{
4493 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
4494}
4495
4496
4497/**
4498 * Client confirms that it is done handling message(s) to a particular
4499 * peer. We may now provide more messages to CORE for this peer.
4500 *
4501 * Notifies the respective queues that more messages can now be received.
4502 *
4503 * @param cls the client
4504 * @param rom the message that was sent
4505 */
4506static void
4507handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4508{
4509 struct TransportClient *tc = cls;
4510 struct VirtualLink *vl;
4511 uint32_t delta;
4512 struct CommunicatorMessageContext *cmc;
4513
4514 if (CT_CORE != tc->type)
4515 {
4516 GNUNET_break (0);
4517 GNUNET_SERVICE_client_drop (tc->client);
4518 return;
4519 }
4520 vl = lookup_virtual_link (&rom->peer);
4521 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4522 {
4523 GNUNET_STATISTICS_update (GST_stats,
4524 "# RECV_OK dropped: virtual link unknown",
4525 1,
4526 GNUNET_NO);
4527 GNUNET_SERVICE_client_continue (tc->client);
4528 return;
4529 }
4530 delta = ntohl (rom->increase_window_delta);
4531 vl->core_recv_window += delta;
4532 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4533 "CORE ack receiving message, increased CORE recv window to %d\n",
4534 vl->core_recv_window);
4535 GNUNET_SERVICE_client_continue (tc->client);
4536 if (vl->core_recv_window <= 0)
4537 return;
4538 /* resume communicators */
4539 while (NULL != (cmc = vl->cmc_tail))
4540 {
4541 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4542 if (GNUNET_NO == cmc->continue_send)
4543 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
4544 }
4545}
4546
4547
4548/**
4549 * Communicator started. Process the request.
4550 *
4551 * @param cls the client
4552 * @param cam the send message that was sent
4553 */
4554static void
4555handle_communicator_available (
4556 void *cls,
4557 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4558{
4559 struct TransportClient *tc = cls;
4560 uint16_t size;
4561
4562 size = ntohs (cam->header.size) - sizeof(*cam);
4563 if (0 == size)
4564 {
4565 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4566 "Receive-only communicator connected\n");
4567 return; /* receive-only communicator */
4568 }
4569 tc->details.communicator.address_prefix =
4570 GNUNET_strdup ((const char *) &cam[1]);
4571 tc->details.communicator.cc =
4572 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4573 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4574 "Communicator with prefix `%s' connected\n",
4575 tc->details.communicator.address_prefix);
4576 GNUNET_SERVICE_client_continue (tc->client);
4577}
4578
4579
4580/**
4581 * Communicator requests backchannel transmission. Check the request.
4582 *
4583 * @param cls the client
4584 * @param cb the send message that was sent
4585 * @return #GNUNET_OK if message is well-formed
4586 */
4587static int
4588check_communicator_backchannel (
4589 void *cls,
4590 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4591{
4592 const struct GNUNET_MessageHeader *inbox;
4593 const char *is;
4594 uint16_t msize;
4595 uint16_t isize;
4596
4597 (void) cls;
4598 msize = ntohs (cb->header.size) - sizeof(*cb);
4599 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4600 isize = ntohs (inbox->size);
4601 if (isize >= msize)
4602 {
4603 GNUNET_break (0);
4604 return GNUNET_SYSERR;
4605 }
4606 is = (const char *) inbox;
4607 is += isize;
4608 msize -= isize;
4609 GNUNET_assert (0 < msize);
4610 if ('\0' != is[msize - 1])
4611 {
4612 GNUNET_break (0);
4613 return GNUNET_SYSERR;
4614 }
4615 return GNUNET_OK;
4616}
4617
4618
4619/**
4620 * Sign ephemeral keys in our @a dv are current.
4621 *
4622 * @param[in,out] dv virtual link to update ephemeral for
4623 */
4624static void
4625sign_ephemeral (struct DistanceVector *dv)
4626{
4627 struct EphemeralConfirmationPS ec;
4628
4629 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4630 dv->ephemeral_validity =
4631 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4632 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4633 ec.target = dv->target;
4634 ec.ephemeral_key = dv->ephemeral_key;
4635 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4636 ec.purpose.size = htonl (sizeof(ec));
4637 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4638 &ec,
4639 &dv->sender_sig);
4640}
4641
4642
4643static void
4644free_queue_entry (struct QueueEntry *qe,
4645 struct TransportClient *tc);
4646
4647
4648static void
4649free_timedout_queue_entry (void *cls)
4650{
4651 struct TransportClient *tc = cls;
4652 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
4653
4654 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4655 "freeing timedout queue entries\n");
4656
4657 tc->details.communicator.free_queue_entry_task = NULL;
4658 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
4659 queue = queue->next_client)
4660 {
4661 struct QueueEntry *qep = queue->queue_head;
4662
4663 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4664 "checking QID %u for timedout queue entries\n",
4665 queue->qid);
4666 while (NULL != qep)
4667 {
4668 struct QueueEntry *pos = qep;
4669
4670 qep = qep->next;
4671 struct GNUNET_TIME_Relative diff = GNUNET_TIME_absolute_get_difference (
4672 pos->creation_timestamp, now);
4673
4674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4675 "diff to now %s \n",
4676 GNUNET_TIME_relative2s (diff, GNUNET_NO));
4677 if (GNUNET_TIME_relative_cmp (QUEUE_ENTRY_TIMEOUT, <, diff))
4678 {
4679 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4680 "Freeing timed out QueueEntry with MID %" PRIu64
4681 " and QID %u\n",
4682 pos->mid,
4683 queue->qid);
4684 free_queue_entry (pos, tc);
4685 }
4686 }
4687 }
4688}
4689
4690
4691/**
4692 * Send the message @a payload on @a queue.
4693 *
4694 * @param queue the queue to use for transmission
4695 * @param pm pending message to update once transmission is done, may be NULL!
4696 * @param payload the payload to send (encapsulated in a
4697 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4698 * @param payload_size number of bytes in @a payload
4699 */
4700static void
4701queue_send_msg (struct Queue *queue,
4702 struct PendingMessage *pm,
4703 const void *payload,
4704 size_t payload_size)
4705{
4706 struct Neighbour *n = queue->neighbour;
4707 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4708 struct GNUNET_MQ_Envelope *env;
4709 struct PendingAcknowledgement *pa;
4710
4711 GNUNET_log (
4712 GNUNET_ERROR_TYPE_DEBUG,
4713 "Queueing %u bytes of payload for transmission <%" PRIu64
4714 "> on queue %llu to %s\n",
4715 (unsigned int) payload_size,
4716 (NULL == pm) ? 0 : pm->logging_uuid,
4717 (unsigned long long) queue->qid,
4718 GNUNET_i2s (&queue->neighbour->pid));
4719 env = GNUNET_MQ_msg_extra (smt,
4720 payload_size,
4721 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4722 smt->qid = htonl (queue->qid);
4723 smt->mid = GNUNET_htonll (queue->mid_gen);
4724 smt->receiver = n->pid;
4725 memcpy (&smt[1], payload, payload_size);
4726 {
4727 /* Pass the env to the communicator of queue for transmission. */
4728 struct QueueEntry *qe;
4729
4730 qe = GNUNET_new (struct QueueEntry);
4731 qe->creation_timestamp = GNUNET_TIME_absolute_get ();
4732 qe->mid = queue->mid_gen;
4733 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4734 "Create QueueEntry with MID %" PRIu64
4735 " and QID %u and prefix %s\n",
4736 qe->mid,
4737 queue->qid,
4738 queue->tc->details.communicator.address_prefix);
4739 queue->mid_gen++;
4740 qe->queue = queue;
4741 if (NULL != pm)
4742 {
4743 qe->pm = pm;
4744 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
4745 // GNUNET_assert (NULL == pm->qe);
4746 if (NULL != pm->qe)
4747 {
4748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4749 "Retransmitting message <%" PRIu64
4750 "> remove pm from qe with MID: %llu \n",
4751 pm->logging_uuid,
4752 (unsigned long long) pm->qe->mid);
4753 pm->qe->pm = NULL;
4754 }
4755 pm->qe = qe;
4756 }
4757 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4758 if (0 == queue->q_capacity)
4759 {
4760 // Messages without FC or fragments can get here.
4761 if (NULL != pm)
4762 {
4763 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4764 "Message %" PRIu64
4765 " (pm type %u) was not send because queue has no capacity.\n",
4766 pm->logging_uuid,
4767 pm->pmt);
4768 pm->qe = NULL;
4769 }
4770 GNUNET_free (env);
4771 GNUNET_free (qe);
4772 return;
4773 }
4774 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4775 queue->queue_length++;
4776 queue->tc->details.communicator.total_queue_length++;
4777 if (GNUNET_NO == queue->unlimited_length)
4778 queue->q_capacity--;
4779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4780 "Queue %s with qid %u has capacity %" PRIu64 "\n",
4781 queue->address,
4782 queue->qid,
4783 queue->q_capacity);
4784 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4785 queue->tc->details.communicator.total_queue_length)
4786 queue->idle = GNUNET_NO;
4787 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4788 queue->idle = GNUNET_NO;
4789 if (0 == queue->q_capacity)
4790 queue->idle = GNUNET_NO;
4791
4792 if (GNUNET_NO == queue->idle)
4793 {
4794 struct TransportClient *tc = queue->tc;
4795
4796 if (NULL == tc->details.communicator.free_queue_entry_task)
4797 tc->details.communicator.free_queue_entry_task =
4798 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
4799 &
4800 free_timedout_queue_entry,
4801 tc);
4802 }
4803 if (NULL != pm && NULL != (pa = pm->pa_head))
4804 {
4805 while (pm != pa->pm)
4806 pa = pa->next_pa;
4807 pa->num_send++;
4808 }
4809 // GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
4810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4811 "Sending message MID %" PRIu64
4812 " of type %u (%u) and size %lu with MQ %p queue %s (QID %u) pending %"
4813 PRIu64 "\n",
4814 GNUNET_ntohll (smt->mid),
4815 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
4816 ntohs (smt->header.size),
4817 (unsigned long) payload_size,
4818 queue->tc->mq,
4819 queue->address,
4820 queue->qid,
4821 (NULL == pm) ? 0 : pm->logging_uuid);
4822 GNUNET_MQ_send (queue->tc->mq, env);
4823 }
4824}
4825
4826
4827/**
4828 * Pick a queue of @a n under constraints @a options and schedule
4829 * transmission of @a hdr.
4830 *
4831 * @param n neighbour to send to
4832 * @param hdr message to send as payload
4833 * @param options whether queues must be confirmed or not,
4834 * and whether we may pick multiple (2) queues
4835 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4836 */
4837static struct GNUNET_TIME_Relative
4838route_via_neighbour (const struct Neighbour *n,
4839 const struct GNUNET_MessageHeader *hdr,
4840 enum RouteMessageOptions options)
4841{
4842 struct GNUNET_TIME_Absolute now;
4843 unsigned int candidates;
4844 unsigned int sel1;
4845 unsigned int sel2;
4846 struct GNUNET_TIME_Relative rtt;
4847
4848 /* Pick one or two 'random' queues from n (under constraints of options) */
4849 now = GNUNET_TIME_absolute_get ();
4850 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4851 weight in the future; weight could be assigned by observed
4852 bandwidth (note: not sure if we should do this for this type
4853 of control traffic though). */
4854 candidates = 0;
4855 for (struct Queue *pos = n->queue_head; NULL != pos;
4856 pos = pos->next_neighbour)
4857 {
4858 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4859 (pos->validated_until.abs_value_us > now.abs_value_us))
4860 candidates++;
4861 }
4862 if (0 == candidates)
4863 {
4864 /* This can happen rarely if the last confirmed queue timed
4865 out just as we were beginning to process this message. */
4866 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4867 "Could not route message of type %u to %s: no valid queue\n",
4868 ntohs (hdr->type),
4869 GNUNET_i2s (&n->pid));
4870 GNUNET_STATISTICS_update (GST_stats,
4871 "# route selection failed (all no valid queue)",
4872 1,
4873 GNUNET_NO);
4874 return GNUNET_TIME_UNIT_FOREVER_REL;
4875 }
4876
4877 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4878 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4879 if (0 == (options & RMO_REDUNDANT))
4880 sel2 = candidates; /* picks none! */
4881 else
4882 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4883 candidates = 0;
4884 for (struct Queue *pos = n->queue_head; NULL != pos;
4885 pos = pos->next_neighbour)
4886 {
4887 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4888 (pos->validated_until.abs_value_us > now.abs_value_us))
4889 {
4890 if ((sel1 == candidates) || (sel2 == candidates))
4891 {
4892 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4893 "Routing message of type %u to %s using %s (#%u)\n",
4894 ntohs (hdr->type),
4895 GNUNET_i2s (&n->pid),
4896 pos->address,
4897 (sel1 == candidates) ? 1 : 2);
4898 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4899 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4900 }
4901 candidates++;
4902 }
4903 }
4904 return rtt;
4905}
4906
4907
4908/**
4909 * Structure of the key material used to encrypt backchannel messages.
4910 */
4911struct DVKeyState
4912{
4913 /**
4914 * State of our block cipher.
4915 */
4916 gcry_cipher_hd_t cipher;
4917
4918 /**
4919 * Actual key material.
4920 */
4921 struct
4922 {
4923 /**
4924 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4925 */
4926 struct GNUNET_CRYPTO_AuthKey hmac_key;
4927
4928 /**
4929 * Symmetric key to use for encryption.
4930 */
4931 char aes_key[256 / 8];
4932
4933 /**
4934 * Counter value to use during setup.
4935 */
4936 char aes_ctr[128 / 8];
4937 } material;
4938};
4939
4940
4941/**
4942 * Given the key material in @a km and the initialization vector
4943 * @a iv, setup the key material for the backchannel in @a key.
4944 *
4945 * @param km raw master secret
4946 * @param iv initialization vector
4947 * @param[out] key symmetric cipher and HMAC state to generate
4948 */
4949static void
4950dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4951 const struct GNUNET_ShortHashCode *iv,
4952 struct DVKeyState *key)
4953{
4954 /* must match what we defive from decapsulated key */
4955 GNUNET_assert (GNUNET_YES ==
4956 GNUNET_CRYPTO_kdf (&key->material,
4957 sizeof(key->material),
4958 "transport-backchannel-key",
4959 strlen ("transport-backchannel-key"),
4960 km,
4961 sizeof(*km),
4962 iv,
4963 sizeof(*iv),
4964 NULL));
4965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4966 "Deriving backchannel key based on KM %s and IV %s\n",
4967 GNUNET_h2s (km),
4968 GNUNET_sh2s (iv));
4969 GNUNET_assert (0 == gcry_cipher_open (&key->cipher,
4970 GCRY_CIPHER_AES256 /* low level: go for speed */,
4971 GCRY_CIPHER_MODE_CTR,
4972 0 /* flags */));
4973 GNUNET_assert (0 == gcry_cipher_setkey (key->cipher,
4974 &key->material.aes_key,
4975 sizeof(key->material.aes_key)));
4976 gcry_cipher_setctr (key->cipher,
4977 &key->material.aes_ctr,
4978 sizeof(key->material.aes_ctr));
4979}
4980
4981
4982/**
4983 * Do HMAC calculation for backchannel messages over @a data using key
4984 * material from @a key.
4985 *
4986 * @param key key material (from DH)
4987 * @param[out] hmac set to the HMAC
4988 * @param data data to perform HMAC calculation over
4989 * @param data_size number of bytes in @a data
4990 */
4991static void
4992dv_hmac (const struct DVKeyState *key,
4993 struct GNUNET_HashCode *hmac,
4994 const void *data,
4995 size_t data_size)
4996{
4997 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
4998}
4999
5000
5001/**
5002 * Perform backchannel encryption using symmetric secret in @a key
5003 * to encrypt data from @a in to @a dst.
5004 *
5005 * @param[in,out] key key material to use
5006 * @param dst where to write the result
5007 * @param in input data to encrypt (plaintext)
5008 * @param in_size number of bytes of input in @a in and available at @a dst
5009 */
5010static void
5011dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
5012{
5013 GNUNET_assert (0 ==
5014 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
5015}
5016
5017
5018/**
5019 * Perform backchannel encryption using symmetric secret in @a key
5020 * to encrypt data from @a in to @a dst.
5021 *
5022 * @param[in,out] key key material to use
5023 * @param ciph cipher text to decrypt
5024 * @param[out] out output data to generate (plaintext)
5025 * @param out_size number of bytes of input in @a ciph and available in @a out
5026 * @return GNUNET_OK on success
5027 */
5028static enum GNUNET_GenericReturnValue
5029dv_decrypt (struct DVKeyState *key,
5030 void *out,
5031 const void *ciph,
5032 size_t out_size)
5033{
5034 return (0 ==
5035 gcry_cipher_decrypt (key->cipher,
5036 out, out_size,
5037 ciph, out_size)) ? GNUNET_OK : GNUNET_SYSERR;
5038}
5039
5040
5041/**
5042 * Clean up key material in @a key.
5043 *
5044 * @param key key material to clean up (memory must not be free'd!)
5045 */
5046static void
5047dv_key_clean (struct DVKeyState *key)
5048{
5049 gcry_cipher_close (key->cipher);
5050 GNUNET_CRYPTO_zero_keys (&key->material, sizeof(key->material));
5051}
5052
5053
5054/**
5055 * Function to call to further operate on the now DV encapsulated
5056 * message @a hdr, forwarding it via @a next_hop under respect of
5057 * @a options.
5058 *
5059 * @param cls closure
5060 * @param next_hop next hop of the DV path
5061 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
5062 * @param options options of the original message
5063 */
5064typedef void (*DVMessageHandler) (void *cls,
5065 struct Neighbour *next_hop,
5066 const struct GNUNET_MessageHeader *hdr,
5067 enum RouteMessageOptions options);
5068
5069/**
5070 * Pick a path of @a dv under constraints @a options and schedule
5071 * transmission of @a hdr.
5072 *
5073 * @param target neighbour to ultimately send to
5074 * @param num_dvhs length of the @a dvhs array
5075 * @param dvhs array of hops to send the message to
5076 * @param hdr message to send as payload
5077 * @param use function to call with the encapsulated message
5078 * @param use_cls closure for @a use
5079 * @param options whether path must be confirmed or not, to be passed to @a use
5080 * @param without_fc shall this TransportDVBoxMessage be forwarded without flow control.
5081 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
5082 */
5083static struct GNUNET_TIME_Relative
5084encapsulate_for_dv (struct DistanceVector *dv,
5085 unsigned int num_dvhs,
5086 struct DistanceVectorHop **dvhs,
5087 const struct GNUNET_MessageHeader *hdr,
5088 DVMessageHandler use,
5089 void *use_cls,
5090 enum RouteMessageOptions options,
5091 enum GNUNET_GenericReturnValue without_fc)
5092{
5093 struct TransportDVBoxMessage box_hdr;
5094 struct TransportDVBoxPayloadP payload_hdr;
5095 uint16_t enc_body_size = ntohs (hdr->size);
5096 char enc[sizeof(struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
5097 struct DVKeyState *key;
5098 struct GNUNET_TIME_Relative rtt;
5099 struct GNUNET_HashCode km;
5100
5101 key = GNUNET_new (struct DVKeyState);
5102 /* Encrypt payload */
5103 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5104 box_hdr.total_hops = htons (0);
5105 box_hdr.without_fc = htons (without_fc);
5106 // update_ephemeral (dv);
5107 if (0 ==
5108 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
5109 {
5110 GNUNET_CRYPTO_eddsa_kem_encaps (&dv->target.public_key,
5111 &dv->ephemeral_key,
5112 &km);
5113 dv->km = GNUNET_new (struct GNUNET_HashCode);
5114 GNUNET_memcpy (dv->km, &km, sizeof(struct GNUNET_HashCode));
5115 sign_ephemeral (dv);
5116 }
5117 box_hdr.ephemeral_key = dv->ephemeral_key;
5118 payload_hdr.sender_sig = dv->sender_sig;
5119
5120 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5121 &box_hdr.iv,
5122 sizeof(box_hdr.iv));
5123 // We are creating this key, so this must work.
5124 // FIXME: Possibly also add return values here. We are processing
5125 // Input from other peers...
5126 dv_setup_key_state_from_km (dv->km, &box_hdr.iv, key);
5127 payload_hdr.sender = GST_my_identity;
5128 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5129 dv_encrypt (key, &payload_hdr, enc, sizeof(payload_hdr));
5130 dv_encrypt (key,
5131 hdr,
5132 &enc[sizeof(struct TransportDVBoxPayloadP)],
5133 enc_body_size);
5134 dv_hmac (key, &box_hdr.hmac, enc, sizeof(enc));
5135 dv_key_clean (key);
5136 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
5137 /* For each selected path, take the pre-computed header and body
5138 and add the path in the middle of the message; then send it. */
5139 for (unsigned int i = 0; i < num_dvhs; i++)
5140 {
5141 struct DistanceVectorHop *dvh = dvhs[i];
5142 unsigned int num_hops = dvh->distance + 1;
5143 char buf[sizeof(struct TransportDVBoxMessage)
5144 + sizeof(struct GNUNET_PeerIdentity) * num_hops
5145 + sizeof(struct TransportDVBoxPayloadP)
5146 + enc_body_size] GNUNET_ALIGN;
5147 struct GNUNET_PeerIdentity *dhops;
5148
5149 box_hdr.header.size = htons (sizeof(buf));
5150 box_hdr.orig_size = htons (sizeof(buf));
5151 box_hdr.num_hops = htons (num_hops);
5152 memcpy (buf, &box_hdr, sizeof(box_hdr));
5153 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
5154 memcpy (dhops,
5155 dvh->path,
5156 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
5157 dhops[dvh->distance] = dv->target;
5158 if (GNUNET_EXTRA_LOGGING > 0)
5159 {
5160 char *path;
5161
5162 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
5163 for (unsigned int j = 0; j < num_hops; j++)
5164 {
5165 char *tmp;
5166
5167 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
5168 GNUNET_free (path);
5169 path = tmp;
5170 }
5171 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5172 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
5173 ntohs (hdr->type),
5174 GNUNET_i2s (&dv->target),
5175 i + 1,
5176 num_dvhs,
5177 path);
5178 GNUNET_free (path);
5179 }
5180 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
5181 memcpy (&dhops[num_hops], enc, sizeof(enc));
5182 use (use_cls,
5183 dvh->next_hop,
5184 (const struct GNUNET_MessageHeader *) buf,
5185 options);
5186 GNUNET_free (key);
5187 }
5188 return rtt;
5189}
5190
5191
5192/**
5193 * Wrapper around #route_via_neighbour() that matches the
5194 * #DVMessageHandler structure.
5195 *
5196 * @param cls unused
5197 * @param next_hop where to send next
5198 * @param hdr header of the message to send
5199 * @param options message options for queue selection
5200 */
5201static void
5202send_dv_to_neighbour (void *cls,
5203 struct Neighbour *next_hop,
5204 const struct GNUNET_MessageHeader *hdr,
5205 enum RouteMessageOptions options)
5206{
5207 (void) cls;
5208 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
5209}
5210
5211
5212/**
5213 * We need to transmit @a hdr to @a target. If necessary, this may
5214 * involve DV routing. This function routes without applying flow
5215 * control or congestion control and should only be used for control
5216 * traffic.
5217 *
5218 * @param target peer to receive @a hdr
5219 * @param hdr header of the message to route and #GNUNET_free()
5220 * @param options which transmission channels are allowed
5221 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
5222 */
5223static struct GNUNET_TIME_Relative
5224route_control_message_without_fc (struct VirtualLink *vl,
5225// route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
5226 const struct GNUNET_MessageHeader *hdr,
5227 enum RouteMessageOptions options)
5228{
5229 // struct VirtualLink *vl;
5230 struct Neighbour *n;
5231 struct DistanceVector *dv;
5232 struct GNUNET_TIME_Relative rtt1;
5233 struct GNUNET_TIME_Relative rtt2;
5234 const struct GNUNET_PeerIdentity *target = &vl->target;
5235
5236 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5237 "Trying to route message of type %u to %s without fc\n",
5238 ntohs (hdr->type),
5239 GNUNET_i2s (target));
5240
5241 // TODO Do this elsewhere. vl should be given as parameter to method.
5242 // vl = lookup_virtual_link (target);
5243 GNUNET_assert (NULL != vl && GNUNET_YES == vl->confirmed);
5244 if (NULL == vl)
5245 return GNUNET_TIME_UNIT_FOREVER_REL;
5246 n = vl->n;
5247 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
5248 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
5249 {
5250 /* if confirmed is required, and we do not have anything
5251 confirmed, drop respective options */
5252 if (NULL == n)
5253 n = lookup_neighbour (target);
5254 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
5255 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
5256 }
5257 if ((NULL == n) && (NULL == dv))
5258 {
5259 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5260 "Cannot route message of type %u to %s: no route\n",
5261 ntohs (hdr->type),
5262 GNUNET_i2s (target));
5263 GNUNET_STATISTICS_update (GST_stats,
5264 "# Messages dropped in routing: no acceptable method",
5265 1,
5266 GNUNET_NO);
5267 return GNUNET_TIME_UNIT_FOREVER_REL;
5268 }
5269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5270 "Routing message of type %u to %s with options %X\n",
5271 ntohs (hdr->type),
5272 GNUNET_i2s (target),
5273 (unsigned int) options);
5274 /* If both dv and n are possible and we must choose:
5275 flip a coin for the choice between the two; for now 50/50 */
5276 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
5277 {
5278 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
5279 n = NULL;
5280 else
5281 dv = NULL;
5282 }
5283 if ((NULL != n) && (NULL != dv))
5284 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
5285 enough for redundancy, so clear the flag. */
5286 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
5287 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
5288 if (NULL != n)
5289 {
5290 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5291 "Try to route message of type %u to %s without fc via neighbour\n",
5292 ntohs (hdr->type),
5293 GNUNET_i2s (target));
5294 rtt1 = route_via_neighbour (n, hdr, options);
5295 }
5296 if (NULL != dv)
5297 {
5298 struct DistanceVectorHop *hops[2];
5299 unsigned int res;
5300
5301 res = pick_random_dv_hops (dv,
5302 options,
5303 hops,
5304 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
5305 if (0 == res)
5306 {
5307 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5308 "Failed to route message, could not determine DV path\n");
5309 return rtt1;
5310 }
5311 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5312 "encapsulate_for_dv 1\n");
5313 rtt2 = encapsulate_for_dv (dv,
5314 res,
5315 hops,
5316 hdr,
5317 &send_dv_to_neighbour,
5318 NULL,
5319 options & (~RMO_REDUNDANT),
5320 GNUNET_YES);
5321 }
5322 return GNUNET_TIME_relative_min (rtt1, rtt2);
5323}
5324
5325
5326static void
5327consider_sending_fc (void *cls);
5328
5329/**
5330 * Something changed on the virtual link with respect to flow
5331 * control. Consider retransmitting the FC window size.
5332 *
5333 * @param cls a `struct VirtualLink` to work with
5334 */
5335static void
5336task_consider_sending_fc (void *cls)
5337{
5338 struct VirtualLink *vl = cls;
5339 vl->fc_retransmit_task = NULL;
5340 consider_sending_fc (cls);
5341}
5342
5343
5344static char *
5345get_address_without_port (const char *address);
5346
5347
5348struct AddGlobalAddressesContext
5349{
5350 size_t off;
5351 char *tgnas;
5352};
5353
5354
5355static enum GNUNET_GenericReturnValue
5356add_global_addresses (void *cls,
5357 const struct GNUNET_PeerIdentity *pid,
5358 void *value)
5359{
5360 struct AddGlobalAddressesContext *ctx = cls;
5361 struct TransportGlobalNattedAddress *tgna = value;
5362 char *addr = (char *) &tgna[1];
5363 size_t address_len = strlen (addr);
5364 unsigned int off = 0;
5365
5366 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5367 "sending address %s length %u\n",
5368 addr,
5369 address_len);
5370 tgna = GNUNET_malloc (sizeof (struct TransportGlobalNattedAddress) + address_len);
5371 tgna->address_length = htonl (address_len);
5372 GNUNET_memcpy (&tgna[1], addr, address_len);
5373 GNUNET_memcpy (&(ctx->tgnas[ctx->off]), tgna, sizeof (struct TransportGlobalNattedAddress) + address_len);
5374 GNUNET_free (tgna);
5375 ctx->off += sizeof(struct TransportGlobalNattedAddress) + address_len;
5376}
5377
5378
5379/**
5380 * Something changed on the virtual link with respect to flow
5381 * control. Consider retransmitting the FC window size.
5382 *
5383 * @param cls a `struct VirtualLink` to work with
5384 */
5385static void
5386consider_sending_fc (void *cls)
5387{
5388 struct VirtualLink *vl = cls;
5389 struct GNUNET_TIME_Absolute monotime;
5390 struct TransportFlowControlMessage *fc;
5391 struct GNUNET_TIME_Relative duration;
5392 struct GNUNET_TIME_Relative rtt;
5393 struct Neighbour *n = vl->n;
5394
5395 if (0 < n->number_of_addresses)
5396 {
5397 size_t addresses_size =
5398 n->number_of_addresses * sizeof (struct TransportGlobalNattedAddress) + n->size_of_global_addresses;
5399 char *tgnas = GNUNET_malloc (addresses_size);
5400 struct AddGlobalAddressesContext ctx;
5401 ctx.off = 0;
5402 ctx.tgnas = tgnas;
5403
5404 fc = GNUNET_malloc (sizeof (struct TransportFlowControlMessage) + addresses_size);
5405 fc->header.size = htons (sizeof(struct TransportFlowControlMessage) + addresses_size);
5406 fc->size_of_addresses = htonl (n->size_of_global_addresses);
5407 fc->number_of_addresses = htonl (n->number_of_addresses);
5408 GNUNET_CONTAINER_multipeermap_iterate (n->natted_addresses,
5409 &add_global_addresses,
5410 &ctx);
5411 GNUNET_memcpy (&fc[1], tgnas, addresses_size);
5412 GNUNET_free (tgnas);
5413 }
5414 else
5415 {
5416 fc = GNUNET_malloc (sizeof (struct TransportFlowControlMessage));
5417 fc->header.size = htons (sizeof(struct TransportFlowControlMessage));
5418 }
5419
5420 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
5421 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
5422 it always! */
5423 /* For example, we should probably ONLY do this if a bit more than
5424 an RTT has passed, or if the window changed "significantly" since
5425 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
5426 need an estimate for the bandwidth-delay-product for the entire
5427 VL, as that determines "significantly". We have the delay, but
5428 the bandwidth statistics need to be added for the VL!*/(void) duration;
5429
5430 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5431 "Sending FC seq %u to %s with new window %llu\n",
5432 (unsigned int) vl->fc_seq_gen,
5433 GNUNET_i2s (&vl->target),
5434 (unsigned long long) vl->incoming_fc_window_size);
5435 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
5436 vl->last_fc_transmission = monotime;
5437 fc->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
5438 fc->seq = htonl (vl->fc_seq_gen++);
5439 fc->inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size
5440 + vl->incoming_fc_window_size_used
5441 + vl->incoming_fc_window_size_loss);
5442 fc->outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
5443 fc->outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
5444 fc->sender_time = GNUNET_TIME_absolute_hton (monotime);
5445 rtt = route_control_message_without_fc (vl, &fc->header, RMO_DV_ALLOWED);
5446 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
5447 {
5448 rtt = GNUNET_TIME_UNIT_SECONDS;
5449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5450 "FC retransmission to %s failed, will retry in %s\n",
5451 GNUNET_i2s (&vl->target),
5452 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
5453 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
5454 }
5455 else
5456 {
5457 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
5458 vl->last_fc_rtt = rtt;
5459 }
5460 if (NULL != vl->fc_retransmit_task)
5461 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
5462 if (MAX_FC_RETRANSMIT_COUNT == vl->fc_retransmit_count)
5463 {
5464 rtt = GNUNET_TIME_UNIT_MINUTES;
5465 vl->fc_retransmit_count = 0;
5466 }
5467 vl->fc_retransmit_task =
5468 GNUNET_SCHEDULER_add_delayed (rtt, &task_consider_sending_fc, vl);
5469 vl->fc_retransmit_count++;
5470 GNUNET_free (fc);
5471}
5472
5473
5474/**
5475 * There is a message at the head of the pending messages for @a vl
5476 * which may be ready for transmission. Check if a queue is ready to
5477 * take it.
5478 *
5479 * This function must (1) check for flow control to ensure that we can
5480 * right now send to @a vl, (2) check that the pending message in the
5481 * queue is actually eligible, (3) determine if any applicable queue
5482 * (direct neighbour or DVH path) is ready to accept messages, and
5483 * (4) prioritize based on the preferences associated with the
5484 * pending message.
5485 *
5486 * So yeah, easy.
5487 *
5488 * @param vl virtual link where we should check for transmission
5489 */
5490static void
5491check_vl_transmission (struct VirtualLink *vl)
5492{
5493 struct Neighbour *n = vl->n;
5494 struct DistanceVector *dv = vl->dv;
5495 struct GNUNET_TIME_Absolute now;
5496 struct VirtualLink *vl_next_hop;
5497 int elig;
5498
5499 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5500 "check_vl_transmission to target %s\n",
5501 GNUNET_i2s (&vl->target));
5502 /* Check that we have an eligible pending message!
5503 (cheaper than having #transmit_on_queue() find out!) */
5504 elig = GNUNET_NO;
5505 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
5506 pm = pm->next_vl)
5507 {
5508 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5509 "check_vl_transmission loop\n");
5510 if (NULL != pm->qe)
5511 continue; /* not eligible, is in a queue! */
5512 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
5513 vl->outbound_fc_window_size)
5514 {
5515 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5516 "Stalled message %" PRIu64
5517 " transmission on VL %s due to flow control: %llu < %llu\n",
5518 pm->logging_uuid,
5519 GNUNET_i2s (&vl->target),
5520 (unsigned long long) vl->outbound_fc_window_size,
5521 (unsigned long long) (pm->bytes_msg
5522 + vl->outbound_fc_window_size_used));
5523 consider_sending_fc (vl);
5524 return; /* We have a message, but flow control says "nope" */
5525 }
5526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5527 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
5528 GNUNET_i2s (&vl->target));
5529 /* Notify queues at direct neighbours that we are interested */
5530 now = GNUNET_TIME_absolute_get ();
5531 if (NULL != n)
5532 {
5533 for (struct Queue *queue = n->queue_head; NULL != queue;
5534 queue = queue->next_neighbour)
5535 {
5536 if ((GNUNET_YES == queue->idle) &&
5537 (queue->validated_until.abs_value_us > now.abs_value_us))
5538 {
5539 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5540 "Direct neighbour %s not stalled\n",
5541 GNUNET_i2s (&n->pid));
5542 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5543 queue,
5544 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
5545 elig = GNUNET_YES;
5546 }
5547 else
5548 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5549 "Neighbour Queue QID: %u (%u) busy or invalid\n",
5550 queue->qid,
5551 queue->idle);
5552 }
5553 }
5554 /* Notify queues via DV that we are interested */
5555 if (NULL != dv)
5556 {
5557 /* Do DV with lower scheduler priority, which effectively means that
5558 IF a neighbour exists and is available, we prefer it. */
5559 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5560 pos = pos->next_dv)
5561 {
5562 struct Neighbour *nh = pos->next_hop;
5563
5564
5565 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
5566 continue; /* skip this one: path not validated */
5567 else
5568 {
5569 vl_next_hop = lookup_virtual_link (&nh->pid);
5570 GNUNET_assert (NULL != vl_next_hop);
5571 if (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
5572 vl_next_hop->outbound_fc_window_size)
5573 {
5574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5575 "Stalled message %" PRIu64
5576 " transmission on next hop %s due to flow control: %llu < %llu\n",
5577 pm->logging_uuid,
5578 GNUNET_i2s (&vl_next_hop->target),
5579 (unsigned long
5580 long) vl_next_hop->outbound_fc_window_size,
5581 (unsigned long long) (pm->bytes_msg
5582 + vl_next_hop->
5583 outbound_fc_window_size_used));
5584 consider_sending_fc (vl_next_hop);
5585 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
5586 }
5587 for (struct Queue *queue = nh->queue_head; NULL != queue;
5588 queue = queue->next_neighbour)
5589 if ((GNUNET_YES == queue->idle) &&
5590 (queue->validated_until.abs_value_us > now.abs_value_us))
5591 {
5592 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5593 "Next hop neighbour %s not stalled\n",
5594 GNUNET_i2s (&nh->pid));
5595 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5596 queue,
5597 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
5598 elig = GNUNET_YES;
5599 }
5600 else
5601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5602 "DV Queue QID: %u (%u) busy or invalid\n",
5603 queue->qid,
5604 queue->idle);
5605 }
5606 }
5607 }
5608 if (GNUNET_YES == elig)
5609 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5610 "Eligible message %" PRIu64 " of size %u to %s: %llu/%llu\n",
5611 pm->logging_uuid,
5612 pm->bytes_msg,
5613 GNUNET_i2s (&vl->target),
5614 (unsigned long long) vl->outbound_fc_window_size,
5615 (unsigned long long) (pm->bytes_msg
5616 + vl->outbound_fc_window_size_used));
5617 break;
5618 }
5619}
5620
5621
5622/**
5623 * Client asked for transmission to a peer. Process the request.
5624 *
5625 * @param cls the client
5626 * @param obm the send message that was sent
5627 */
5628static void
5629handle_client_send (void *cls, const struct OutboundMessage *obm)
5630{
5631 struct TransportClient *tc = cls;
5632 struct PendingMessage *pm;
5633 const struct GNUNET_MessageHeader *obmm;
5634 uint32_t bytes_msg;
5635 struct VirtualLink *vl;
5636 enum GNUNET_MQ_PriorityPreferences pp;
5637
5638 GNUNET_assert (CT_CORE == tc->type);
5639 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5640 bytes_msg = ntohs (obmm->size);
5641 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
5642 vl = lookup_virtual_link (&obm->peer);
5643 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5644 {
5645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5646 "Don't have %s as a neighbour (anymore).\n",
5647 GNUNET_i2s (&obm->peer));
5648 /* Failure: don't have this peer as a neighbour (anymore).
5649 Might have gone down asynchronously, so this is NOT
5650 a protocol violation by CORE. Still count the event,
5651 as this should be rare. */
5652 GNUNET_SERVICE_client_continue (tc->client);
5653 GNUNET_STATISTICS_update (GST_stats,
5654 "# messages dropped (neighbour unknown)",
5655 1,
5656 GNUNET_NO);
5657 return;
5658 }
5659
5660 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
5661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5662 "1 created pm %p storing vl %p\n",
5663 pm,
5664 vl);
5665 pm->logging_uuid = logging_uuid_gen++;
5666 pm->prefs = pp;
5667 pm->client = tc;
5668 pm->vl = vl;
5669 pm->bytes_msg = bytes_msg;
5670 memcpy (&pm[1], obmm, bytes_msg);
5671 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5672 "Sending message of type %u with %u bytes as <%" PRIu64
5673 "> to %s\n",
5674 ntohs (obmm->type),
5675 bytes_msg,
5676 pm->logging_uuid,
5677 GNUNET_i2s (&obm->peer));
5678 GNUNET_CONTAINER_MDLL_insert (client,
5679 tc->details.core.pending_msg_head,
5680 tc->details.core.pending_msg_tail,
5681 pm);
5682 GNUNET_CONTAINER_MDLL_insert (vl,
5683 vl->pending_msg_head,
5684 vl->pending_msg_tail,
5685 pm);
5686 check_vl_transmission (vl);
5687 GNUNET_SERVICE_client_continue (tc->client);
5688}
5689
5690
5691/**
5692 * Communicator requests backchannel transmission. Process the request.
5693 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
5694 * (which for now has exactly the same format, only a different message type)
5695 * and passes it on for routing.
5696 *
5697 * @param cls the client
5698 * @param cb the send message that was sent
5699 */
5700static void
5701handle_communicator_backchannel (
5702 void *cls,
5703 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
5704{
5705 struct Neighbour *n;
5706 struct VirtualLink *vl;
5707 struct TransportClient *tc = cls;
5708 const struct GNUNET_MessageHeader *inbox =
5709 (const struct GNUNET_MessageHeader *) &cb[1];
5710 uint16_t isize = ntohs (inbox->size);
5711 const char *is = ((const char *) &cb[1]) + isize;
5712 size_t slen = strlen (is) + 1;
5713 char
5714 mbuf[slen + isize
5715 + sizeof(struct
5716 TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
5717 struct TransportBackchannelEncapsulationMessage *be =
5718 (struct TransportBackchannelEncapsulationMessage *) mbuf;
5719
5720 /* 0-termination of 'is' was checked already in
5721 #check_communicator_backchannel() */
5722 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5723 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
5724 GNUNET_i2s (&cb->pid),
5725 is,
5726 ntohs (inbox->type),
5727 ntohs (inbox->size));
5728 /* encapsulate and encrypt message */
5729 be->header.type =
5730 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
5731 be->header.size = htons (sizeof(mbuf));
5732 memcpy (&be[1], inbox, isize);
5733 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
5734 + isize],
5735 is,
5736 strlen (is) + 1);
5737 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
5738 vl = lookup_virtual_link (&cb->pid);
5739 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
5740 {
5741 route_control_message_without_fc (vl, &be->header, RMO_DV_ALLOWED);
5742 }
5743 else
5744 {
5745 /* Use route via neighbour */
5746 n = lookup_neighbour (&cb->pid);
5747 if (NULL != n)
5748 route_via_neighbour (
5749 n,
5750 &be->header,
5751 RMO_NONE);
5752 }
5753 GNUNET_SERVICE_client_continue (tc->client);
5754}
5755
5756
5757/**
5758 * Address of our peer added. Test message is well-formed.
5759 *
5760 * @param cls the client
5761 * @param aam the send message that was sent
5762 * @return #GNUNET_OK if message is well-formed
5763 */
5764static int
5765check_add_address (void *cls,
5766 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5767{
5768 struct TransportClient *tc = cls;
5769
5770 if (CT_COMMUNICATOR != tc->type)
5771 {
5772 GNUNET_break (0);
5773 return GNUNET_SYSERR;
5774 }
5775 GNUNET_MQ_check_zero_termination (aam);
5776 return GNUNET_OK;
5777}
5778
5779
5780/**
5781 * Ask peerstore to store our address.
5782 *
5783 * @param cls an `struct AddressListEntry *`
5784 */
5785static void
5786store_pi (void *cls);
5787
5788
5789/**
5790 * Function called when peerstore is done storing our address.
5791 *
5792 * @param cls a `struct AddressListEntry`
5793 * @param success #GNUNET_YES if peerstore was successful
5794 */
5795static void
5796peerstore_store_own_cb (void *cls, int success)
5797{
5798 struct AddressListEntry *ale = cls;
5799
5800 ale->sc = NULL;
5801 if (GNUNET_YES != success)
5802 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5803 "Failed to store our own address `%s' in peerstore!\n",
5804 ale->address);
5805 else
5806 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5807 "Successfully stored our own address `%s' in peerstore!\n",
5808 ale->address);
5809 /* refresh period is 1/4 of expiration time, that should be plenty
5810 without being excessive. */
5811 ale->st =
5812 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5813 4ULL),
5814 &store_pi,
5815 ale);
5816}
5817
5818
5819static void
5820shc_cont (void *cls, int success)
5821{
5822 struct AddressListEntry *ale = cls;
5823 struct GNUNET_TIME_Absolute expiration;
5824
5825 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5826 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5827 "transport",
5828 &GST_my_identity,
5829 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5830 ale->signed_address,
5831 ale->signed_address_len,
5832 expiration,
5833 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5834 &peerstore_store_own_cb,
5835 ale);
5836 if (NULL == ale->sc)
5837 {
5838 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5839 "Failed to store our address `%s' with peerstore\n",
5840 ale->address);
5841 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
5842 &store_pi,
5843 ale);
5844 }
5845}
5846
5847
5848/**
5849 * Ask peerstore to store our address.
5850 *
5851 * @param cls an `struct AddressListEntry *`
5852 */
5853static void
5854store_pi (void *cls)
5855{
5856 struct AddressListEntry *ale = cls;
5857 struct GNUNET_MQ_Envelope *env;
5858 const struct GNUNET_MessageHeader *msg;
5859 const char *dash;
5860 char *address_uri;
5861 char *prefix = GNUNET_HELLO_address_to_prefix (ale->address);
5862 unsigned int add_success;
5863
5864 dash = strchr (ale->address, '-');
5865 GNUNET_assert (NULL != dash);
5866 dash++;
5867 GNUNET_asprintf (&address_uri,
5868 "%s://%s",
5869 prefix,
5870 dash);
5871 GNUNET_free (prefix);
5872 ale->st = NULL;
5873 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5874 "Storing our address `%s' in peerstore until %s!\n",
5875 ale->address,
5876 GNUNET_STRINGS_absolute_time_to_string (hello_mono_time));
5877 add_success = GNUNET_HELLO_builder_add_address (GST_my_hello,
5878 address_uri);
5879 if (GNUNET_OK != add_success)
5880 {
5881 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5882 "Storing our address `%s' %s\n",
5883 address_uri,
5884 GNUNET_NO == add_success ? "not done" : "failed");
5885 GNUNET_free (address_uri);
5886 return;
5887 }
5888 else
5889 {
5890
5891 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5892 "Storing our address `%s'\n",
5893 address_uri);
5894 }
5895 // FIXME hello_mono_time used here?? What about expiration in ale?
5896 GNUNET_HELLO_sign_address (ale->address,
5897 ale->nt,
5898 hello_mono_time,
5899 GST_my_private_key,
5900 &ale->signed_address,
5901 &ale->signed_address_len);
5902 GNUNET_free (address_uri);
5903 env = GNUNET_HELLO_builder_to_env (GST_my_hello,
5904 GST_my_private_key,
5905 GNUNET_TIME_UNIT_ZERO);
5906 msg = GNUNET_MQ_env_get_msg (env);
5907 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5908 "store_pi 1\n");
5909 ale->shc = GNUNET_PEERSTORE_hello_add (peerstore,
5910 msg,
5911 shc_cont,
5912 ale);
5913 GNUNET_free (env);
5914}
5915
5916
5917static struct AddressListEntry *
5918create_address_entry (struct TransportClient *tc,
5919 struct GNUNET_TIME_Relative expiration,
5920 enum GNUNET_NetworkType nt,
5921 const char *address,
5922 uint32_t aid,
5923 size_t slen)
5924{
5925 struct AddressListEntry *ale;
5926
5927 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
5928 ale->tc = tc;
5929 ale->address = (const char *) &ale[1];
5930 ale->expiration = expiration;
5931 ale->aid = aid;
5932 ale->nt = nt;
5933 memcpy (&ale[1], address, slen);
5934 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5935
5936 return ale;
5937}
5938
5939
5940/**
5941 * Address of our peer added. Process the request.
5942 *
5943 * @param cls the client
5944 * @param aam the send message that was sent
5945 */
5946static void
5947handle_add_address (void *cls,
5948 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5949{
5950 struct TransportClient *tc = cls;
5951 struct AddressListEntry *ale;
5952 size_t slen;
5953 char *address;
5954
5955 /* 0-termination of &aam[1] was checked in #check_add_address */
5956 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5957 "Communicator added address `%s'!\n",
5958 (const char *) &aam[1]);
5959 slen = ntohs (aam->header.size) - sizeof(*aam);
5960 ale = create_address_entry (tc,
5961 GNUNET_TIME_relative_ntoh (aam->expiration),
5962 (enum GNUNET_NetworkType) ntohl (aam->nt),
5963 (const char *) &aam[1],
5964 aam->aid,
5965 slen);
5966 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5967 tc->details.communicator.addr_tail,
5968 ale);
5969 GNUNET_SERVICE_client_continue (tc->client);
5970}
5971
5972
5973/**
5974 * Address of our peer deleted. Process the request.
5975 *
5976 * @param cls the client
5977 * @param dam the send message that was sent
5978 */
5979static void
5980handle_del_address (void *cls,
5981 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5982{
5983 struct TransportClient *tc = cls;
5984 struct AddressListEntry *alen;
5985
5986 if (CT_COMMUNICATOR != tc->type)
5987 {
5988 GNUNET_break (0);
5989 GNUNET_SERVICE_client_drop (tc->client);
5990 return;
5991 }
5992 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5993 NULL != ale;
5994 ale = alen)
5995 {
5996 alen = ale->next;
5997 if (dam->aid != ale->aid)
5998 continue;
5999 GNUNET_assert (ale->tc == tc);
6000 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6001 "Communicator deleted address `%s'!\n",
6002 ale->address);
6003 free_address_list_entry (ale);
6004 GNUNET_SERVICE_client_continue (tc->client);
6005 return;
6006 }
6007 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
6008 "Communicator removed address we did not even have.\n");
6009 GNUNET_SERVICE_client_continue (tc->client);
6010 // GNUNET_SERVICE_client_drop (tc->client);
6011}
6012
6013
6014/**
6015 * Given an inbound message @a msg from a communicator @a cmc,
6016 * demultiplex it based on the type calling the right handler.
6017 *
6018 * @param cmc context for demultiplexing
6019 * @param msg message to demultiplex
6020 */
6021static void
6022demultiplex_with_cmc (struct CommunicatorMessageContext *cmc);
6023
6024
6025/**
6026 * Function called when we are done giving a message of a certain
6027 * size to CORE and should thus decrement the number of bytes of
6028 * RAM reserved for that peer's MQ.
6029 *
6030 * @param cls a `struct CoreSentContext`
6031 */
6032static void
6033core_env_sent_cb (void *cls)
6034{
6035 struct CoreSentContext *ctx = cls;
6036 struct VirtualLink *vl = ctx->vl;
6037
6038 if (NULL == vl)
6039 {
6040 /* lost the link in the meantime, ignore */
6041 GNUNET_free (ctx);
6042 return;
6043 }
6044 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
6045 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
6046 vl->incoming_fc_window_size_ram -= ctx->size;
6047 vl->incoming_fc_window_size_used += ctx->isize;
6048 consider_sending_fc (vl);
6049 GNUNET_free (ctx);
6050}
6051
6052
6053static void
6054finish_handling_raw_message (struct VirtualLink *vl,
6055 const struct GNUNET_MessageHeader *mh,
6056 struct CommunicatorMessageContext *cmc,
6057 unsigned int free_cmc)
6058{
6059 uint16_t size = ntohs (mh->size);
6060 int have_core;
6061
6062 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
6063 {
6064 GNUNET_STATISTICS_update (GST_stats,
6065 "# CORE messages dropped (FC arithmetic overflow)",
6066 1,
6067 GNUNET_NO);
6068 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6069 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
6070 (unsigned int) ntohs (mh->type),
6071 (unsigned int) ntohs (mh->size));
6072 if (GNUNET_YES == free_cmc)
6073 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
6074 return;
6075 }
6076 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
6077 {
6078 GNUNET_STATISTICS_update (GST_stats,
6079 "# CORE messages dropped (FC window overflow)",
6080 1,
6081 GNUNET_NO);
6082 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6083 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
6084 (unsigned int) ntohs (mh->type),
6085 (unsigned int) ntohs (mh->size));
6086 if (GNUNET_YES == free_cmc)
6087 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
6088 return;
6089 }
6090
6091 /* Forward to all CORE clients */
6092 have_core = GNUNET_NO;
6093 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
6094 {
6095 struct GNUNET_MQ_Envelope *env;
6096 struct InboundMessage *im;
6097 struct CoreSentContext *ctx;
6098
6099 if (CT_CORE != tc->type)
6100 continue;
6101 vl->incoming_fc_window_size_ram += size;
6102 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
6103 ctx = GNUNET_new (struct CoreSentContext);
6104 ctx->vl = vl;
6105 ctx->size = size;
6106 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
6107 have_core = GNUNET_YES;
6108 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
6109 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
6110 im->peer = cmc->im.sender;
6111 memcpy (&im[1], mh, size);
6112 GNUNET_MQ_send (tc->mq, env);
6113 vl->core_recv_window--;
6114 }
6115 if (GNUNET_NO == have_core)
6116 {
6117 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
6118 "Dropped message to CORE: no CORE client connected!\n");
6119 /* Nevertheless, count window as used, as it is from the
6120 perspective of the other peer! */
6121 vl->incoming_fc_window_size_used += size;
6122 /* TODO-M1 */
6123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6124 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
6125 (unsigned int) ntohs (mh->type),
6126 (unsigned int) ntohs (mh->size));
6127 if (GNUNET_YES == free_cmc)
6128 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
6129 return;
6130 }
6131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6132 "Delivered message from %s of type %u to CORE recv window %d\n",
6133 GNUNET_i2s (&cmc->im.sender),
6134 ntohs (mh->type),
6135 vl->core_recv_window);
6136 if (vl->core_recv_window > 0)
6137 {
6138 if (GNUNET_YES == free_cmc)
6139 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
6140 return;
6141 }
6142 /* Wait with calling #finish_cmc_handling(cmc) until the message
6143 was processed by CORE MQs (for CORE flow control)! */
6144 if (GNUNET_YES == free_cmc)
6145 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
6146}
6147
6148
6149/**
6150 * Communicator gave us an unencapsulated message to pass as-is to
6151 * CORE. Process the request.
6152 *
6153 * @param cls a `struct CommunicatorMessageContext` (must call
6154 * #finish_cmc_handling() when done)
6155 * @param mh the message that was received
6156 */
6157static void
6158handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
6159{
6160 struct CommunicatorMessageContext *cmc = cls;
6161 // struct CommunicatorMessageContext *cmc_copy =
6162 // GNUNET_new (struct CommunicatorMessageContext);
6163 struct GNUNET_MessageHeader *mh_copy;
6164 struct RingBufferEntry *rbe;
6165 struct VirtualLink *vl;
6166 uint16_t size = ntohs (mh->size);
6167
6168 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6169 "Handling raw message of type %u with %u bytes\n",
6170 (unsigned int) ntohs (mh->type),
6171 (unsigned int) ntohs (mh->size));
6172
6173 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
6174 (size < sizeof(struct GNUNET_MessageHeader)))
6175 {
6176 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
6177
6178 GNUNET_break (0);
6179 finish_cmc_handling (cmc);
6180 GNUNET_SERVICE_client_drop (client);
6181 return;
6182 }
6183 vl = lookup_virtual_link (&cmc->im.sender);
6184 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6185 {
6186 /* FIXME: sender is giving us messages for CORE but we don't have
6187 the link up yet! I *suspect* this can happen right now (i.e.
6188 sender has verified us, but we didn't verify sender), but if
6189 we pass this on, CORE would be confused (link down, messages
6190 arrive). We should investigate more if this happens often,
6191 or in a persistent manner, and possibly do "something" about
6192 it. Thus logging as error for now. */
6193
6194 mh_copy = GNUNET_malloc (size);
6195 rbe = GNUNET_new (struct RingBufferEntry);
6196 rbe->cmc = cmc;
6197 /*cmc_copy->tc = cmc->tc;
6198 cmc_copy->im = cmc->im;*/
6199 GNUNET_memcpy (mh_copy, mh, size);
6200
6201 rbe->mh = mh_copy;
6202
6203 if (GNUNET_YES == is_ring_buffer_full)
6204 {
6205 struct RingBufferEntry *rbe_old = ring_buffer[ring_buffer_head];
6206 GNUNET_free (rbe_old->cmc);
6207 GNUNET_free (rbe_old->mh);
6208 GNUNET_free (rbe_old);
6209 }
6210 ring_buffer[ring_buffer_head] = rbe;// cmc_copy;
6211 // cmc_copy->mh = (const struct GNUNET_MessageHeader *) mh_copy;
6212 cmc->mh = (const struct GNUNET_MessageHeader *) mh_copy;
6213 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6214 "Storing message for %s and type %u (%u) in ring buffer head %u is full %u\n",
6215 GNUNET_i2s (&cmc->im.sender),
6216 (unsigned int) ntohs (mh->type),
6217 (unsigned int) ntohs (mh_copy->type),
6218 ring_buffer_head,
6219 is_ring_buffer_full);
6220 if (RING_BUFFER_SIZE - 1 == ring_buffer_head)
6221 {
6222 ring_buffer_head = 0;
6223 is_ring_buffer_full = GNUNET_YES;
6224 }
6225 else
6226 ring_buffer_head++;
6227
6228 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6229 "%u items stored in ring buffer\n",
6230 GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
6231 ring_buffer_head);
6232
6233 /*GNUNET_break_op (0);
6234 GNUNET_STATISTICS_update (GST_stats,
6235 "# CORE messages dropped (virtual link still down)",
6236 1,
6237 GNUNET_NO);
6238
6239 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6240 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
6241 (unsigned int) ntohs (mh->type),
6242 (unsigned int) ntohs (mh->size));
6243 finish_cmc_handling (cmc);*/
6244 finish_cmc_handling_with_continue (cmc, GNUNET_NO);
6245 cmc->continue_send = GNUNET_YES;
6246 // GNUNET_free (cmc);
6247 return;
6248 }
6249 finish_handling_raw_message (vl, mh, cmc, GNUNET_YES);
6250}
6251
6252
6253/**
6254 * Communicator gave us a fragment box. Check the message.
6255 *
6256 * @param cls a `struct CommunicatorMessageContext`
6257 * @param fb the send message that was sent
6258 * @return #GNUNET_YES if message is well-formed
6259 */
6260static int
6261check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
6262{
6263 uint16_t size = ntohs (fb->header.size);
6264 uint16_t bsize = size - sizeof(*fb);
6265
6266 (void) cls;
6267 if (0 == bsize)
6268 {
6269 GNUNET_break_op (0);
6270 return GNUNET_SYSERR;
6271 }
6272 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
6273 {
6274 GNUNET_break_op (0);
6275 return GNUNET_SYSERR;
6276 }
6277 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
6278 {
6279 GNUNET_break_op (0);
6280 return GNUNET_SYSERR;
6281 }
6282 return GNUNET_YES;
6283}
6284
6285
6286/**
6287 * Clean up an idle cumulative acknowledgement data structure.
6288 *
6289 * @param cls a `struct AcknowledgementCummulator *`
6290 */
6291static void
6292destroy_ack_cummulator (void *cls)
6293{
6294 struct AcknowledgementCummulator *ac = cls;
6295
6296 ac->task = NULL;
6297 GNUNET_assert (0 == ac->num_acks);
6298 GNUNET_assert (
6299 GNUNET_YES ==
6300 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
6301 GNUNET_free (ac);
6302}
6303
6304
6305/**
6306 * Do the transmission of a cumulative acknowledgement now.
6307 *
6308 * @param cls a `struct AcknowledgementCummulator *`
6309 */
6310static void
6311transmit_cummulative_ack_cb (void *cls)
6312{
6313 struct Neighbour *n;
6314 struct VirtualLink *vl;
6315 struct AcknowledgementCummulator *ac = cls;
6316 char buf[sizeof(struct TransportReliabilityAckMessage)
6317 + ac->num_acks
6318 * sizeof(struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
6319 struct TransportReliabilityAckMessage *ack =
6320 (struct TransportReliabilityAckMessage *) buf;
6321 struct TransportCummulativeAckPayloadP *ap;
6322
6323 ac->task = NULL;
6324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6325 "Sending ACK with %u components to %s\n",
6326 ac->num_acks,
6327 GNUNET_i2s (&ac->target));
6328 GNUNET_assert (0 < ac->num_acks);
6329 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
6330 ack->header.size =
6331 htons (sizeof(*ack)
6332 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
6333 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
6334 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
6335 for (unsigned int i = 0; i < ac->num_acks; i++)
6336 {
6337 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
6338 ap[i].ack_delay = GNUNET_TIME_relative_hton (
6339 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
6340 }
6341 /*route_control_message_without_fc (
6342 &ac->target,
6343 &ack->header,
6344 RMO_DV_ALLOWED);*/
6345 vl = lookup_virtual_link (&ac->target);
6346 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6347 {
6348 route_control_message_without_fc (
6349 vl,
6350 &ack->header,
6351 RMO_DV_ALLOWED);
6352 }
6353 else
6354 {
6355 /* Use route via neighbour */
6356 n = lookup_neighbour (&ac->target);
6357 if (NULL != n)
6358 route_via_neighbour (
6359 n,
6360 &ack->header,
6361 RMO_NONE);
6362 }
6363 ac->num_acks = 0;
6364 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
6365 &destroy_ack_cummulator,
6366 ac);
6367}
6368
6369
6370/**
6371 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
6372 * transmission by at most @a ack_delay.
6373 *
6374 * @param pid target peer
6375 * @param ack_uuid UUID to ack
6376 * @param max_delay how long can the ACK wait
6377 */
6378static void
6379cummulative_ack (const struct GNUNET_PeerIdentity *pid,
6380 const struct AcknowledgementUUIDP *ack_uuid,
6381 struct GNUNET_TIME_Absolute max_delay)
6382{
6383 struct AcknowledgementCummulator *ac;
6384
6385 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6386 "Scheduling ACK %s for transmission to %s\n",
6387 GNUNET_uuid2s (&ack_uuid->value),
6388 GNUNET_i2s (pid));
6389 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
6390 if (NULL == ac)
6391 {
6392 ac = GNUNET_new (struct AcknowledgementCummulator);
6393 ac->target = *pid;
6394 ac->min_transmission_time = max_delay;
6395 GNUNET_assert (GNUNET_YES ==
6396 GNUNET_CONTAINER_multipeermap_put (
6397 ack_cummulators,
6398 &ac->target,
6399 ac,
6400 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6401 }
6402 else
6403 {
6404 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
6405 {
6406 /* must run immediately, ack buffer full! */
6407 transmit_cummulative_ack_cb (ac);
6408 }
6409 GNUNET_SCHEDULER_cancel (ac->task);
6410 ac->min_transmission_time =
6411 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
6412 }
6413 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
6414 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
6415 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
6416 ac->num_acks++;
6417 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
6418 &transmit_cummulative_ack_cb,
6419 ac);
6420}
6421
6422
6423/**
6424 * Closure for #find_by_message_uuid.
6425 */
6426struct FindByMessageUuidContext
6427{
6428 /**
6429 * UUID to look for.
6430 */
6431 struct MessageUUIDP message_uuid;
6432
6433 /**
6434 * Set to the reassembly context if found.
6435 */
6436 struct ReassemblyContext *rc;
6437};
6438
6439
6440/**
6441 * Iterator called to find a reassembly context by the message UUID in the
6442 * multihashmap32.
6443 *
6444 * @param cls a `struct FindByMessageUuidContext`
6445 * @param key a key (unused)
6446 * @param value a `struct ReassemblyContext`
6447 * @return #GNUNET_YES if not found, #GNUNET_NO if found
6448 */
6449static int
6450find_by_message_uuid (void *cls, uint32_t key, void *value)
6451{
6452 struct FindByMessageUuidContext *fc = cls;
6453 struct ReassemblyContext *rc = value;
6454
6455 (void) key;
6456 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
6457 {
6458 fc->rc = rc;
6459 return GNUNET_NO;
6460 }
6461 return GNUNET_YES;
6462}
6463
6464
6465/**
6466 * Communicator gave us a fragment. Process the request.
6467 *
6468 * @param cls a `struct CommunicatorMessageContext` (must call
6469 * #finish_cmc_handling() when done)
6470 * @param fb the message that was received
6471 */
6472static void
6473handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
6474{
6475 struct CommunicatorMessageContext *cmc = cls;
6476 struct VirtualLink *vl;
6477 struct ReassemblyContext *rc;
6478 const struct GNUNET_MessageHeader *msg;
6479 uint16_t msize;
6480 uint16_t fsize;
6481 uint16_t frag_off;
6482 char *target;
6483 struct GNUNET_TIME_Relative cdelay;
6484 struct FindByMessageUuidContext fc;
6485
6486 vl = lookup_virtual_link (&cmc->im.sender);
6487 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6488 {
6489 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
6490
6491 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6492 "No virtual link for %s to handle fragment\n",
6493 GNUNET_i2s (&cmc->im.sender));
6494 GNUNET_break (0);
6495 finish_cmc_handling (cmc);
6496 GNUNET_SERVICE_client_drop (client);
6497 return;
6498 }
6499 if (NULL == vl->reassembly_map)
6500 {
6501 vl->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
6502 vl->reassembly_heap =
6503 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
6504 vl->reassembly_timeout_task =
6505 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
6506 &reassembly_cleanup_task,
6507 vl);
6508 }
6509 msize = ntohs (fb->msg_size);
6510 fc.message_uuid = fb->msg_uuid;
6511 fc.rc = NULL;
6512 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (vl->reassembly_map,
6513 fb->msg_uuid.uuid,
6514 &find_by_message_uuid,
6515 &fc);
6516 fsize = ntohs (fb->header.size) - sizeof(*fb);
6517 if (NULL == (rc = fc.rc))
6518 {
6519 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
6520 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
6521 rc->msg_uuid = fb->msg_uuid;
6522 rc->virtual_link = vl;
6523 rc->msg_size = msize;
6524 rc->reassembly_timeout =
6525 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
6526 rc->last_frag = GNUNET_TIME_absolute_get ();
6527 rc->hn = GNUNET_CONTAINER_heap_insert (vl->reassembly_heap,
6528 rc,
6529 rc->reassembly_timeout.abs_value_us);
6530 GNUNET_assert (GNUNET_OK ==
6531 GNUNET_CONTAINER_multihashmap32_put (
6532 vl->reassembly_map,
6533 rc->msg_uuid.uuid,
6534 rc,
6535 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
6536 target = (char *) &rc[1];
6537 rc->bitfield = (uint8_t *) (target + rc->msg_size);
6538 if (fsize != rc->msg_size)
6539 rc->msg_missing = rc->msg_size;
6540 else
6541 rc->msg_missing = 0;
6542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6543 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %"
6544 PRIu64 "\n",
6545 fsize,
6546 ntohs (fb->frag_off),
6547 msize,
6548 rc->msg_missing,
6549 GNUNET_i2s (&cmc->im.sender),
6550 fb->msg_uuid.uuid);
6551 }
6552 else
6553 {
6554 target = (char *) &rc[1];
6555 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6556 "Received fragment at offset %u/%u from %s for message %u\n",
6557 ntohs (fb->frag_off),
6558 msize,
6559 GNUNET_i2s (&cmc->im.sender),
6560 (unsigned int) fb->msg_uuid.uuid);
6561 }
6562 if (msize != rc->msg_size)
6563 {
6564 GNUNET_break (0);
6565 finish_cmc_handling (cmc);
6566 return;
6567 }
6568
6569 /* reassemble */
6570 if (0 == fsize)
6571 {
6572 GNUNET_break (0);
6573 finish_cmc_handling (cmc);
6574 return;
6575 }
6576 frag_off = ntohs (fb->frag_off);
6577 if (frag_off + fsize > msize)
6578 {
6579 /* Fragment (plus fragment size) exceeds message size! */
6580 GNUNET_break_op (0);
6581 finish_cmc_handling (cmc);
6582 return;
6583 }
6584 memcpy (&target[frag_off], &fb[1], fsize);
6585 /* update bitfield and msg_missing */
6586 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
6587 {
6588 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
6589 {
6590 rc->bitfield[i / 8] |= (1 << (i % 8));
6591 rc->msg_missing--;
6592 }
6593 }
6594
6595 /* Compute cumulative ACK */
6596 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
6597 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
6598 if (0 == rc->msg_missing)
6599 cdelay = GNUNET_TIME_UNIT_ZERO;
6600 cummulative_ack (&cmc->im.sender,
6601 &fb->ack_uuid,
6602 GNUNET_TIME_relative_to_absolute (cdelay));
6603 rc->last_frag = GNUNET_TIME_absolute_get ();
6604 /* is reassembly complete? */
6605 if (0 != rc->msg_missing)
6606 {
6607 finish_cmc_handling (cmc);
6608 return;
6609 }
6610 /* reassembly is complete, verify result */
6611 msg = (const struct GNUNET_MessageHeader *) &rc[1];
6612 if (ntohs (msg->size) != rc->msg_size)
6613 {
6614 GNUNET_break (0);
6615 free_reassembly_context (rc);
6616 finish_cmc_handling (cmc);
6617 return;
6618 }
6619 /* successful reassembly */
6620 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6621 "Fragment reassembly complete for message %u\n",
6622 (unsigned int) fb->msg_uuid.uuid);
6623 /* FIXME: check that the resulting msg is NOT a
6624 DV Box or Reliability Box, as that is NOT allowed! */
6625 cmc->mh = msg;
6626 demultiplex_with_cmc (cmc);
6627 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
6628 en-route and we forget that we finished this reassembly immediately!
6629 -> keep around until timeout?
6630 -> shorten timeout based on ACK? */
6631 free_reassembly_context (rc);
6632}
6633
6634
6635/**
6636 * Communicator gave us a reliability box. Check the message.
6637 *
6638 * @param cls a `struct CommunicatorMessageContext`
6639 * @param rb the send message that was sent
6640 * @return #GNUNET_YES if message is well-formed
6641 */
6642static int
6643check_reliability_box (void *cls,
6644 const struct TransportReliabilityBoxMessage *rb)
6645{
6646 (void) cls;
6647 const struct GNUNET_MessageHeader *inbox = (const struct
6648 GNUNET_MessageHeader *) &rb[1];
6649
6650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6651 "check_send_msg with size %u: inner msg type %u and size %u (%lu %lu)\n",
6652 ntohs (rb->header.size),
6653 ntohs (inbox->type),
6654 ntohs (inbox->size),
6655 sizeof (struct TransportReliabilityBoxMessage),
6656 sizeof (struct GNUNET_MessageHeader));
6657 GNUNET_MQ_check_boxed_message (rb);
6658 return GNUNET_YES;
6659}
6660
6661
6662/**
6663 * Communicator gave us a reliability box. Process the request.
6664 *
6665 * @param cls a `struct CommunicatorMessageContext` (must call
6666 * #finish_cmc_handling() when done)
6667 * @param rb the message that was received
6668 */
6669static void
6670handle_reliability_box (void *cls,
6671 const struct TransportReliabilityBoxMessage *rb)
6672{
6673 struct CommunicatorMessageContext *cmc = cls;
6674 const struct GNUNET_MessageHeader *inbox =
6675 (const struct GNUNET_MessageHeader *) &rb[1];
6676 struct GNUNET_TIME_Relative rtt;
6677
6678 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6679 "Received reliability box from %s with UUID %s of type %u\n",
6680 GNUNET_i2s (&cmc->im.sender),
6681 GNUNET_uuid2s (&rb->ack_uuid.value),
6682 (unsigned int) ntohs (inbox->type));
6683 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
6684 do not really have an RTT for the
6685 * incoming* queue (should we have
6686 the sender add it to the rb message?) */
6687 cummulative_ack (
6688 &cmc->im.sender,
6689 &rb->ack_uuid,
6690 (0 == ntohl (rb->ack_countdown))
6691 ? GNUNET_TIME_UNIT_ZERO_ABS
6692 : GNUNET_TIME_relative_to_absolute (
6693 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
6694 /* continue with inner message */
6695 /* FIXME: check that inbox is NOT a DV Box, fragment or another
6696 reliability box (not allowed!) */
6697 cmc->mh = inbox;
6698 demultiplex_with_cmc (cmc);
6699}
6700
6701
6702/**
6703 * Check if we have advanced to another age since the last time. If
6704 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
6705 * the current age)
6706 *
6707 * @param[in,out] pd data to update
6708 * @param age current age
6709 */
6710static void
6711update_pd_age (struct PerformanceData *pd, unsigned int age)
6712{
6713 unsigned int sage;
6714
6715 if (age == pd->last_age)
6716 return; /* nothing to do */
6717 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
6718 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
6719 {
6720 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
6721
6722 the->bytes_sent = 0;
6723 the->bytes_received = 0;
6724 }
6725 pd->last_age = age;
6726}
6727
6728
6729/**
6730 * Update @a pd based on the latest @a rtt and the number of bytes
6731 * that were confirmed to be successfully transmitted.
6732 *
6733 * @param[in,out] pd data to update
6734 * @param rtt latest round-trip time
6735 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
6736 */
6737static void
6738update_performance_data (struct PerformanceData *pd,
6739 struct GNUNET_TIME_Relative rtt,
6740 uint16_t bytes_transmitted_ok)
6741{
6742 uint64_t nval = rtt.rel_value_us;
6743 uint64_t oval = pd->aged_rtt.rel_value_us;
6744 unsigned int age = get_age ();
6745 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
6746
6747 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
6748 pd->aged_rtt = rtt;
6749 else
6750 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
6751 update_pd_age (pd, age);
6752 the->bytes_received += bytes_transmitted_ok;
6753}
6754
6755
6756/**
6757 * We have successfully transmitted data via @a q, update metrics.
6758 *
6759 * @param q queue to update
6760 * @param rtt round trip time observed
6761 * @param bytes_transmitted_ok number of bytes successfully transmitted
6762 */
6763static void
6764update_queue_performance (struct Queue *q,
6765 struct GNUNET_TIME_Relative rtt,
6766 uint16_t bytes_transmitted_ok)
6767{
6768 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
6769}
6770
6771
6772/**
6773 * We have successfully transmitted data via @a dvh, update metrics.
6774 *
6775 * @param dvh distance vector path data to update
6776 * @param rtt round trip time observed
6777 * @param bytes_transmitted_ok number of bytes successfully transmitted
6778 */
6779static void
6780update_dvh_performance (struct DistanceVectorHop *dvh,
6781 struct GNUNET_TIME_Relative rtt,
6782 uint16_t bytes_transmitted_ok)
6783{
6784 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
6785}
6786
6787
6788/**
6789 * We have completed transmission of @a pm, remove it from
6790 * the transmission queues (and if it is a fragment, continue
6791 * up the tree as necessary).
6792 *
6793 * @param pm pending message that was transmitted
6794 */
6795static void
6796completed_pending_message (struct PendingMessage *pm)
6797{
6798 struct PendingMessage *pos;
6799
6800 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6801 "Complete transmission of message %" PRIu64 " %u\n",
6802 pm->logging_uuid,
6803 pm->pmt);
6804 switch (pm->pmt)
6805 {
6806 case PMT_CORE:
6807 case PMT_RELIABILITY_BOX:
6808 /* Full message sent, we are done */
6809 client_send_response (pm);
6810 return;
6811
6812 case PMT_FRAGMENT_BOX:
6813 /* Fragment sent over reliable channel */
6814 pos = pm->frag_parent;
6815 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6816 free_pending_message (pm);
6817 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6818 "pos frag_off %lu pos bytes_msg %lu pmt %u parent %u\n",
6819 (unsigned long) pos->frag_off,
6820 (unsigned long) pos->bytes_msg,
6821 pos->pmt,
6822 NULL == pos->frag_parent ? 1 : 0);
6823 /* check if subtree is done */
6824 while ((NULL == pos->head_frag) && (pos->frag_off == (pos->bytes_msg
6825 - sizeof(struct
6826 TransportFragmentBoxMessage)))
6827 &&
6828 (NULL != pos->frag_parent))
6829 {
6830 pm = pos;
6831 pos = pm->frag_parent;
6832 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
6833 {
6834 client_send_response (pm);
6835 return;
6836 }
6837 else if (PMT_DV_BOX == pm->pmt)
6838 {
6839 client_send_response (pos);
6840 return;
6841 }
6842 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6843 free_pending_message (pm);
6844 }
6845
6846 /* Was this the last applicable fragment? */
6847 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent || PMT_DV_BOX ==
6848 pos->pmt) &&
6849 (pos->frag_off == pos->bytes_msg))
6850 client_send_response (pos);
6851 return;
6852
6853 case PMT_DV_BOX:
6854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6855 "Completed transmission of message %" PRIu64 " (DV Box)\n",
6856 pm->logging_uuid);
6857 if (NULL != pm->frag_parent)
6858 {
6859 pos = pm->frag_parent;
6860 free_pending_message (pm);
6861 pos->bpm = NULL;
6862 client_send_response (pos);
6863 }
6864 else
6865 client_send_response (pm);
6866 return;
6867 }
6868}
6869
6870
6871/**
6872 * The @a pa was acknowledged, process the acknowledgement.
6873 *
6874 * @param pa the pending acknowledgement that was satisfied
6875 * @param ack_delay artificial delay from cumulative acks created by the
6876 * other peer
6877 */
6878static void
6879handle_acknowledged (struct PendingAcknowledgement *pa,
6880 struct GNUNET_TIME_Relative ack_delay)
6881{
6882 struct GNUNET_TIME_Relative delay;
6883
6884 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
6885 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
6886 if (NULL != pa->queue && 1 == pa->num_send)
6887 update_queue_performance (pa->queue, delay, pa->message_size);
6888 if (NULL != pa->dvh && 1 == pa->num_send)
6889 update_dvh_performance (pa->dvh, delay, pa->message_size);
6890 if (NULL != pa->pm)
6891 completed_pending_message (pa->pm);
6892 free_pending_acknowledgement (pa);
6893}
6894
6895
6896/**
6897 * Communicator gave us a reliability ack. Check it is well-formed.
6898 *
6899 * @param cls a `struct CommunicatorMessageContext` (unused)
6900 * @param ra the message that was received
6901 * @return #GNUNET_Ok if @a ra is well-formed
6902 */
6903static int
6904check_reliability_ack (void *cls,
6905 const struct TransportReliabilityAckMessage *ra)
6906{
6907 unsigned int n_acks;
6908
6909 (void) cls;
6910 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6911 / sizeof(struct TransportCummulativeAckPayloadP);
6912 if (0 == n_acks)
6913 {
6914 GNUNET_break_op (0);
6915 return GNUNET_SYSERR;
6916 }
6917 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
6918 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
6919 {
6920 GNUNET_break_op (0);
6921 return GNUNET_SYSERR;
6922 }
6923 return GNUNET_OK;
6924}
6925
6926
6927/**
6928 * Communicator gave us a reliability ack. Process the request.
6929 *
6930 * @param cls a `struct CommunicatorMessageContext` (must call
6931 * #finish_cmc_handling() when done)
6932 * @param ra the message that was received
6933 */
6934static void
6935handle_reliability_ack (void *cls,
6936 const struct TransportReliabilityAckMessage *ra)
6937{
6938 struct CommunicatorMessageContext *cmc = cls;
6939 const struct TransportCummulativeAckPayloadP *ack;
6940 unsigned int n_acks;
6941 uint32_t ack_counter;
6942
6943 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6944 / sizeof(struct TransportCummulativeAckPayloadP);
6945 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
6946 for (unsigned int i = 0; i < n_acks; i++)
6947 {
6948 struct PendingAcknowledgement *pa =
6949 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
6950 if (NULL == pa)
6951 {
6952 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6953 "Received ACK from %s with UUID %s which is unknown to us!\n",
6954 GNUNET_i2s (&cmc->im.sender),
6955 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6956 GNUNET_STATISTICS_update (
6957 GST_stats,
6958 "# FRAGMENT_ACKS dropped, no matching pending message",
6959 1,
6960 GNUNET_NO);
6961 continue;
6962 }
6963 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6964 "Received ACK from %s with UUID %s\n",
6965 GNUNET_i2s (&cmc->im.sender),
6966 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6967 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
6968 }
6969
6970 ack_counter = htonl (ra->ack_counter);
6971 (void) ack_counter; /* silence compiler warning for now */
6972 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
6973 // (DV and/or Neighbour?)
6974 finish_cmc_handling (cmc);
6975}
6976
6977
6978/**
6979 * Communicator gave us a backchannel encapsulation. Check the message.
6980 *
6981 * @param cls a `struct CommunicatorMessageContext`
6982 * @param be the send message that was sent
6983 * @return #GNUNET_YES if message is well-formed
6984 */
6985static int
6986check_backchannel_encapsulation (
6987 void *cls,
6988 const struct TransportBackchannelEncapsulationMessage *be)
6989{
6990 uint16_t size = ntohs (be->header.size) - sizeof(*be);
6991 const struct GNUNET_MessageHeader *inbox =
6992 (const struct GNUNET_MessageHeader *) &be[1];
6993 const char *is;
6994 uint16_t isize;
6995
6996 (void) cls;
6997 if (ntohs (inbox->size) >= size)
6998 {
6999 GNUNET_break_op (0);
7000 return GNUNET_SYSERR;
7001 }
7002 isize = ntohs (inbox->size);
7003 is = ((const char *) inbox) + isize;
7004 size -= isize;
7005 if ('\0' != is[size - 1])
7006 {
7007 GNUNET_break_op (0);
7008 return GNUNET_SYSERR;
7009 }
7010 return GNUNET_YES;
7011}
7012
7013
7014/**
7015 * Communicator gave us a backchannel encapsulation. Process the request.
7016 * (We are the destination of the backchannel here.)
7017 *
7018 * @param cls a `struct CommunicatorMessageContext` (must call
7019 * #finish_cmc_handling() when done)
7020 * @param be the message that was received
7021 */
7022static void
7023handle_backchannel_encapsulation (
7024 void *cls,
7025 const struct TransportBackchannelEncapsulationMessage *be)
7026{
7027 struct CommunicatorMessageContext *cmc = cls;
7028 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
7029 struct GNUNET_MQ_Envelope *env;
7030 struct TransportClient *tc;
7031 const struct GNUNET_MessageHeader *inbox =
7032 (const struct GNUNET_MessageHeader *) &be[1];
7033 uint16_t isize = ntohs (inbox->size);
7034 const char *target_communicator = ((const char *) inbox) + isize;
7035 char *sender;
7036 char *self;
7037
7038 GNUNET_asprintf (&sender,
7039 "%s",
7040 GNUNET_i2s (&cmc->im.sender));
7041 GNUNET_asprintf (&self,
7042 "%s",
7043 GNUNET_i2s (&GST_my_identity));
7044
7045 /* Find client providing this communicator */
7046 for (tc = clients_head; NULL != tc; tc = tc->next)
7047 if ((CT_COMMUNICATOR == tc->type) &&
7048 (0 ==
7049 strcmp (tc->details.communicator.address_prefix, target_communicator)))
7050 break;
7051 if (NULL == tc)
7052 {
7053 char *stastr;
7054
7055 GNUNET_asprintf (
7056 &stastr,
7057 "# Backchannel message dropped: target communicator `%s' unknown",
7058 target_communicator);
7059 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
7060 GNUNET_free (stastr);
7061 finish_cmc_handling (cmc);
7062 return;
7063 }
7064 /* Finally, deliver backchannel message to communicator */
7065 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7066 "Delivering backchannel message from %s to %s of type %u to %s\n",
7067 sender,
7068 self,
7069 ntohs (inbox->type),
7070 target_communicator);
7071 env = GNUNET_MQ_msg_extra (
7072 cbi,
7073 isize,
7074 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
7075 cbi->pid = cmc->im.sender;
7076 memcpy (&cbi[1], inbox, isize);
7077 GNUNET_MQ_send (tc->mq, env);
7078 finish_cmc_handling (cmc);
7079}
7080
7081
7082/**
7083 * Task called when we should check if any of the DV paths
7084 * we have learned to a target are due for garbage collection.
7085 *
7086 * Collects stale paths, and possibly frees the entire DV
7087 * entry if no paths are left. Otherwise re-schedules itself.
7088 *
7089 * @param cls a `struct DistanceVector`
7090 */
7091static void
7092path_cleanup_cb (void *cls)
7093{
7094 struct DistanceVector *dv = cls;
7095 struct DistanceVectorHop *pos;
7096
7097 dv->timeout_task = NULL;
7098 while (NULL != (pos = dv->dv_head))
7099 {
7100 GNUNET_assert (dv == pos->dv);
7101 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
7102 break;
7103 free_distance_vector_hop (pos);
7104 }
7105 if (NULL == pos)
7106 {
7107 free_dv_route (dv);
7108 return;
7109 }
7110 dv->timeout_task =
7111 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
7112}
7113
7114
7115static void
7116send_msg_from_cache (struct VirtualLink *vl)
7117{
7118
7119 const struct GNUNET_PeerIdentity target = vl->target;
7120
7121
7122 if ((GNUNET_YES == is_ring_buffer_full) || (0 < ring_buffer_head))
7123 {
7124 struct RingBufferEntry *ring_buffer_copy[RING_BUFFER_SIZE];
7125 unsigned int tail = GNUNET_YES == is_ring_buffer_full ? ring_buffer_head :
7126 0;
7127 unsigned int head = GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
7128 ring_buffer_head;
7129 struct GNUNET_TRANSPORT_IncomingMessage im;
7130 struct CommunicatorMessageContext *cmc;
7131 struct RingBufferEntry *rbe;
7132 struct GNUNET_MessageHeader *mh;
7133
7134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7135 "Sending from ring buffer, which has %u items\n",
7136 head);
7137
7138 ring_buffer_head = 0;
7139 for (unsigned int i = 0; i < head; i++)
7140 {
7141 rbe = ring_buffer[(i + tail) % RING_BUFFER_SIZE];
7142 cmc = rbe->cmc;
7143 mh = rbe->mh;
7144
7145 im = cmc->im;
7146 // mh = cmc->mh;
7147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7148 "Sending message of type %u to ring buffer target %s using vl target %s index %u\n",
7149 mh->type,
7150 GNUNET_i2s (&im.sender),
7151 GNUNET_i2s2 (&target),
7152 (i + tail) % RING_BUFFER_SIZE);
7153 if (0 == GNUNET_memcmp (&target, &im.sender))
7154 {
7155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7156 "Finish handling message of type %u and size %u\n",
7157 (unsigned int) ntohs (mh->type),
7158 (unsigned int) ntohs (mh->size));
7159 finish_handling_raw_message (vl, mh, cmc, GNUNET_NO);
7160 GNUNET_free (mh);
7161 GNUNET_free (rbe->cmc);
7162 GNUNET_free (rbe);
7163 }
7164 else
7165 {
7166 ring_buffer_copy[ring_buffer_head] = rbe;
7167 ring_buffer_head++;
7168 }
7169 }
7170
7171 if ((GNUNET_YES == is_ring_buffer_full) && (RING_BUFFER_SIZE - 1 >
7172 ring_buffer_head))
7173 {
7174 is_ring_buffer_full = GNUNET_NO;
7175 }
7176
7177 for (unsigned int i = 0; i < ring_buffer_head; i++)
7178 {
7179 ring_buffer[i] = ring_buffer_copy[i];
7180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7181 "ring_buffer_copy[i]->mh->type for i %u %u\n",
7182 i,
7183 ring_buffer_copy[i]->mh->type);
7184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7185 "ring_buffer[i]->mh->type for i %u %u\n",
7186 i,
7187 ring_buffer[i]->mh->type);
7188 }
7189
7190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7191 "%u items still in ring buffer\n",
7192 ring_buffer_head);
7193 }
7194
7195 if ((GNUNET_YES == is_ring_buffer_dv_full) || (0 < ring_buffer_dv_head))
7196 {
7197 struct PendingMessage *ring_buffer_dv_copy[RING_BUFFER_SIZE];
7198 struct PendingMessage *pm;
7199 unsigned int tail = GNUNET_YES == is_ring_buffer_dv_full ?
7200 ring_buffer_dv_head :
7201 0;
7202 unsigned int head = GNUNET_YES == is_ring_buffer_dv_full ?
7203 RING_BUFFER_SIZE :
7204 ring_buffer_dv_head;
7205
7206 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7207 "Sending from ring buffer dv, which has %u items\n",
7208 head);
7209
7210 ring_buffer_dv_head = 0;
7211 for (unsigned int i = 0; i < head; i++)
7212 {
7213 pm = ring_buffer_dv[(i + tail) % RING_BUFFER_SIZE];
7214
7215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7216 "Sending to ring buffer target %s using vl target %s\n",
7217 GNUNET_i2s (&pm->target),
7218 GNUNET_i2s2 (&target));
7219 if (0 == GNUNET_memcmp (&target, &pm->target))
7220 {
7221 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7222 "Adding PendingMessage to vl, checking transmission.\n");
7223 pm->vl = vl;
7224 GNUNET_CONTAINER_MDLL_insert (vl,
7225 vl->pending_msg_head,
7226 vl->pending_msg_tail,
7227 pm);
7228
7229 check_vl_transmission (vl);
7230 }
7231 else
7232 {
7233 ring_buffer_dv_copy[ring_buffer_dv_head] = pm;
7234 ring_buffer_dv_head++;
7235 }
7236 }
7237
7238 if (is_ring_buffer_dv_full && (RING_BUFFER_SIZE - 1 > ring_buffer_dv_head))
7239 {
7240 is_ring_buffer_dv_full = GNUNET_NO;
7241 }
7242
7243 for (unsigned int i = 0; i < ring_buffer_dv_head; i++)
7244 ring_buffer_dv[i] = ring_buffer_dv_copy[i];
7245
7246 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7247 "%u items still in ring buffer dv.\n",
7248 ring_buffer_dv_head);
7249
7250 }
7251}
7252
7253
7254/**
7255 * The @a hop is a validated path to the respective target
7256 * peer and we should tell core about it -- and schedule
7257 * a job to revoke the state.
7258 *
7259 * @param hop a path to some peer that is the reason for activation
7260 */
7261static void
7262activate_core_visible_dv_path (struct DistanceVectorHop *hop)
7263{
7264 struct DistanceVector *dv = hop->dv;
7265 struct VirtualLink *vl;
7266
7267 vl = lookup_virtual_link (&dv->target);
7268 if (NULL == vl)
7269 {
7270
7271 vl = GNUNET_new (struct VirtualLink);
7272 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7273 "Creating new virtual link %p to %s using DV!\n",
7274 vl,
7275 GNUNET_i2s (&dv->target));
7276 vl->confirmed = GNUNET_YES;
7277 vl->message_uuid_ctr =
7278 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
7279 vl->target = dv->target;
7280 vl->core_recv_window = RECV_WINDOW_SIZE;
7281 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
7282 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
7283 GNUNET_break (GNUNET_YES ==
7284 GNUNET_CONTAINER_multipeermap_put (
7285 links,
7286 &vl->target,
7287 vl,
7288 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7289 vl->dv = dv;
7290 dv->vl = vl;
7291 vl->visibility_task =
7292 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
7293 consider_sending_fc (vl);
7294 /* We lacked a confirmed connection to the target
7295 before, so tell CORE about it (finally!) */
7296 cores_send_connect_info (&dv->target);
7297 send_msg_from_cache (vl);
7298 }
7299 else
7300 {
7301 /* Link was already up, remember dv is also now available and we are done */
7302 vl->dv = dv;
7303 dv->vl = vl;
7304 if (GNUNET_NO == vl->confirmed)
7305 {
7306 vl->confirmed = GNUNET_YES;
7307 vl->visibility_task =
7308 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
7309 consider_sending_fc (vl);
7310 /* We lacked a confirmed connection to the target
7311 before, so tell CORE about it (finally!) */
7312 cores_send_connect_info (&dv->target);
7313 send_msg_from_cache (vl);
7314 }
7315 else
7316 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7317 "Virtual link to %s could now also use DV!\n",
7318 GNUNET_i2s (&dv->target));
7319 }
7320}
7321
7322
7323/**
7324 * We have learned a @a path through the network to some other peer, add it to
7325 * our DV data structure (returning #GNUNET_YES on success).
7326 *
7327 * We do not add paths if we have a sufficient number of shorter
7328 * paths to this target already (returning #GNUNET_NO).
7329 *
7330 * We also do not add problematic paths, like those where we lack the first
7331 * hop in our neighbour list (i.e. due to a topology change) or where some
7332 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
7333 *
7334 * @param path the path we learned, path[0] should be us,
7335 * and then path contains a valid path from us to
7336 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
7337 * @param path_len number of entries on the @a path, at least three!
7338 * @param network_latency how long does the message take from us to
7339 * `path[path_len-1]`? set to "forever" if unknown
7340 * @param path_valid_until how long is this path considered validated? Maybe
7341 * be zero.
7342 * @return #GNUNET_YES on success,
7343 * #GNUNET_NO if we have better path(s) to the target
7344 * #GNUNET_SYSERR if the path is useless and/or invalid
7345 * (i.e. path[1] not a direct neighbour
7346 * or path[i+1] is a direct neighbour for i>0)
7347 */
7348static int
7349learn_dv_path (const struct GNUNET_PeerIdentity *path,
7350 unsigned int path_len,
7351 struct GNUNET_TIME_Relative network_latency,
7352 struct GNUNET_TIME_Absolute path_valid_until)
7353{
7354 struct DistanceVectorHop *hop;
7355 struct DistanceVector *dv;
7356 struct Neighbour *next_hop;
7357 unsigned int shorter_distance;
7358
7359 if (path_len < 3)
7360 {
7361 /* what a boring path! not allowed! */
7362 GNUNET_break (0);
7363 return GNUNET_SYSERR;
7364 }
7365 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
7366 next_hop = lookup_neighbour (&path[1]);
7367 if (NULL == next_hop)
7368 {
7369 /* next hop must be a neighbour, otherwise this whole thing is useless! */
7370 GNUNET_break (0);
7371 return GNUNET_SYSERR;
7372 }
7373 for (unsigned int i = 2; i < path_len; i++)
7374 if (NULL != lookup_neighbour (&path[i]))
7375 {
7376 /* Useless path: we have a direct connection to some hop
7377 in the middle of the path, so this one is not even
7378 terribly useful for redundancy */
7379 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7380 "Path of %u hops useless: directly link to hop %u (%s)\n",
7381 path_len,
7382 i,
7383 GNUNET_i2s (&path[i]));
7384 GNUNET_STATISTICS_update (GST_stats,
7385 "# Useless DV path ignored: hop is neighbour",
7386 1,
7387 GNUNET_NO);
7388 return GNUNET_SYSERR;
7389 }
7390 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
7391 if (NULL == dv)
7392 {
7393 dv = GNUNET_new (struct DistanceVector);
7394 dv->target = path[path_len - 1];
7395 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
7396 &path_cleanup_cb,
7397 dv);
7398 GNUNET_assert (GNUNET_OK ==
7399 GNUNET_CONTAINER_multipeermap_put (
7400 dv_routes,
7401 &dv->target,
7402 dv,
7403 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7404 }
7405 /* Check if we have this path already! */
7406 shorter_distance = 0;
7407 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
7408 pos = pos->next_dv)
7409 {
7410 if (pos->distance < path_len - 3)
7411 shorter_distance++;
7412 /* Note that the distances in 'pos' excludes us (path[0]),
7413 the next_hop (path[1]) and the target so we need to subtract three
7414 and check next_hop explicitly */
7415 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
7416 {
7417 int match = GNUNET_YES;
7418
7419 for (unsigned int i = 0; i < pos->distance; i++)
7420 {
7421 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
7422 {
7423 match = GNUNET_NO;
7424 break;
7425 }
7426 }
7427 if (GNUNET_YES == match)
7428 {
7429 struct GNUNET_TIME_Relative last_timeout;
7430
7431 /* Re-discovered known path, update timeout */
7432 GNUNET_STATISTICS_update (GST_stats,
7433 "# Known DV path refreshed",
7434 1,
7435 GNUNET_NO);
7436 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
7437 pos->timeout =
7438 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
7439 pos->path_valid_until =
7440 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
7441 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
7442 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
7443 if (0 <
7444 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
7445 activate_core_visible_dv_path (pos);
7446 if (last_timeout.rel_value_us <
7447 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
7448 DV_PATH_DISCOVERY_FREQUENCY)
7449 .rel_value_us)
7450 {
7451 /* Some peer send DV learn messages too often, we are learning
7452 the same path faster than it would be useful; do not forward! */
7453 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7454 "Rediscovered path too quickly, not forwarding further\n");
7455 return GNUNET_NO;
7456 }
7457 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7458 "Refreshed known path to %s valid until %s, forwarding further\n",
7459 GNUNET_i2s (&dv->target),
7460 GNUNET_STRINGS_absolute_time_to_string (
7461 pos->path_valid_until));
7462 return GNUNET_YES;
7463 }
7464 }
7465 }
7466 /* Count how many shorter paths we have (incl. direct
7467 neighbours) before simply giving up on this one! */
7468 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
7469 {
7470 /* We have a shorter path already! */
7471 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7472 "Have many shorter DV paths %s, not forwarding further\n",
7473 GNUNET_i2s (&dv->target));
7474 return GNUNET_NO;
7475 }
7476 /* create new DV path entry */
7477 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7478 "Discovered new DV path to %s valid until %s\n",
7479 GNUNET_i2s (&dv->target),
7480 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
7481 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
7482 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
7483 hop->next_hop = next_hop;
7484 hop->dv = dv;
7485 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
7486 memcpy (&hop[1],
7487 &path[2],
7488 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
7489 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
7490 hop->path_valid_until = path_valid_until;
7491 hop->distance = path_len - 3;
7492 hop->pd.aged_rtt = network_latency;
7493 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
7494 GNUNET_CONTAINER_MDLL_insert (neighbour,
7495 next_hop->dv_head,
7496 next_hop->dv_tail,
7497 hop);
7498 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
7499 activate_core_visible_dv_path (hop);
7500 return GNUNET_YES;
7501}
7502
7503
7504/**
7505 * Communicator gave us a DV learn message. Check the message.
7506 *
7507 * @param cls a `struct CommunicatorMessageContext`
7508 * @param dvl the send message that was sent
7509 * @return #GNUNET_YES if message is well-formed
7510 */
7511static int
7512check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
7513{
7514 uint16_t size = ntohs (dvl->header.size);
7515 uint16_t num_hops = ntohs (dvl->num_hops);
7516 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
7517
7518 (void) cls;
7519 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
7520 {
7521 GNUNET_break_op (0);
7522 return GNUNET_SYSERR;
7523 }
7524 if (num_hops > MAX_DV_HOPS_ALLOWED)
7525 {
7526 GNUNET_break_op (0);
7527 return GNUNET_SYSERR;
7528 }
7529 for (unsigned int i = 0; i < num_hops; i++)
7530 {
7531 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
7532 {
7533 GNUNET_break_op (0);
7534 return GNUNET_SYSERR;
7535 }
7536 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
7537 {
7538 GNUNET_break_op (0);
7539 return GNUNET_SYSERR;
7540 }
7541 }
7542 return GNUNET_YES;
7543}
7544
7545
7546/**
7547 * Build and forward a DV learn message to @a next_hop.
7548 *
7549 * @param next_hop peer to send the message to
7550 * @param msg message received
7551 * @param bi_history bitmask specifying hops on path that were bidirectional
7552 * @param nhops length of the @a hops array
7553 * @param hops path the message traversed so far
7554 * @param in_time when did we receive the message, used to calculate network
7555 * delay
7556 */
7557static void
7558forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
7559 const struct TransportDVLearnMessage *msg,
7560 uint16_t bi_history,
7561 uint16_t nhops,
7562 const struct DVPathEntryP *hops,
7563 struct GNUNET_TIME_Absolute in_time)
7564{
7565 struct Neighbour *n;
7566 struct VirtualLink *vl;
7567 struct DVPathEntryP *dhops;
7568 char buf[sizeof(struct TransportDVLearnMessage)
7569 + (nhops + 1) * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
7570 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
7571 struct GNUNET_TIME_Relative nnd;
7572
7573 /* compute message for forwarding */
7574 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7575 "Forwarding DV learn message originating from %s to %s\n",
7576 GNUNET_i2s (&msg->initiator),
7577 GNUNET_i2s2 (next_hop));
7578 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
7579 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
7580 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
7581 + (nhops + 1) * sizeof(struct DVPathEntryP));
7582 fwd->num_hops = htons (nhops + 1);
7583 fwd->bidirectional = htons (bi_history);
7584 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
7585 GNUNET_TIME_relative_ntoh (
7586 msg->non_network_delay));
7587 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
7588 fwd->init_sig = msg->init_sig;
7589 fwd->initiator = msg->initiator;
7590 fwd->challenge = msg->challenge;
7591 fwd->monotonic_time = msg->monotonic_time;
7592 dhops = (struct DVPathEntryP *) &fwd[1];
7593 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
7594 dhops[nhops].hop = GST_my_identity;
7595 {
7596 struct DvHopPS dhp = {
7597 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
7598 .purpose.size = htonl (sizeof(dhp)),
7599 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
7600 .succ = *next_hop,
7601 .challenge = msg->challenge
7602 };
7603 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7604 &dhp,
7605 &dhops[nhops].hop_sig);
7606 }
7607 /*route_control_message_without_fc (next_hop,
7608 &fwd->header,
7609 RMO_UNCONFIRMED_ALLOWED);*/
7610 vl = lookup_virtual_link (next_hop);
7611 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
7612 {
7613 route_control_message_without_fc (vl,
7614 &fwd->header,
7615 RMO_UNCONFIRMED_ALLOWED);
7616 }
7617 else
7618 {
7619 /* Use route via neighbour */
7620 n = lookup_neighbour (next_hop);
7621 if (NULL != n)
7622 route_via_neighbour (
7623 n,
7624 &fwd->header,
7625 RMO_UNCONFIRMED_ALLOWED);
7626 }
7627}
7628
7629
7630/**
7631 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
7632 *
7633 * @param sender_monotonic_time monotonic time of the initiator
7634 * @param init the signer
7635 * @param challenge the challenge that was signed
7636 * @param init_sig signature presumably by @a init
7637 * @return #GNUNET_OK if the signature is valid
7638 */
7639static int
7640validate_dv_initiator_signature (
7641 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
7642 const struct GNUNET_PeerIdentity *init,
7643 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge,
7644 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
7645{
7646 struct DvInitPS ip = { .purpose.purpose = htonl (
7647 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
7648 .purpose.size = htonl (sizeof(ip)),
7649 .monotonic_time = sender_monotonic_time,
7650 .challenge = *challenge };
7651
7652 if (
7653 GNUNET_OK !=
7654 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
7655 &ip,
7656 init_sig,
7657 &init->public_key))
7658 {
7659 GNUNET_break_op (0);
7660 return GNUNET_SYSERR;
7661 }
7662 return GNUNET_OK;
7663}
7664
7665
7666/**
7667 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
7668 */
7669struct NeighbourSelectionContext
7670{
7671 /**
7672 * Original message we received.
7673 */
7674 const struct TransportDVLearnMessage *dvl;
7675
7676 /**
7677 * The hops taken.
7678 */
7679 const struct DVPathEntryP *hops;
7680
7681 /**
7682 * Time we received the message.
7683 */
7684 struct GNUNET_TIME_Absolute in_time;
7685
7686 /**
7687 * Offsets of the selected peers.
7688 */
7689 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
7690
7691 /**
7692 * Number of peers eligible for selection.
7693 */
7694 unsigned int num_eligible;
7695
7696 /**
7697 * Number of peers that were selected for forwarding.
7698 */
7699 unsigned int num_selections;
7700
7701 /**
7702 * Number of hops in @e hops
7703 */
7704 uint16_t nhops;
7705
7706 /**
7707 * Bitmap of bidirectional connections encountered.
7708 */
7709 uint16_t bi_history;
7710};
7711
7712
7713/**
7714 * Function called for each neighbour during #handle_dv_learn.
7715 *
7716 * @param cls a `struct NeighbourSelectionContext *`
7717 * @param pid identity of the peer
7718 * @param value a `struct Neighbour`
7719 * @return #GNUNET_YES (always)
7720 */
7721static int
7722dv_neighbour_selection (void *cls,
7723 const struct GNUNET_PeerIdentity *pid,
7724 void *value)
7725{
7726 struct NeighbourSelectionContext *nsc = cls;
7727
7728 (void) value;
7729 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7730 return GNUNET_YES; /* skip initiator */
7731 for (unsigned int i = 0; i < nsc->nhops; i++)
7732 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7733 return GNUNET_YES;
7734 /* skip peers on path */
7735 nsc->num_eligible++;
7736 return GNUNET_YES;
7737}
7738
7739
7740/**
7741 * Function called for each neighbour during #handle_dv_learn.
7742 * We call #forward_dv_learn() on the neighbour(s) selected
7743 * during #dv_neighbour_selection().
7744 *
7745 * @param cls a `struct NeighbourSelectionContext *`
7746 * @param pid identity of the peer
7747 * @param value a `struct Neighbour`
7748 * @return #GNUNET_YES (always)
7749 */
7750static int
7751dv_neighbour_transmission (void *cls,
7752 const struct GNUNET_PeerIdentity *pid,
7753 void *value)
7754{
7755 struct NeighbourSelectionContext *nsc = cls;
7756
7757 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7758 "transmission %s\n",
7759 GNUNET_i2s (pid));
7760 (void) value;
7761 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7762 return GNUNET_YES; /* skip initiator */
7763 for (unsigned int i = 0; i < nsc->nhops; i++)
7764 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7765 return GNUNET_YES;
7766 /* skip peers on path */
7767 for (unsigned int i = 0; i < nsc->num_selections; i++)
7768 {
7769 if (nsc->selections[i] == nsc->num_eligible)
7770 {
7771 forward_dv_learn (pid,
7772 nsc->dvl,
7773 nsc->bi_history,
7774 nsc->nhops,
7775 nsc->hops,
7776 nsc->in_time);
7777 break;
7778 }
7779 }
7780 nsc->num_eligible++;
7781 return GNUNET_YES;
7782}
7783
7784
7785/**
7786 * Computes the number of neighbours we should forward a DVInit
7787 * message to given that it has so far taken @a hops_taken hops
7788 * though the network and that the number of neighbours we have
7789 * in total is @a neighbour_count, out of which @a eligible_count
7790 * are not yet on the path.
7791 *
7792 * NOTE: technically we might want to include NSE in the formula to
7793 * get a better grip on the overall network size. However, for now
7794 * using NSE here would create a dependency issue in the build system.
7795 * => Left for later, hardcoded to 50 for now.
7796 *
7797 * The goal of the fomula is that we want to reach a total of LOG(NSE)
7798 * peers via DV (`target_total`). We want the reach to be spread out
7799 * over various distances to the origin, with a bias towards shorter
7800 * distances.
7801 *
7802 * We make the strong assumption that the network topology looks
7803 * "similar" at other hops, in particular the @a neighbour_count
7804 * should be comparable at other hops.
7805 *
7806 * If the local neighbourhood is densely connected, we expect that @a
7807 * eligible_count is close to @a neighbour_count minus @a hops_taken
7808 * as a lot of the path is already known. In that case, we should
7809 * forward to few(er) peers to try to find a path out of the
7810 * neighbourhood. OTOH, if @a eligible_count is close to @a
7811 * neighbour_count, we should forward to many peers as we are either
7812 * still close to the origin (i.e. @a hops_taken is small) or because
7813 * we managed to get beyond a local cluster. We express this as
7814 * the `boost_factor` using the square of the fraction of eligible
7815 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
7816 * 99% are eligible, the 'boost' will be almost 1).
7817 *
7818 * Second, the more hops we have taken, the larger the problem of an
7819 * exponential traffic explosion gets. So we take the `target_total`,
7820 * and compute our degree such that at each distance d 2^{-d} peers
7821 * are selected (corrected by the `boost_factor`).
7822 *
7823 * @param hops_taken number of hops DVInit has travelled so far
7824 * @param neighbour_count number of neighbours we have in total
7825 * @param eligible_count number of neighbours we could in
7826 * theory forward to
7827 */
7828static unsigned int
7829calculate_fork_degree (unsigned int hops_taken,
7830 unsigned int neighbour_count,
7831 unsigned int eligible_count)
7832{
7833 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
7834 double eligible_ratio =
7835 ((double) eligible_count) / ((double) neighbour_count);
7836 double boost_factor = eligible_ratio * eligible_ratio;
7837 unsigned int rnd;
7838 double left;
7839
7840 if (hops_taken >= 64)
7841 {
7842 GNUNET_break (0);
7843 return 0; /* precaution given bitshift below */
7844 }
7845 for (unsigned int i = 1; i < hops_taken; i++)
7846 {
7847 /* For each hop, subtract the expected number of targets
7848 reached at distance d (so what remains divided by 2^d) */
7849 target_total -= (target_total * boost_factor / (1LLU << i));
7850 }
7851 rnd =
7852 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
7853 /* round up or down probabilistically depending on how close we were
7854 when floor()ing to rnd */
7855 left = target_total - (double) rnd;
7856 if (UINT32_MAX * left >
7857 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
7858 rnd++; /* round up */
7859 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7860 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
7861 hops_taken,
7862 rnd,
7863 eligible_count,
7864 neighbour_count);
7865 return rnd;
7866}
7867
7868
7869/**
7870 * Function called when peerstore is done storing a DV monotonic time.
7871 *
7872 * @param cls a `struct Neighbour`
7873 * @param success #GNUNET_YES if peerstore was successful
7874 */
7875static void
7876neighbour_store_dvmono_cb (void *cls, int success)
7877{
7878 struct Neighbour *n = cls;
7879
7880 n->sc = NULL;
7881 if (GNUNET_YES != success)
7882 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7883 "Failed to store other peer's monotonic time in peerstore!\n");
7884}
7885
7886
7887/**
7888 * Communicator gave us a DV learn message. Process the request.
7889 *
7890 * @param cls a `struct CommunicatorMessageContext` (must call
7891 * #finish_cmc_handling() when done)
7892 * @param dvl the message that was received
7893 */
7894static void
7895handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
7896{
7897 struct CommunicatorMessageContext *cmc = cls;
7898 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
7899 int bi_hop;
7900 uint16_t nhops;
7901 uint16_t bi_history;
7902 const struct DVPathEntryP *hops;
7903 int do_fwd;
7904 int did_initiator;
7905 struct GNUNET_TIME_Absolute in_time;
7906 struct Neighbour *n;
7907
7908 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
7909 bi_history = ntohs (dvl->bidirectional);
7910 hops = (const struct DVPathEntryP *) &dvl[1];
7911 if (0 == nhops)
7912 {
7913 /* sanity check */
7914 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
7915 {
7916 GNUNET_break (0);
7917 finish_cmc_handling (cmc);
7918 return;
7919 }
7920 }
7921 else
7922 {
7923 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7924 "handle dv learn message last hop %s\n",
7925 GNUNET_i2s (&hops[nhops - 1].hop));
7926 /* sanity check */
7927 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
7928 {
7929 GNUNET_break (0);
7930 finish_cmc_handling (cmc);
7931 return;
7932 }
7933 }
7934
7935 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
7936 cc = cmc->tc->details.communicator.cc;
7937 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
7938 cc); // FIXME: add bi-directional flag to cc?
7939 in_time = GNUNET_TIME_absolute_get ();
7940
7941 /* continue communicator here, everything else can happen asynchronous! */
7942 finish_cmc_handling (cmc);
7943
7944 n = lookup_neighbour (&dvl->initiator);
7945 if (NULL != n)
7946 {
7947 if ((n->dv_monotime_available == GNUNET_YES) &&
7948 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
7949 n->last_dv_learn_monotime.abs_value_us))
7950 {
7951 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7952 "DV learn from %s discarded due to time travel",
7953 GNUNET_i2s (&dvl->initiator));
7954 GNUNET_STATISTICS_update (GST_stats,
7955 "# DV learn discarded due to time travel",
7956 1,
7957 GNUNET_NO);
7958 return;
7959 }
7960 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
7961 &dvl->initiator,
7962 &dvl->challenge,
7963 &dvl->init_sig))
7964 {
7965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7966 "DV learn signature from %s invalid\n",
7967 GNUNET_i2s (&dvl->initiator));
7968 GNUNET_break_op (0);
7969 return;
7970 }
7971 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
7972 if (GNUNET_YES == n->dv_monotime_available)
7973 {
7974 if (NULL != n->sc)
7975 {
7976 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7977 "store cancel\n");
7978 GNUNET_PEERSTORE_store_cancel (n->sc);
7979 }
7980 n->sc =
7981 GNUNET_PEERSTORE_store (peerstore,
7982 "transport",
7983 &dvl->initiator,
7984 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
7985 &dvl->monotonic_time,
7986 sizeof(dvl->monotonic_time),
7987 GNUNET_TIME_UNIT_FOREVER_ABS,
7988 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7989 &neighbour_store_dvmono_cb,
7990 n);
7991 }
7992 }
7993 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
7994 If signature verification load too high, implement random drop strategy */
7995 for (unsigned int i = 0; i < nhops; i++)
7996 {
7997 struct DvHopPS dhp = { .purpose.purpose =
7998 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
7999 .purpose.size = htonl (sizeof(dhp)),
8000 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
8001 .succ = (nhops == i + 1) ? GST_my_identity
8002 : hops[i + 1].hop,
8003 .challenge = dvl->challenge };
8004
8005 if (GNUNET_OK !=
8006 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
8007 &dhp,
8008 &hops[i].hop_sig,
8009 &hops[i].hop.public_key))
8010 {
8011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8012 "DV learn from %s signature of hop %u invalid\n",
8013 GNUNET_i2s (&dvl->initiator),
8014 i);
8015 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8016 "signature of hop %s invalid\n",
8017 GNUNET_i2s (&hops[i].hop));
8018 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8019 "pred %s\n",
8020 GNUNET_i2s (&dhp.pred));
8021 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8022 "succ %s\n",
8023 GNUNET_i2s (&dhp.succ));
8024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8025 "hash %s\n",
8026 GNUNET_sh2s (&dhp.challenge.value));
8027 GNUNET_break_op (0);
8028 return;
8029 }
8030 }
8031 if (GNUNET_EXTRA_LOGGING > 0)
8032 {
8033 char *path;
8034
8035 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
8036 for (unsigned int i = 0; i < nhops; i++)
8037 {
8038 char *tmp;
8039
8040 GNUNET_asprintf (&tmp,
8041 "%s%s%s",
8042 path,
8043 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
8044 GNUNET_i2s (&hops[i].hop));
8045 GNUNET_free (path);
8046 path = tmp;
8047 }
8048 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8049 "Received DVInit via %s%s%s\n",
8050 path,
8051 bi_hop ? "<->" : "-->",
8052 GNUNET_i2s (&GST_my_identity));
8053 GNUNET_free (path);
8054 }
8055 do_fwd = GNUNET_YES;
8056 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
8057 {
8058 struct GNUNET_PeerIdentity path[nhops + 1];
8059 struct GNUNET_TIME_Relative host_latency_sum;
8060 struct GNUNET_TIME_Relative latency;
8061 struct GNUNET_TIME_Relative network_latency;
8062
8063 /* We initiated this, learn the forward path! */
8064 path[0] = GST_my_identity;
8065 path[1] = hops[0].hop;
8066 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
8067
8068 // Need also something to lookup initiation time
8069 // to compute RTT! -> add RTT argument here?
8070 latency = GNUNET_TIME_absolute_get_duration (GNUNET_TIME_absolute_ntoh (
8071 dvl->monotonic_time));
8072 GNUNET_assert (latency.rel_value_us >= host_latency_sum.rel_value_us);
8073 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
8074 // (based on dvl->challenge, we can identify time of origin!)
8075
8076 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
8077 /* assumption: latency on all links is the same */
8078 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
8079
8080 for (unsigned int i = 2; i <= nhops; i++)
8081 {
8082 struct GNUNET_TIME_Relative ilat;
8083
8084 /* assumption: linear latency increase per hop */
8085 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
8086 path[i] = hops[i - 1].hop;
8087 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8088 "Learned path with %u hops to %s with latency %s\n",
8089 i,
8090 GNUNET_i2s (&path[i]),
8091 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
8092 learn_dv_path (path,
8093 i + 1,
8094 ilat,
8095 GNUNET_TIME_relative_to_absolute (
8096 ADDRESS_VALIDATION_LIFETIME));
8097 }
8098 /* as we initiated, do not forward again (would be circular!) */
8099 do_fwd = GNUNET_NO;
8100 return;
8101 }
8102 if (bi_hop)
8103 {
8104 /* last hop was bi-directional, we could learn something here! */
8105 struct GNUNET_PeerIdentity path[nhops + 2];
8106
8107 path[0] = GST_my_identity;
8108 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
8109 for (unsigned int i = 0; i < nhops; i++)
8110 {
8111 int iret;
8112
8113 if (0 == (bi_history & (1 << i)))
8114 break; /* i-th hop not bi-directional, stop learning! */
8115 if (i == nhops - 1)
8116 {
8117 path[i + 2] = dvl->initiator;
8118 }
8119 else
8120 {
8121 path[i + 2] = hops[nhops - i - 2].hop;
8122 }
8123
8124 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8125 "Learned inverse path with %u hops to %s\n",
8126 i + 2,
8127 GNUNET_i2s (&path[i + 2]));
8128 iret = learn_dv_path (path,
8129 i + 3,
8130 GNUNET_TIME_UNIT_FOREVER_REL,
8131 GNUNET_TIME_relative_to_absolute (
8132 ADDRESS_VALIDATION_LIFETIME));
8133 if (GNUNET_SYSERR == iret)
8134 {
8135 /* path invalid or too long to be interesting for US, thus should also
8136 not be interesting to our neighbours, cut path when forwarding to
8137 'i' hops, except of course for the one that goes back to the
8138 initiator */
8139 GNUNET_STATISTICS_update (GST_stats,
8140 "# DV learn not forwarded due invalidity of path",
8141 1,
8142 GNUNET_NO);
8143 do_fwd = GNUNET_NO;
8144 break;
8145 }
8146 if ((GNUNET_NO == iret) && (nhops == i + 1))
8147 {
8148 /* we have better paths, and this is the longest target,
8149 so there cannot be anything interesting later */
8150 GNUNET_STATISTICS_update (GST_stats,
8151 "# DV learn not forwarded, got better paths",
8152 1,
8153 GNUNET_NO);
8154 do_fwd = GNUNET_NO;
8155 break;
8156 }
8157 }
8158 }
8159 if (MAX_DV_HOPS_ALLOWED == nhops)
8160 {
8161 /* At limit, we're out of here! */
8162 return;
8163 }
8164
8165 /* Forward to initiator, if path non-trivial and possible */
8166 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
8167 did_initiator = GNUNET_NO;
8168 if ((1 <= nhops) &&
8169 (GNUNET_YES ==
8170 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
8171 {
8172 /* send back to origin! */
8173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8174 "Sending DVL back to initiator %s\n",
8175 GNUNET_i2s (&dvl->initiator));
8176 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
8177 did_initiator = GNUNET_YES;
8178 }
8179 /* We forward under two conditions: either we still learned something
8180 ourselves (do_fwd), or the path was darn short and thus the initiator is
8181 likely to still be very interested in this (and we did NOT already
8182 send it back to the initiator) */
8183 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
8184 (GNUNET_NO == did_initiator)))
8185 {
8186 /* Pick random neighbours that are not yet on the path */
8187 struct NeighbourSelectionContext nsc;
8188 unsigned int n_cnt;
8189
8190 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
8191 nsc.nhops = nhops;
8192 nsc.dvl = dvl;
8193 nsc.bi_history = bi_history;
8194 nsc.hops = hops;
8195 nsc.in_time = in_time;
8196 nsc.num_eligible = 0;
8197 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8198 &dv_neighbour_selection,
8199 &nsc);
8200 if (0 == nsc.num_eligible)
8201 return; /* done here, cannot forward to anyone else */
8202 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
8203 nsc.num_selections =
8204 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
8205 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8206 "Forwarding DVL to %u other peers\n",
8207 nsc.num_selections);
8208 for (unsigned int i = 0; i < nsc.num_selections; i++)
8209 nsc.selections[i] =
8210 (nsc.num_selections == n_cnt)
8211 ? i /* all were selected, avoid collisions by chance */
8212 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
8213 nsc.num_eligible = 0;
8214 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8215 &dv_neighbour_transmission,
8216 &nsc);
8217 }
8218}
8219
8220
8221/**
8222 * Communicator gave us a DV box. Check the message.
8223 *
8224 * @param cls a `struct CommunicatorMessageContext`
8225 * @param dvb the send message that was sent
8226 * @return #GNUNET_YES if message is well-formed
8227 */
8228static int
8229check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
8230{
8231 uint16_t size = ntohs (dvb->header.size);
8232 uint16_t num_hops = ntohs (dvb->num_hops);
8233 const struct GNUNET_PeerIdentity *hops =
8234 (const struct GNUNET_PeerIdentity *) &dvb[1];
8235
8236 (void) cls;
8237 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
8238 + sizeof(struct GNUNET_MessageHeader))
8239 {
8240 GNUNET_break_op (0);
8241 return GNUNET_SYSERR;
8242 }
8243 /* This peer must not be on the path */
8244 for (unsigned int i = 0; i < num_hops; i++)
8245 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
8246 {
8247 GNUNET_break_op (0);
8248 return GNUNET_SYSERR;
8249 }
8250 return GNUNET_YES;
8251}
8252
8253
8254/**
8255 * Create a DV Box message and queue it for transmission to
8256 * @a next_hop.
8257 *
8258 * @param next_hop peer to receive the message next
8259 * @param total_hops how many hops did the message take so far
8260 * @param num_hops length of the @a hops array
8261 * @param origin origin of the message
8262 * @param hops next peer(s) to the destination, including destination
8263 * @param payload payload of the box
8264 * @param payload_size number of bytes in @a payload
8265 */
8266static void
8267forward_dv_box (struct Neighbour *next_hop,
8268 struct TransportDVBoxMessage *hdr,
8269 uint16_t total_hops,
8270 uint16_t num_hops,
8271 const struct GNUNET_PeerIdentity *hops,
8272 const void *enc_payload,
8273 uint16_t enc_payload_size)
8274{
8275 struct VirtualLink *vl = next_hop->vl;
8276 struct PendingMessage *pm;
8277 size_t msg_size = sizeof(struct TransportDVBoxMessage)
8278 + num_hops * sizeof(struct GNUNET_PeerIdentity)
8279 + enc_payload_size;
8280 char *buf;
8281 char msg_buf[msg_size] GNUNET_ALIGN;
8282 struct GNUNET_PeerIdentity *dhops;
8283
8284 hdr->num_hops = htons (num_hops);
8285 hdr->total_hops = htons (total_hops);
8286 hdr->header.size = htons (msg_size);
8287 memcpy (msg_buf, hdr, sizeof(*hdr));
8288 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
8289 TransportDVBoxMessage)];
8290 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
8291 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
8292
8293 if (GNUNET_YES == ntohs (hdr->without_fc))
8294 {
8295 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8296 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
8297 enc_payload_size,
8298 GNUNET_i2s (&next_hop->pid),
8299 (unsigned int) num_hops,
8300 (unsigned int) total_hops);
8301 route_via_neighbour (next_hop, (const struct
8302 GNUNET_MessageHeader *) msg_buf,
8303 RMO_ANYTHING_GOES);
8304 }
8305 else
8306 {
8307 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
8308 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8309 "2 created pm %p storing vl %p \n",
8310 pm,
8311 vl);
8312 pm->pmt = PMT_DV_BOX;
8313 pm->vl = vl;
8314 pm->target = next_hop->pid;
8315 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
8316 pm->logging_uuid = logging_uuid_gen++;
8317 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
8318 pm->bytes_msg = msg_size;
8319 buf = (char *) &pm[1];
8320 memcpy (buf, msg_buf, msg_size);
8321
8322 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8323 "Created pending message %" PRIu64
8324 " for DV Box with next hop %s (%u/%u)\n",
8325 pm->logging_uuid,
8326 GNUNET_i2s (&next_hop->pid),
8327 (unsigned int) num_hops,
8328 (unsigned int) total_hops);
8329
8330 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
8331 {
8332 GNUNET_CONTAINER_MDLL_insert (vl,
8333 vl->pending_msg_head,
8334 vl->pending_msg_tail,
8335 pm);
8336
8337 check_vl_transmission (vl);
8338 }
8339 else
8340 {
8341 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8342 "The virtual link is not ready for forwarding a DV Box with payload, storing PendingMessage in ring buffer.\n");
8343
8344 if (NULL != ring_buffer_dv[ring_buffer_dv_head])
8345 {
8346 struct PendingMessage *pm_old = ring_buffer_dv[ring_buffer_dv_head];
8347
8348 GNUNET_free (pm_old);
8349 }
8350 ring_buffer_dv[ring_buffer_dv_head] = pm;
8351 if (RING_BUFFER_SIZE - 1 == ring_buffer_dv_head)
8352 {
8353 ring_buffer_dv_head = 0;
8354 is_ring_buffer_dv_full = GNUNET_YES;
8355 }
8356 else
8357 ring_buffer_dv_head++;
8358
8359 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8360 "%u items stored in DV ring buffer\n",
8361 GNUNET_YES == is_ring_buffer_dv_full ? RING_BUFFER_SIZE :
8362 ring_buffer_dv_head);
8363 }
8364 }
8365}
8366
8367
8368/**
8369 * Free data structures associated with @a b.
8370 *
8371 * @param b data structure to release
8372 */
8373static void
8374free_backtalker (struct Backtalker *b)
8375{
8376 if (NULL != b->get)
8377 {
8378 GNUNET_PEERSTORE_iteration_stop (b->get);
8379 b->get = NULL;
8380 GNUNET_assert (NULL != b->cmc);
8381 finish_cmc_handling (b->cmc);
8382 b->cmc = NULL;
8383 }
8384 if (NULL != b->task)
8385 {
8386 GNUNET_SCHEDULER_cancel (b->task);
8387 b->task = NULL;
8388 }
8389 if (NULL != b->sc)
8390 {
8391 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8392 "store cancel\n");
8393 GNUNET_PEERSTORE_store_cancel (b->sc);
8394 b->sc = NULL;
8395 }
8396 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8397 "Removing backtalker for %s\n",
8398 GNUNET_i2s (&b->pid));
8399 GNUNET_assert (
8400 GNUNET_YES ==
8401 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
8402 GNUNET_free (b);
8403}
8404
8405
8406/**
8407 * Callback to free backtalker records.
8408 *
8409 * @param cls NULL
8410 * @param pid unused
8411 * @param value a `struct Backtalker`
8412 * @return #GNUNET_OK (always)
8413 */
8414static int
8415free_backtalker_cb (void *cls,
8416 const struct GNUNET_PeerIdentity *pid,
8417 void *value)
8418{
8419 struct Backtalker *b = value;
8420
8421 (void) cls;
8422 (void) pid;
8423 free_backtalker (b);
8424 return GNUNET_OK;
8425}
8426
8427
8428/**
8429 * Function called when it is time to clean up a backtalker.
8430 *
8431 * @param cls a `struct Backtalker`
8432 */
8433static void
8434backtalker_timeout_cb (void *cls)
8435{
8436 struct Backtalker *b = cls;
8437
8438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8439 "backtalker timeout.\n");
8440 b->task = NULL;
8441 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
8442 {
8443 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8444 return;
8445 }
8446 GNUNET_assert (NULL == b->sc);
8447 free_backtalker (b);
8448}
8449
8450
8451/**
8452 * Function called with the monotonic time of a backtalker
8453 * by PEERSTORE. Updates the time and continues processing.
8454 *
8455 * @param cls a `struct Backtalker`
8456 * @param record the information found, NULL for the last call
8457 * @param emsg error message
8458 */
8459static void
8460backtalker_monotime_cb (void *cls,
8461 const struct GNUNET_PEERSTORE_Record *record,
8462 const char *emsg)
8463{
8464 struct Backtalker *b = cls;
8465 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8466 struct GNUNET_TIME_Absolute mt;
8467
8468 (void) emsg;
8469 if (NULL == record)
8470 {
8471 /* we're done with #backtalker_monotime_cb() invocations,
8472 continue normal processing */
8473 b->get = NULL;
8474 GNUNET_assert (NULL != b->cmc);
8475 b->cmc->mh = (const struct GNUNET_MessageHeader *) &b[1];
8476 if (0 != b->body_size)
8477 demultiplex_with_cmc (b->cmc);
8478 else
8479 finish_cmc_handling (b->cmc);
8480 b->cmc = NULL;
8481 return;
8482 }
8483 if (sizeof(*mtbe) != record->value_size)
8484 {
8485 GNUNET_PEERSTORE_iteration_next (b->get, 1);
8486 GNUNET_break (0);
8487 return;
8488 }
8489 mtbe = record->value;
8490 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
8491 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
8492 {
8493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8494 "Backtalker message from %s dropped, monotime in the past\n",
8495 GNUNET_i2s (&b->pid));
8496 GNUNET_STATISTICS_update (
8497 GST_stats,
8498 "# Backchannel messages dropped: monotonic time not increasing",
8499 1,
8500 GNUNET_NO);
8501 b->monotonic_time = mt;
8502 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
8503 */
8504 b->body_size = 0;
8505 }
8506 GNUNET_PEERSTORE_iteration_next (b->get, 1);
8507}
8508
8509
8510/**
8511 * Function called by PEERSTORE when the store operation of
8512 * a backtalker's monotonic time is complete.
8513 *
8514 * @param cls the `struct Backtalker`
8515 * @param success #GNUNET_OK on success
8516 */
8517static void
8518backtalker_monotime_store_cb (void *cls, int success)
8519{
8520 struct Backtalker *b = cls;
8521
8522 if (GNUNET_OK != success)
8523 {
8524 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8525 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
8526 }
8527 b->sc = NULL;
8528 if (NULL != b->task)
8529 {
8530 GNUNET_SCHEDULER_cancel (b->task);
8531 b->task = NULL;
8532 }
8533 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8534}
8535
8536
8537/**
8538 * The backtalker @a b monotonic time changed. Update PEERSTORE.
8539 *
8540 * @param b a backtalker with updated monotonic time
8541 */
8542static void
8543update_backtalker_monotime (struct Backtalker *b)
8544{
8545 struct GNUNET_TIME_AbsoluteNBO mtbe;
8546
8547 if (NULL != b->sc)
8548 {
8549 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8550 "store cancel before store with sc %p\n",
8551 b->sc);
8552 /*GNUNET_PEERSTORE_store_cancel (b->sc);
8553 b->sc = NULL;*/
8554 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8555 "store cancel before store with sc %p is null\n",
8556 b->sc);
8557 }
8558 else
8559 {
8560 GNUNET_SCHEDULER_cancel (b->task);
8561 b->task = NULL;
8562 }
8563 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
8564 b->sc =
8565 GNUNET_PEERSTORE_store (peerstore,
8566 "transport",
8567 &b->pid,
8568 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
8569 &mtbe,
8570 sizeof(mtbe),
8571 GNUNET_TIME_UNIT_FOREVER_ABS,
8572 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
8573 &backtalker_monotime_store_cb,
8574 b);
8575}
8576
8577
8578/**
8579 * Communicator gave us a DV box. Process the request.
8580 *
8581 * @param cls a `struct CommunicatorMessageContext` (must call
8582 * #finish_cmc_handling() when done)
8583 * @param dvb the message that was received
8584 */
8585static void
8586handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
8587{
8588 struct CommunicatorMessageContext *cmc = cls;
8589 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
8590 uint16_t num_hops = ntohs (dvb->num_hops);
8591 const struct GNUNET_PeerIdentity *hops =
8592 (const struct GNUNET_PeerIdentity *) &dvb[1];
8593 const char *enc_payload = (const char *) &hops[num_hops];
8594 uint16_t enc_payload_size =
8595 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
8596 struct DVKeyState key;
8597 struct GNUNET_HashCode hmac;
8598 const char *hdr;
8599 size_t hdr_len;
8600
8601 if (GNUNET_EXTRA_LOGGING > 0)
8602 {
8603 char *path;
8604
8605 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
8606 for (unsigned int i = 0; i < num_hops; i++)
8607 {
8608 char *tmp;
8609
8610 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
8611 GNUNET_free (path);
8612 path = tmp;
8613 }
8614 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8615 "Received DVBox with remaining path %s\n",
8616 path);
8617 GNUNET_free (path);
8618 }
8619
8620 if (num_hops > 0)
8621 {
8622 /* We're trying from the end of the hops array, as we may be
8623 able to find a shortcut unknown to the origin that way */
8624 for (int i = num_hops - 1; i >= 0; i--)
8625 {
8626 struct Neighbour *n;
8627
8628 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
8629 {
8630 GNUNET_break_op (0);
8631 finish_cmc_handling (cmc);
8632 return;
8633 }
8634 n = lookup_neighbour (&hops[i]);
8635 if (NULL == n)
8636 continue;
8637 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8638 "Skipping %u/%u hops ahead while routing DV Box\n",
8639 i,
8640 num_hops);
8641
8642 forward_dv_box (n,
8643 (struct TransportDVBoxMessage *) dvb,
8644 ntohs (dvb->total_hops) + 1,
8645 num_hops - i - 1, /* number of hops left */
8646 &hops[i + 1], /* remaining hops */
8647 enc_payload,
8648 enc_payload_size);
8649 GNUNET_STATISTICS_update (GST_stats,
8650 "# DV hops skipped routing boxes",
8651 i,
8652 GNUNET_NO);
8653 GNUNET_STATISTICS_update (GST_stats,
8654 "# DV boxes routed (total)",
8655 1,
8656 GNUNET_NO);
8657 finish_cmc_handling (cmc);
8658 return;
8659 }
8660 /* Woopsie, next hop not in neighbours, drop! */
8661 GNUNET_STATISTICS_update (GST_stats,
8662 "# DV Boxes dropped: next hop unknown",
8663 1,
8664 GNUNET_NO);
8665 finish_cmc_handling (cmc);
8666 return;
8667 }
8668 /* We are the target. Unbox and handle message. */
8669 GNUNET_STATISTICS_update (GST_stats,
8670 "# DV boxes opened (ultimate target)",
8671 1,
8672 GNUNET_NO);
8673 cmc->total_hops = ntohs (dvb->total_hops);
8674
8675 // DH key derivation with received DV, could be garbage.
8676 struct GNUNET_HashCode km;
8677
8678 if (GNUNET_YES != GNUNET_CRYPTO_eddsa_kem_decaps (GST_my_private_key,
8679 &dvb->ephemeral_key,
8680 &km))
8681 {
8682 GNUNET_break_op (0);
8683 finish_cmc_handling (cmc);
8684 return;
8685 }
8686 dv_setup_key_state_from_km (&km, &dvb->iv, &key);
8687 hdr = (const char *) &dvb[1];
8688 hdr_len = ntohs (dvb->orig_size) - sizeof(*dvb) - sizeof(struct
8689 GNUNET_PeerIdentity)
8690 * ntohs (dvb->total_hops);
8691
8692 dv_hmac (&key, &hmac, hdr, hdr_len);
8693 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
8694 {
8695 /* HMAC mismatch, discard! */
8696 GNUNET_break_op (0);
8697 finish_cmc_handling (cmc);
8698 return;
8699 }
8700 /* begin actual decryption */
8701 {
8702 struct Backtalker *b;
8703 struct GNUNET_TIME_Absolute monotime;
8704 struct TransportDVBoxPayloadP ppay;
8705 char body[hdr_len - sizeof(ppay)] GNUNET_ALIGN;
8706 const struct GNUNET_MessageHeader *mh;
8707
8708 GNUNET_assert (hdr_len >=
8709 sizeof(ppay) + sizeof(struct GNUNET_MessageHeader));
8710 if (GNUNET_OK != dv_decrypt (&key, &ppay, hdr, sizeof(ppay)))
8711 {
8712 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8713 "Error decrypting DV payload header\n");
8714 GNUNET_break_op (0);
8715 finish_cmc_handling (cmc);
8716 return;
8717 }
8718 if (GNUNET_OK != dv_decrypt (&key, body,
8719 &hdr[sizeof(ppay)], hdr_len - sizeof(ppay)))
8720 {
8721 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8722 "Error decrypting DV payload\n");
8723 GNUNET_break_op (0);
8724 finish_cmc_handling (cmc);
8725 return;
8726 }
8727 mh = (const struct GNUNET_MessageHeader *) body;
8728 dv_key_clean (&key);
8729 if (ntohs (mh->size) != sizeof(body))
8730 {
8731 GNUNET_break_op (0);
8732 finish_cmc_handling (cmc);
8733 return;
8734 }
8735 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
8736 switch (ntohs (mh->type))
8737 {
8738 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
8739 GNUNET_break_op (0);
8740 finish_cmc_handling (cmc);
8741 return;
8742
8743 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
8744 GNUNET_break_op (0);
8745 finish_cmc_handling (cmc);
8746 return;
8747
8748 default:
8749 /* permitted, continue */
8750 break;
8751 }
8752 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
8753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8754 "Decrypted backtalk from %s\n",
8755 GNUNET_i2s (&ppay.sender));
8756 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
8757 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
8758 {
8759 GNUNET_STATISTICS_update (
8760 GST_stats,
8761 "# Backchannel messages dropped: monotonic time not increasing",
8762 1,
8763 GNUNET_NO);
8764 finish_cmc_handling (cmc);
8765 return;
8766 }
8767 if ((NULL == b) ||
8768 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
8769 {
8770 /* Check signature */
8771 struct EphemeralConfirmationPS ec;
8772
8773 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
8774 ec.target = GST_my_identity;
8775 ec.ephemeral_key = dvb->ephemeral_key;
8776 ec.purpose.size = htonl (sizeof(ec));
8777 ec.sender_monotonic_time = ppay.monotonic_time;
8778 if (
8779 GNUNET_OK !=
8780 GNUNET_CRYPTO_eddsa_verify (
8781 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
8782 &ec,
8783 &ppay.sender_sig,
8784 &ppay.sender.public_key))
8785 {
8786 /* Signature invalid, discard! */
8787 GNUNET_break_op (0);
8788 finish_cmc_handling (cmc);
8789 return;
8790 }
8791 }
8792 /* Update sender, we now know the real origin! */
8793 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8794 "DVBox received for me from %s via %s\n",
8795 GNUNET_i2s2 (&ppay.sender),
8796 GNUNET_i2s (&cmc->im.sender));
8797 cmc->im.sender = ppay.sender;
8798
8799 if (NULL != b)
8800 {
8801 /* update key cache and mono time */
8802 b->last_ephemeral = dvb->ephemeral_key;
8803 b->monotonic_time = monotime;
8804 update_backtalker_monotime (b);
8805 b->timeout =
8806 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8807 cmc->mh = mh;
8808 demultiplex_with_cmc (cmc);
8809 return;
8810 }
8811 /* setup data structure to cache signature AND check
8812 monotonic time with PEERSTORE before forwarding backchannel payload */
8813 b = GNUNET_malloc (sizeof(struct Backtalker) + sizeof(body));
8814 b->pid = ppay.sender;
8815 b->body_size = sizeof(body);
8816 memcpy (&b[1], body, sizeof(body));
8817 GNUNET_assert (GNUNET_YES ==
8818 GNUNET_CONTAINER_multipeermap_put (
8819 backtalkers,
8820 &b->pid,
8821 b,
8822 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8823 b->monotonic_time = monotime; /* NOTE: to be checked still! */
8824 b->cmc = cmc;
8825 b->timeout =
8826 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8827 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8828 b->get =
8829 GNUNET_PEERSTORE_iteration_start (peerstore,
8830 "transport",
8831 &b->pid,
8832 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
8833 &backtalker_monotime_cb,
8834 b);
8835 } /* end actual decryption */
8836}
8837
8838
8839/**
8840 * Client notified us about transmission from a peer. Process the request.
8841 *
8842 * @param cls a `struct TransportClient` which sent us the message
8843 * @param im the send message that was sent
8844 * @return #GNUNET_YES if message is well-formed
8845 */
8846static int
8847check_incoming_msg (void *cls,
8848 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8849{
8850 struct TransportClient *tc = cls;
8851
8852 if (CT_COMMUNICATOR != tc->type)
8853 {
8854 GNUNET_break (0);
8855 return GNUNET_SYSERR;
8856 }
8857 GNUNET_MQ_check_boxed_message (im);
8858 return GNUNET_OK;
8859}
8860
8861
8862/**
8863 * Closure for #check_known_address.
8864 */
8865struct CheckKnownAddressContext
8866{
8867 /**
8868 * Set to the address we are looking for.
8869 */
8870 const char *address;
8871
8872 /**
8873 * Set to a matching validation state, if one was found.
8874 */
8875 struct ValidationState *vs;
8876};
8877
8878
8879/**
8880 * Test if the validation state in @a value matches the
8881 * address from @a cls.
8882 *
8883 * @param cls a `struct CheckKnownAddressContext`
8884 * @param pid unused (must match though)
8885 * @param value a `struct ValidationState`
8886 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8887 */
8888static int
8889check_known_address (void *cls,
8890 const struct GNUNET_PeerIdentity *pid,
8891 void *value)
8892{
8893 struct CheckKnownAddressContext *ckac = cls;
8894 struct ValidationState *vs = value;
8895
8896 (void) pid;
8897 if (0 != strcmp (vs->address, ckac->address))
8898 return GNUNET_OK;
8899 ckac->vs = vs;
8900 return GNUNET_NO;
8901}
8902
8903
8904/**
8905 * Task run periodically to validate some address based on #validation_heap.
8906 *
8907 * @param cls NULL
8908 */
8909static void
8910validation_start_cb (void *cls);
8911
8912
8913/**
8914 * Set the time for next_challenge of @a vs to @a new_time.
8915 * Updates the heap and if necessary reschedules the job.
8916 *
8917 * @param vs validation state to update
8918 * @param new_time new time for revalidation
8919 */
8920static void
8921update_next_challenge_time (struct ValidationState *vs,
8922 struct GNUNET_TIME_Absolute new_time)
8923{
8924 struct GNUNET_TIME_Relative delta;
8925
8926 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
8927 return; /* be lazy */
8928 vs->next_challenge = new_time;
8929 if (NULL == vs->hn)
8930 vs->hn =
8931 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
8932 else
8933 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
8934 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
8935 (NULL != validation_task))
8936 return;
8937 if (NULL != validation_task)
8938 GNUNET_SCHEDULER_cancel (validation_task);
8939 /* randomize a bit */
8940 delta.rel_value_us =
8941 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
8942 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
8943 new_time = GNUNET_TIME_absolute_add (new_time, delta);
8944 validation_task =
8945 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
8946}
8947
8948
8949/**
8950 * Start address validation.
8951 *
8952 * @param pid peer the @a address is for
8953 * @param address an address to reach @a pid (presumably)
8954 */
8955static void
8956start_address_validation (const struct GNUNET_PeerIdentity *pid,
8957 const char *address)
8958{
8959 struct GNUNET_TIME_Absolute now;
8960 struct ValidationState *vs;
8961 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
8962
8963 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8964 pid,
8965 &check_known_address,
8966 &ckac);
8967 if (NULL != (vs = ckac.vs))
8968 {
8969 /* if 'vs' is not currently valid, we need to speed up retrying the
8970 * validation */
8971 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8972 {
8973 /* reduce backoff as we got a fresh advertisement */
8974 vs->challenge_backoff =
8975 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8976 GNUNET_TIME_relative_divide (
8977 vs->challenge_backoff,
8978 2));
8979 update_next_challenge_time (vs,
8980 GNUNET_TIME_relative_to_absolute (
8981 vs->challenge_backoff));
8982 }
8983 return;
8984 }
8985 now = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
8986 vs = GNUNET_new (struct ValidationState);
8987 vs->pid = *pid;
8988 vs->valid_until =
8989 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8990 vs->first_challenge_use = now;
8991 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8992 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8993 &vs->challenge,
8994 sizeof(vs->challenge));
8995 vs->address = GNUNET_strdup (address);
8996 GNUNET_CRYPTO_hash (vs->address, strlen (vs->address), &vs->hc);
8997 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8998 "Starting address validation `%s' of peer %s using challenge %s\n",
8999 address,
9000 GNUNET_i2s (pid),
9001 GNUNET_sh2s (&vs->challenge.value));
9002 GNUNET_assert (GNUNET_YES ==
9003 GNUNET_CONTAINER_multipeermap_put (
9004 validation_map,
9005 &vs->pid,
9006 vs,
9007 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
9008 update_next_challenge_time (vs, now);
9009}
9010
9011
9012static struct Queue *
9013find_queue (const struct GNUNET_PeerIdentity *pid, const char *address);
9014
9015
9016static void
9017suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address);
9018
9019
9020static void
9021hello_for_incoming_cb (void *cls,
9022 const struct GNUNET_PeerIdentity *pid,
9023 const char *uri)
9024{
9025 (void) cls;
9026 struct Queue *q;
9027 int pfx_len;
9028 const char *eou;
9029 char *address;
9030
9031 eou = strstr (uri,
9032 "://");
9033 pfx_len = eou - uri;
9034 eou += 3;
9035 GNUNET_asprintf (&address,
9036 "%.*s-%s",
9037 pfx_len,
9038 uri,
9039 eou);
9040
9041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9042 "helo for client %s\n",
9043 address);
9044 q = find_queue (pid, address);
9045 if (NULL == q)
9046 {
9047 suggest_to_connect (pid, address);
9048 }
9049 else
9050 start_address_validation (pid, address);
9051 GNUNET_free (address);
9052}
9053
9054
9055/**
9056 * Function called by PEERSTORE for each matching record.
9057 *
9058 * @param cls closure, a `struct IncomingRequest`
9059 * @param record peerstore record information
9060 * @param emsg error message, or NULL if no errors
9061 */
9062static void
9063handle_hello_for_incoming (void *cls,
9064 const struct GNUNET_PEERSTORE_Record *record,
9065 const char *emsg)
9066{
9067 struct IncomingRequest *ir = cls;
9068 struct GNUNET_HELLO_Builder *builder;
9069 struct GNUNET_MessageHeader *hello;
9070
9071 if (NULL != emsg)
9072 {
9073 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9074 "Got failure from PEERSTORE: %s\n",
9075 emsg);
9076 return;
9077 }
9078 hello = record->value;
9079 if (0 == GNUNET_memcmp (&record->peer, &GST_my_identity))
9080 {
9081 GNUNET_PEERSTORE_monitor_next (ir->nc, 1);
9082 return;
9083 }
9084 builder = GNUNET_HELLO_builder_from_msg (hello);
9085 GNUNET_HELLO_builder_iterate (builder,
9086 hello_for_incoming_cb,
9087 NULL);
9088 GNUNET_HELLO_builder_free (builder);
9089}
9090
9091
9092static void
9093hello_for_incoming_error_cb (void *cls)
9094{
9095 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9096 "Error in PEERSTORE monitoring\n");
9097}
9098
9099
9100static void
9101hello_for_incoming_sync_cb (void *cls)
9102{
9103 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9104 "Done with initial PEERSTORE iteration during monitoring\n");
9105}
9106
9107
9108/**
9109 * Communicator gave us a transport address validation challenge. Process the
9110 * request.
9111 *
9112 * @param cls a `struct CommunicatorMessageContext` (must call
9113 * #finish_cmc_handling() when done)
9114 * @param tvc the message that was received
9115 */
9116static void
9117handle_validation_challenge (
9118 void *cls,
9119 const struct TransportValidationChallengeMessage *tvc)
9120{
9121 struct CommunicatorMessageContext *cmc = cls;
9122 struct TransportValidationResponseMessage tvr;
9123 struct VirtualLink *vl;
9124 struct GNUNET_TIME_RelativeNBO validity_duration;
9125 struct IncomingRequest *ir;
9126 struct Neighbour *n;
9127 struct GNUNET_PeerIdentity sender;
9128
9129 /* DV-routed messages are not allowed for validation challenges */
9130 if (cmc->total_hops > 0)
9131 {
9132 GNUNET_break_op (0);
9133 finish_cmc_handling (cmc);
9134 return;
9135 }
9136 validity_duration = cmc->im.expected_address_validity;
9137 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9138 "Received address validation challenge %s\n",
9139 GNUNET_sh2s (&tvc->challenge.value));
9140 /* If we have a virtual link, we use this mechanism to signal the
9141 size of the flow control window, and to allow the sender
9142 to ask for increases. If for us the virtual link is still down,
9143 we will always give a window size of zero. */
9144 tvr.header.type =
9145 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
9146 tvr.header.size = htons (sizeof(tvr));
9147 tvr.reserved = htonl (0);
9148 tvr.challenge = tvc->challenge;
9149 tvr.origin_time = tvc->sender_time;
9150 tvr.validity_duration = validity_duration;
9151 {
9152 /* create signature */
9153 struct TransportValidationPS tvp = {
9154 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
9155 .purpose.size = htonl (sizeof(tvp)),
9156 .validity_duration = validity_duration,
9157 .challenge = tvc->challenge
9158 };
9159
9160 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
9161 &tvp,
9162 &tvr.signature);
9163 }
9164 sender = cmc->im.sender;
9165 vl = lookup_virtual_link (&sender);
9166 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9167 {
9168 // route_control_message_without_fc (&cmc->im.sender,
9169 route_control_message_without_fc (vl,
9170 &tvr.header,
9171 RMO_ANYTHING_GOES | RMO_REDUNDANT);
9172 }
9173 else
9174 {
9175 /* Use route via neighbour */
9176 n = lookup_neighbour (&sender);
9177 if (NULL != n)
9178 route_via_neighbour (n, &tvr.header,
9179 RMO_ANYTHING_GOES | RMO_REDUNDANT
9180 | RMO_UNCONFIRMED_ALLOWED);
9181 }
9182
9183 finish_cmc_handling (cmc);
9184 if (NULL != vl)
9185 return;
9186
9187 /* For us, the link is still down, but we need bi-directional
9188 connections (for flow-control and for this to be useful for
9189 CORE), so we must try to bring the link up! */
9190
9191 /* (1) Check existing queues, if any, we may be lucky! */
9192 n = lookup_neighbour (&sender);
9193 if (NULL != n)
9194 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
9195 start_address_validation (&sender, q->address);
9196 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
9197 we could use */
9198 for (ir = ir_head; NULL != ir; ir = ir->next)
9199 if (0 == GNUNET_memcmp (&ir->pid, &sender))
9200 return;
9201 /* we are already trying */
9202 ir = GNUNET_new (struct IncomingRequest);
9203 ir->pid = sender;
9204 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
9205
9206 ir->nc = GNUNET_PEERSTORE_monitor_start (GST_cfg,
9207 GNUNET_YES,
9208 "peerstore",
9209 NULL,
9210 GNUNET_PEERSTORE_HELLO_KEY,
9211 &hello_for_incoming_error_cb,
9212 NULL,
9213 &hello_for_incoming_sync_cb,
9214 NULL,
9215 &handle_hello_for_incoming,
9216 ir);
9217 ir_total++;
9218 /* Bound attempts we do in parallel here, might otherwise get excessive */
9219 while (ir_total > MAX_INCOMING_REQUEST)
9220 free_incoming_request (ir_head);
9221}
9222
9223
9224/**
9225 * Closure for #check_known_challenge.
9226 */
9227struct CheckKnownChallengeContext
9228{
9229 /**
9230 * Set to the challenge we are looking for.
9231 */
9232 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge;
9233
9234 /**
9235 * Set to a matching validation state, if one was found.
9236 */
9237 struct ValidationState *vs;
9238};
9239
9240
9241/**
9242 * Test if the validation state in @a value matches the
9243 * challenge from @a cls.
9244 *
9245 * @param cls a `struct CheckKnownChallengeContext`
9246 * @param pid unused (must match though)
9247 * @param value a `struct ValidationState`
9248 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
9249 */
9250static int
9251check_known_challenge (void *cls,
9252 const struct GNUNET_PeerIdentity *pid,
9253 void *value)
9254{
9255 struct CheckKnownChallengeContext *ckac = cls;
9256 struct ValidationState *vs = value;
9257
9258 (void) pid;
9259 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
9260 return GNUNET_OK;
9261 ckac->vs = vs;
9262 return GNUNET_NO;
9263}
9264
9265
9266/**
9267 * Function called when peerstore is done storing a
9268 * validated address.
9269 *
9270 * @param cls a `struct ValidationState`
9271 * @param success #GNUNET_YES on success
9272 */
9273static void
9274peerstore_store_validation_cb (void *cls, int success)
9275{
9276 struct ValidationState *vs = cls;
9277
9278 vs->sc = NULL;
9279 if (GNUNET_YES == success)
9280 return;
9281 GNUNET_STATISTICS_update (GST_stats,
9282 "# Peerstore failed to store foreign address",
9283 1,
9284 GNUNET_NO);
9285}
9286
9287
9288/**
9289 * Find the queue matching @a pid and @a address.
9290 *
9291 * @param pid peer the queue must go to
9292 * @param address address the queue must use
9293 * @return NULL if no such queue exists
9294 */
9295static struct Queue *
9296find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
9297{
9298 struct Neighbour *n;
9299
9300 n = lookup_neighbour (pid);
9301 if (NULL == n)
9302 return NULL;
9303 for (struct Queue *pos = n->queue_head; NULL != pos;
9304 pos = pos->next_neighbour)
9305 {
9306 if (0 == strcmp (pos->address, address))
9307 return pos;
9308 }
9309 return NULL;
9310}
9311
9312
9313static void
9314validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs);
9315
9316static void
9317revalidation_start_cb (void *cls)
9318{
9319 struct ValidationState *vs = cls;
9320 struct Queue *q;
9321 struct GNUNET_TIME_Absolute now;
9322
9323 vs->revalidation_task = NULL;
9324 q = find_queue (&vs->pid, vs->address);
9325 if (NULL == q)
9326 {
9327 now = GNUNET_TIME_absolute_get ();
9328 vs->awaiting_queue = GNUNET_YES;
9329 suggest_to_connect (&vs->pid, vs->address);
9330 update_next_challenge_time (vs, now);
9331 }
9332 else
9333 validation_transmit_on_queue (q, vs);
9334}
9335
9336
9337static enum GNUNET_GenericReturnValue
9338revalidate_map_it (
9339 void *cls,
9340 const struct GNUNET_HashCode *key,
9341 void *value)
9342{
9343 (void) cls;
9344 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9345 "Key in revalidate map %s \n",
9346 GNUNET_h2s (key));
9347 return GNUNET_YES;
9348}
9349
9350
9351/**
9352 * Communicator gave us a transport address validation response. Process the
9353 * request.
9354 *
9355 * @param cls a `struct CommunicatorMessageContext` (must call
9356 * #finish_cmc_handling() when done)
9357 * @param tvr the message that was received
9358 */
9359static void
9360handle_validation_response (
9361 void *cls,
9362 const struct TransportValidationResponseMessage *tvr)
9363{
9364 struct CommunicatorMessageContext *cmc = cls;
9365 struct ValidationState *vs;
9366 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
9367 .vs = NULL};
9368 struct GNUNET_TIME_Absolute origin_time;
9369 struct Queue *q;
9370 struct Neighbour *n;
9371 struct VirtualLink *vl;
9372 const struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get_monotonic (
9373 GST_cfg);
9374
9375 /* check this is one of our challenges */
9376 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
9377 &cmc->im.sender,
9378 &check_known_challenge,
9379 &ckac);
9380 if (NULL == (vs = ckac.vs))
9381 {
9382 /* This can happen simply if we 'forgot' the challenge by now,
9383 i.e. because we received the validation response twice */
9384 GNUNET_STATISTICS_update (GST_stats,
9385 "# Validations dropped, challenge unknown",
9386 1,
9387 GNUNET_NO);
9388 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9389 "Validation response %s dropped, challenge unknown\n",
9390 GNUNET_sh2s (&tvr->challenge.value));
9391 finish_cmc_handling (cmc);
9392 return;
9393 }
9394
9395 /* sanity check on origin time */
9396 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
9397 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
9398 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
9399 {
9400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9401 "Diff first use %" PRIu64 " and last use %" PRIu64 "\n",
9402 vs->first_challenge_use.abs_value_us - origin_time.abs_value_us,
9403 origin_time.abs_value_us - vs->last_challenge_use.abs_value_us);
9404 GNUNET_break_op (0);
9405 finish_cmc_handling (cmc);
9406 return;
9407 }
9408
9409 {
9410 /* check signature */
9411 struct TransportValidationPS tvp = {
9412 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
9413 .purpose.size = htonl (sizeof(tvp)),
9414 .validity_duration = tvr->validity_duration,
9415 .challenge = tvr->challenge
9416 };
9417
9418 if (
9419 GNUNET_OK !=
9420 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
9421 &tvp,
9422 &tvr->signature,
9423 &cmc->im.sender.public_key))
9424 {
9425 GNUNET_break_op (0);
9426 finish_cmc_handling (cmc);
9427 return;
9428 }
9429 }
9430
9431 /* validity is capped by our willingness to keep track of the
9432 validation entry and the maximum the other peer allows */
9433 vs->valid_until = GNUNET_TIME_relative_to_absolute (
9434 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
9435 tvr->validity_duration),
9436 MAX_ADDRESS_VALID_UNTIL));
9437 vs->validated_until =
9438 GNUNET_TIME_absolute_min (vs->valid_until,
9439 GNUNET_TIME_relative_to_absolute (
9440 ADDRESS_VALIDATION_LIFETIME));
9441 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
9442 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
9443 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9444 &vs->challenge,
9445 sizeof(vs->challenge));
9446 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
9447 vs->validated_until,
9448 GNUNET_TIME_relative_multiply (vs->validation_rtt,
9449 VALIDATION_RTT_BUFFER_FACTOR));
9450 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, <, now))
9451 {
9452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9453 "First challenge use is now %" PRIu64 " %s \n",
9454 vs->first_challenge_use.abs_value_us,
9455 GNUNET_sh2s (&vs->challenge.value));
9456 vs->first_challenge_use = now;
9457 }
9458 else
9459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9460 "First challenge use is later %" PRIu64 " %s \n",
9461 vs->first_challenge_use.abs_value_us,
9462 GNUNET_sh2s (&vs->challenge.value));
9463 vs->last_challenge_use =
9464 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
9465 update_next_challenge_time (vs, vs->first_challenge_use);
9466 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9467 "Validation response %s from %s accepted, address valid until %s\n",
9468 GNUNET_sh2s (&tvr->challenge.value),
9469 GNUNET_i2s (&cmc->im.sender),
9470 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
9471 /*memcpy (&hkey,
9472 &hc,
9473 sizeof (hkey));*/
9474 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9475 "Key %s for address %s map size %u contains %u\n",
9476 GNUNET_h2s (&vs->hc),
9477 vs->address,
9478 GNUNET_CONTAINER_multihashmap_size (revalidation_map),
9479 GNUNET_CONTAINER_multihashmap_contains (revalidation_map,
9480 &vs->hc));
9481 GNUNET_assert (GNUNET_YES ==
9482 GNUNET_CONTAINER_multihashmap_put (
9483 revalidation_map,
9484 &vs->hc,
9485 vs,
9486 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9487 GNUNET_CONTAINER_multihashmap_iterate (revalidation_map,
9488 revalidate_map_it,
9489 NULL);
9490 vs->revalidation_task =
9491 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_subtract (vs->next_challenge,
9492 GNUNET_TIME_UNIT_MINUTES),
9493 &revalidation_start_cb, vs);
9494 vs->sc = GNUNET_PEERSTORE_store (peerstore,
9495 "transport",
9496 &cmc->im.sender,
9497 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
9498 vs->address,
9499 strlen (vs->address) + 1,
9500 vs->valid_until,
9501 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
9502 &peerstore_store_validation_cb,
9503 vs);
9504 finish_cmc_handling (cmc);
9505
9506 /* Finally, we now possibly have a confirmed (!) working queue,
9507 update queue status (if queue still is around) */
9508 q = find_queue (&vs->pid, vs->address);
9509 if (NULL == q)
9510 {
9511 GNUNET_STATISTICS_update (GST_stats,
9512 "# Queues lost at time of successful validation",
9513 1,
9514 GNUNET_NO);
9515 return;
9516 }
9517 q->validated_until = vs->validated_until;
9518 q->pd.aged_rtt = vs->validation_rtt;
9519 n = q->neighbour;
9520 vl = lookup_virtual_link (&vs->pid);
9521 if (NULL == vl)
9522 {
9523 vl = GNUNET_new (struct VirtualLink);
9524 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9525 "Creating new virtual link %p to %s using direct neighbour!\n",
9526 vl,
9527 GNUNET_i2s (&vs->pid));
9528 vl->confirmed = GNUNET_YES;
9529 vl->message_uuid_ctr =
9530 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
9531 vl->target = n->pid;
9532 vl->core_recv_window = RECV_WINDOW_SIZE;
9533 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
9534 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
9535 GNUNET_break (GNUNET_YES ==
9536 GNUNET_CONTAINER_multipeermap_put (
9537 links,
9538 &vl->target,
9539 vl,
9540 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9541 vl->n = n;
9542 n->vl = vl;
9543 q->idle = GNUNET_YES;
9544 vl->visibility_task =
9545 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
9546 consider_sending_fc (vl);
9547 /* We lacked a confirmed connection to the target
9548 before, so tell CORE about it (finally!) */
9549 cores_send_connect_info (&n->pid);
9550 send_msg_from_cache (vl);
9551 }
9552 else
9553 {
9554 /* Link was already up, remember n is also now available and we are done */
9555 if (NULL == vl->n)
9556 {
9557 vl->n = n;
9558 n->vl = vl;
9559 if (GNUNET_YES == vl->confirmed)
9560 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9561 "Virtual link to %s could now also use direct neighbour!\n",
9562 GNUNET_i2s (&vs->pid));
9563 }
9564 else
9565 {
9566 GNUNET_assert (n == vl->n);
9567 }
9568 if (GNUNET_NO == vl->confirmed)
9569 {
9570 vl->confirmed = GNUNET_YES;
9571 q->idle = GNUNET_YES;
9572 vl->visibility_task =
9573 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
9574 consider_sending_fc (vl);
9575 /* We lacked a confirmed connection to the target
9576 before, so tell CORE about it (finally!) */
9577 cores_send_connect_info (&n->pid);
9578 send_msg_from_cache (vl);
9579 }
9580 }
9581}
9582
9583
9584/**
9585 * Incoming meessage. Process the request.
9586 *
9587 * @param im the send message that was received
9588 */
9589static void
9590handle_incoming_msg (void *cls,
9591 const struct GNUNET_TRANSPORT_IncomingMessage *im)
9592{
9593 struct TransportClient *tc = cls;
9594 struct CommunicatorMessageContext *cmc =
9595 GNUNET_new (struct CommunicatorMessageContext);
9596
9597 cmc->tc = tc;
9598 cmc->im = *im;
9599 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9600 "Received message with size %u and flow control id %" PRIu64
9601 " via communicator from peer %s\n",
9602 ntohs (im->header.size),
9603 im->fc_id,
9604 GNUNET_i2s (&im->sender));
9605 cmc->im.neighbour_sender = cmc->im.sender;
9606 cmc->mh = (const struct GNUNET_MessageHeader *) &im[1];
9607 demultiplex_with_cmc (cmc);
9608}
9609
9610/**
9611 * Communicator gave us a transport address validation response. Check the
9612 * request.
9613 *
9614 * @param cls a `struct CommunicatorMessageContext`
9615 * @param fc the message that was received
9616 * @return #GNUNET_YES if message is well-formed
9617 */
9618static int
9619check_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
9620{
9621 (void) cls;
9622 struct TransportGlobalNattedAddress *addresses = (struct TransportGlobalNattedAddress *) &fc[1];
9623 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
9624
9625 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9626 "Flow control header size %u size of addresses %u number of addresses %u size of message struct %u second struct %u\n",
9627 ntohs (fc->header.size),
9628 ntohl (fc->size_of_addresses),
9629 ntohl (fc->number_of_addresses),
9630 sizeof(struct TransportFlowControlMessage),
9631 sizeof (struct TransportGlobalNattedAddress));
9632
9633 if (0 == number_of_addresses || ntohs (fc->header.size) == sizeof(struct TransportFlowControlMessage) + ntohl (fc->number_of_addresses) * sizeof (struct TransportGlobalNattedAddress) + ntohl (fc->size_of_addresses))
9634 return GNUNET_OK;
9635 else
9636 {
9637 GNUNET_break_op (0);
9638 return GNUNET_SYSERR;
9639 }
9640}
9641
9642/**
9643 * Communicator gave us a transport address validation response. Process the
9644 * request.
9645 *
9646 * @param cls a `struct CommunicatorMessageContext` (must call
9647 * #finish_cmc_handling() when done)
9648 * @param fc the message that was received
9649 */
9650static void
9651handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
9652{
9653 struct CommunicatorMessageContext *cmc = cls;
9654 struct VirtualLink *vl;
9655 uint32_t seq;
9656 struct GNUNET_TIME_Absolute st;
9657 uint64_t os;
9658 uint64_t wnd;
9659 uint32_t random;
9660
9661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9662 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
9663 vl = lookup_virtual_link (&cmc->im.sender);
9664 if (NULL == vl)
9665 {
9666 vl = GNUNET_new (struct VirtualLink);
9667 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9668 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
9669 vl,
9670 GNUNET_i2s (&cmc->im.sender));
9671 vl->confirmed = GNUNET_NO;
9672 vl->message_uuid_ctr =
9673 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
9674 vl->target = cmc->im.sender;
9675 vl->core_recv_window = RECV_WINDOW_SIZE;
9676 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
9677 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
9678 GNUNET_break (GNUNET_YES ==
9679 GNUNET_CONTAINER_multipeermap_put (
9680 links,
9681 &vl->target,
9682 vl,
9683 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9684 }
9685 if (0 != ntohl (fc->number_of_addresses))
9686 {
9687 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
9688 const char *tgnas;
9689 unsigned int off = 0;
9690
9691 tgnas = (const char *) &fc[1];
9692
9693 for (int i = 1; i <= number_of_addresses; i++)
9694 {
9695 struct TransportGlobalNattedAddress *tgna = (struct TransportGlobalNattedAddress *) &tgnas[off];
9696 char *addr = (char *) &tgna[1];
9697 unsigned int address_length;
9698
9699 address_length = ntohl (tgna->address_length);
9700 off += sizeof(struct TransportGlobalNattedAddress) + address_length;
9701
9702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9703 "received address %s length %u\n",
9704 addr,
9705 ntohl (tgna->address_length));
9706
9707 GNUNET_NAT_add_global_address (nh, addr, ntohl (tgna->address_length));
9708 }
9709 }
9710 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
9711 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
9712 {
9713 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9714 "FC dropped: Message out of order\n");
9715 /* out of order, drop */
9716 GNUNET_STATISTICS_update (GST_stats,
9717 "# FC dropped: message out of order",
9718 1,
9719 GNUNET_NO);
9720 finish_cmc_handling (cmc);
9721 return;
9722 }
9723 seq = ntohl (fc->seq);
9724 if (seq < vl->last_fc_seq)
9725 {
9726 /* Wrap-around/reset of other peer; start all counters from zero */
9727 vl->outbound_fc_window_size_used = 0;
9728 }
9729 vl->last_fc_seq = seq;
9730 vl->last_fc_timestamp = st;
9731 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
9732 os = GNUNET_ntohll (fc->outbound_sent);
9733 vl->incoming_fc_window_size_loss =
9734 (int64_t) (os - vl->incoming_fc_window_size_used);
9735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9736 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
9737 GNUNET_i2s (&vl->target),
9738 (unsigned int) seq,
9739 (unsigned long long) vl->outbound_fc_window_size,
9740 (long long) vl->incoming_fc_window_size_loss);
9741 wnd = GNUNET_ntohll (fc->outbound_window_size);
9742 random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
9743 UINT32_MAX);
9744 if ((GNUNET_YES == vl->confirmed) && ((wnd < vl->incoming_fc_window_size
9745 + vl->incoming_fc_window_size_used
9746 + vl->incoming_fc_window_size_loss) ||
9747 (vl->last_outbound_window_size_received
9748 != wnd) ||
9749 (0 == random
9750 % FC_NO_CHANGE_REPLY_PROBABILITY)))
9751 {
9752 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9753 "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 %u\n",
9754 (unsigned long long) wnd,
9755 (unsigned long long) vl->incoming_fc_window_size,
9756 (unsigned long long) vl->last_outbound_window_size_received,
9757 random % FC_NO_CHANGE_REPLY_PROBABILITY);
9758 consider_sending_fc (vl);
9759 }
9760 if ((wnd == vl->incoming_fc_window_size
9761 + vl->incoming_fc_window_size_used
9762 + vl->incoming_fc_window_size_loss) &&
9763 (vl->last_outbound_window_size_received == wnd) &&
9764 (NULL != vl->fc_retransmit_task))
9765 {
9766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9767 "Stopping FC retransmission to %s: peer is current at window %llu\n",
9768 GNUNET_i2s (&vl->target),
9769 (unsigned long long) wnd);
9770 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
9771 vl->fc_retransmit_task = NULL;
9772 vl->fc_retransmit_count = 0;
9773 }
9774 vl->last_outbound_window_size_received = wnd;
9775 /* FC window likely increased, check transmission possibilities! */
9776 check_vl_transmission (vl);
9777 finish_cmc_handling (cmc);
9778}
9779
9780
9781/**
9782 * Given an inbound message @a msg from a communicator @a cmc,
9783 * demultiplex it based on the type calling the right handler.
9784 *
9785 * @param cmc context for demultiplexing
9786 * @param msg message to demultiplex
9787 */
9788static void
9789demultiplex_with_cmc (struct CommunicatorMessageContext *cmc)
9790{
9791 struct GNUNET_MQ_MessageHandler handlers[] =
9792 { GNUNET_MQ_hd_var_size (fragment_box,
9793 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
9794 struct TransportFragmentBoxMessage,
9795 cmc),
9796 GNUNET_MQ_hd_var_size (reliability_box,
9797 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
9798 struct TransportReliabilityBoxMessage,
9799 cmc),
9800 GNUNET_MQ_hd_var_size (reliability_ack,
9801 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
9802 struct TransportReliabilityAckMessage,
9803 cmc),
9804 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
9805 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
9806 struct TransportBackchannelEncapsulationMessage,
9807 cmc),
9808 GNUNET_MQ_hd_var_size (dv_learn,
9809 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
9810 struct TransportDVLearnMessage,
9811 cmc),
9812 GNUNET_MQ_hd_var_size (dv_box,
9813 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
9814 struct TransportDVBoxMessage,
9815 cmc),
9816 GNUNET_MQ_hd_var_size (flow_control,
9817 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
9818 struct TransportFlowControlMessage,
9819 cmc),
9820 GNUNET_MQ_hd_fixed_size (
9821 validation_challenge,
9822 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
9823 struct TransportValidationChallengeMessage,
9824 cmc),
9825 GNUNET_MQ_hd_fixed_size (
9826 validation_response,
9827 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
9828 struct TransportValidationResponseMessage,
9829 cmc),
9830 GNUNET_MQ_handler_end () };
9831 int ret;
9832 const struct GNUNET_MessageHeader *msg = cmc->mh;
9833
9834 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9835 "Handling message of type %u with %u bytes\n",
9836 (unsigned int) ntohs (msg->type),
9837 (unsigned int) ntohs (msg->size));
9838 ret = GNUNET_MQ_handle_message (handlers, msg);
9839 if (GNUNET_SYSERR == ret)
9840 {
9841 GNUNET_break (0);
9842 GNUNET_SERVICE_client_drop (cmc->tc->client);
9843 GNUNET_free (cmc);
9844 return;
9845 }
9846 if (GNUNET_NO == ret)
9847 {
9848 /* unencapsulated 'raw' message */
9849 handle_raw_message (cmc, msg);
9850 }
9851}
9852
9853
9854/**
9855 * New queue became available. Check message.
9856 *
9857 * @param cls the client
9858 * @param aqm the send message that was sent
9859 */
9860static int
9861check_add_queue_message (void *cls,
9862 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
9863{
9864 struct TransportClient *tc = cls;
9865
9866 if (CT_COMMUNICATOR != tc->type)
9867 {
9868 GNUNET_break (0);
9869 return GNUNET_SYSERR;
9870 }
9871 GNUNET_MQ_check_zero_termination (aqm);
9872 return GNUNET_OK;
9873}
9874
9875
9876/**
9877 * If necessary, generates the UUID for a @a pm
9878 *
9879 * @param pm pending message to generate UUID for.
9880 */
9881static void
9882set_pending_message_uuid (struct PendingMessage *pm)
9883{
9884 if (pm->msg_uuid_set)
9885 return;
9886 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
9887 pm->msg_uuid_set = GNUNET_YES;
9888}
9889
9890
9891/**
9892 * Setup data structure waiting for acknowledgements.
9893 *
9894 * @param queue queue the @a pm will be sent over
9895 * @param dvh path the message will take, may be NULL
9896 * @param pm the pending message for transmission
9897 * @return corresponding fresh pending acknowledgement
9898 */
9899static struct PendingAcknowledgement *
9900prepare_pending_acknowledgement (struct Queue *queue,
9901 struct DistanceVectorHop *dvh,
9902 struct PendingMessage *pm)
9903{
9904 struct PendingAcknowledgement *pa;
9905
9906 pa = GNUNET_new (struct PendingAcknowledgement);
9907 pa->queue = queue;
9908 pa->dvh = dvh;
9909 pa->pm = pm;
9910 do
9911 {
9912 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9913 &pa->ack_uuid,
9914 sizeof(pa->ack_uuid));
9915 }
9916 while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
9917 pending_acks,
9918 &pa->ack_uuid.value,
9919 pa,
9920 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9921 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
9922 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
9923 if (NULL != dvh)
9924 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
9925 pa->transmission_time = GNUNET_TIME_absolute_get ();
9926 pa->message_size = pm->bytes_msg;
9927 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9928 "Waiting for ACKnowledgment `%s' for <%" PRIu64 ">\n",
9929 GNUNET_uuid2s (&pa->ack_uuid.value),
9930 pm->logging_uuid);
9931 return pa;
9932}
9933
9934
9935/**
9936 * Fragment the given @a pm to the given @a mtu. Adds
9937 * additional fragments to the neighbour as well. If the
9938 * @a mtu is too small, generates and error for the @a pm
9939 * and returns NULL.
9940 *
9941 * @param queue which queue to fragment for
9942 * @param dvh path the message will take, or NULL
9943 * @param pm pending message to fragment for transmission
9944 * @return new message to transmit
9945 */
9946static struct PendingMessage *
9947fragment_message (struct Queue *queue,
9948 struct DistanceVectorHop *dvh,
9949 struct PendingMessage *pm)
9950{
9951 struct PendingAcknowledgement *pa;
9952 struct PendingMessage *ff;
9953 uint16_t mtu;
9954 uint16_t msize;
9955
9956 mtu = (UINT16_MAX == queue->mtu)
9957 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
9958 : queue->mtu;
9959 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9960 "Fragmenting message <%" PRIu64
9961 "> with size %u to %s for MTU %u\n",
9962 pm->logging_uuid,
9963 pm->bytes_msg,
9964 GNUNET_i2s (&pm->vl->target),
9965 (unsigned int) mtu);
9966 set_pending_message_uuid (pm);
9967 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9968 "Fragmenting message %" PRIu64 " <%" PRIu64
9969 "> with size %u to %s for MTU %u\n",
9970 pm->msg_uuid.uuid,
9971 pm->logging_uuid,
9972 pm->bytes_msg,
9973 GNUNET_i2s (&pm->vl->target),
9974 (unsigned int) mtu);
9975
9976 /* This invariant is established in #handle_add_queue_message() */
9977 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
9978
9979 /* select fragment for transmission, descending the tree if it has
9980 been expanded until we are at a leaf or at a fragment that is small
9981 enough
9982 */
9983 ff = pm;
9984 msize = ff->bytes_msg;
9985
9986 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
9987 (ff->frag_off == msize) && (NULL != ff->head_frag))
9988 {
9989 ff = ff->head_frag; /* descent into fragmented fragments */
9990 msize = ff->bytes_msg - sizeof(struct TransportFragmentBoxMessage);
9991 }
9992
9993 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < msize))
9994 {
9995 /* Did not yet calculate all fragments, calculate next fragment */
9996 struct PendingMessage *frag;
9997 struct TransportFragmentBoxMessage tfb;
9998 const char *orig;
9999 char *msg;
10000 uint16_t fragmax;
10001 uint16_t fragsize;
10002 uint16_t msize;
10003 uint16_t xoff = 0;
10004 pm->frag_count++;
10005
10006 orig = (const char *) &ff[1];
10007 msize = ff->bytes_msg;
10008 if (pm != ff)
10009 {
10010 const struct TransportFragmentBoxMessage *tfbo;
10011
10012 tfbo = (const struct TransportFragmentBoxMessage *) orig;
10013 orig += sizeof(struct TransportFragmentBoxMessage);
10014 msize -= sizeof(struct TransportFragmentBoxMessage);
10015 xoff = ntohs (tfbo->frag_off);
10016 }
10017 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
10018 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
10019 frag =
10020 GNUNET_malloc (sizeof(struct PendingMessage)
10021 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
10022 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10023 "3 created pm %p from pm %p storing vl %p from pm %p\n",
10024 frag,
10025 ff,
10026 pm->vl,
10027 pm);
10028 frag->logging_uuid = logging_uuid_gen++;
10029 frag->vl = pm->vl;
10030 frag->frag_parent = ff;
10031 frag->timeout = pm->timeout;
10032 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
10033 frag->pmt = PMT_FRAGMENT_BOX;
10034 msg = (char *) &frag[1];
10035 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
10036 tfb.header.size =
10037 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
10038 pa = prepare_pending_acknowledgement (queue, dvh, frag);
10039 tfb.ack_uuid = pa->ack_uuid;
10040 tfb.msg_uuid = pm->msg_uuid;
10041 tfb.frag_off = htons (ff->frag_off + xoff);
10042 tfb.msg_size = htons (pm->bytes_msg);
10043 memcpy (msg, &tfb, sizeof(tfb));
10044 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
10045 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag,
10046 ff->tail_frag, frag);
10047 ff->frag_off += fragsize;
10048 ff = frag;
10049 }
10050
10051 /* Move head to the tail and return it */
10052 GNUNET_CONTAINER_MDLL_remove (frag,
10053 ff->frag_parent->head_frag,
10054 ff->frag_parent->tail_frag,
10055 ff);
10056 GNUNET_CONTAINER_MDLL_insert_tail (frag,
10057 ff->frag_parent->head_frag,
10058 ff->frag_parent->tail_frag,
10059 ff);
10060
10061 return ff;
10062}
10063
10064
10065/**
10066 * Reliability-box the given @a pm. On error (can there be any), NULL
10067 * may be returned, otherwise the "replacement" for @a pm (which
10068 * should then be added to the respective neighbour's queue instead of
10069 * @a pm). If the @a pm is already fragmented or reliability boxed,
10070 * or itself an ACK, this function simply returns @a pm.
10071 *
10072 * @param queue which queue to prepare transmission for
10073 * @param dvh path the message will take, or NULL
10074 * @param pm pending message to box for transmission over unreliabile queue
10075 * @return new message to transmit
10076 */
10077static struct PendingMessage *
10078reliability_box_message (struct Queue *queue,
10079 struct DistanceVectorHop *dvh,
10080 struct PendingMessage *pm)
10081{
10082 struct TransportReliabilityBoxMessage rbox;
10083 struct PendingAcknowledgement *pa;
10084 struct PendingMessage *bpm;
10085 char *msg;
10086
10087 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
10088 return pm; /* already fragmented or reliability boxed, or control message:
10089 do nothing */
10090 if (NULL != pm->bpm)
10091 return pm->bpm; /* already computed earlier: do nothing */
10092 // TODO I guess we do not need this assertion. We might have a DLL with
10093 // fragments, because the MTU changed, and we do not need to fragment anymore.
10094 // But we should keep the fragments until message was completed, because
10095 // the MTU might change again.
10096 // GNUNET_assert (NULL == pm->head_frag);
10097 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
10098 {
10099 /* failed hard */
10100 GNUNET_break (0);
10101 client_send_response (pm);
10102 return NULL;
10103 }
10104
10105 pa = prepare_pending_acknowledgement (queue, dvh, pm);
10106
10107 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
10108 + pm->bytes_msg);
10109 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10110 "4 created pm %p storing vl %p from pm %p\n",
10111 bpm,
10112 pm->vl,
10113 pm);
10114 bpm->logging_uuid = logging_uuid_gen++;
10115 bpm->vl = pm->vl;
10116 bpm->frag_parent = pm;
10117 // Why was this needed?
10118 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
10119 bpm->timeout = pm->timeout;
10120 bpm->pmt = PMT_RELIABILITY_BOX;
10121 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
10122 set_pending_message_uuid (bpm);
10123 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
10124 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
10125 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
10126
10127 rbox.ack_uuid = pa->ack_uuid;
10128 msg = (char *) &bpm[1];
10129 memcpy (msg, &rbox, sizeof(rbox));
10130 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
10131 pm->bpm = bpm;
10132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10133 "Preparing reliability box for message <%" PRIu64
10134 "> of size %d (%d) to %s on queue %s\n",
10135 pm->logging_uuid,
10136 pm->bytes_msg,
10137 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
10138 GNUNET_i2s (&pm->vl->target),
10139 queue->address);
10140 return bpm;
10141}
10142
10143
10144static void
10145reorder_root_pm (struct PendingMessage *pm,
10146 struct GNUNET_TIME_Absolute next_attempt)
10147{
10148 struct VirtualLink *vl = pm->vl;
10149 struct PendingMessage *pos;
10150
10151 /* re-insert sort in neighbour list */
10152 GNUNET_CONTAINER_MDLL_remove (vl,
10153 vl->pending_msg_head,
10154 vl->pending_msg_tail,
10155 pm);
10156 pos = vl->pending_msg_tail;
10157 while ((NULL != pos) &&
10158 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
10159 pos = pos->prev_vl;
10160 GNUNET_CONTAINER_MDLL_insert_after (vl,
10161 vl->pending_msg_head,
10162 vl->pending_msg_tail,
10163 pos,
10164 pm);
10165}
10166
10167
10168static unsigned int
10169check_next_attempt_tree (struct PendingMessage *pm, struct PendingMessage *root)
10170{
10171 struct PendingMessage *pos;
10172 enum GNUNET_GenericReturnValue frags_in_flight;
10173
10174 pos = pm->head_frag;
10175 while (NULL != pos)
10176 {
10177 if (pos->frags_in_flight_round == pm->frags_in_flight_round ||
10178 GNUNET_NO == check_next_attempt_tree (pos, root))
10179 frags_in_flight = GNUNET_NO;
10180 else
10181 {
10182 frags_in_flight = GNUNET_YES;
10183 break;
10184 }
10185 pos = pos->next_frag;
10186 }
10187
10188 return frags_in_flight;
10189}
10190
10191
10192static void
10193harmonize_flight_round (struct PendingMessage *pm)
10194{
10195 struct PendingMessage *pos;
10196
10197 pos = pm->head_frag;
10198 while (NULL != pos)
10199 {
10200 pos->frags_in_flight_round = pm->frags_in_flight_round;
10201 harmonize_flight_round (pos);
10202 pos = pos->next_frag;
10203 }
10204}
10205
10206
10207/**
10208 * Change the value of the `next_attempt` field of @a pm
10209 * to @a next_attempt and re-order @a pm in the transmission
10210 * list as required by the new timestamp.
10211 *
10212 * @param pm a pending message to update
10213 * @param next_attempt timestamp to use
10214 */
10215static void
10216update_pm_next_attempt (struct PendingMessage *pm,
10217 struct GNUNET_TIME_Absolute next_attempt)
10218{
10219 if (NULL == pm->frag_parent)
10220 {
10221 pm->next_attempt = next_attempt;
10222 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10223 "Next attempt for message <%" PRIu64 "> set to %" PRIu64 "\n",
10224 pm->logging_uuid,
10225 next_attempt.abs_value_us);
10226 reorder_root_pm (pm, next_attempt);
10227 }
10228 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))// || (PMT_FRAGMENT_BOX == pm->pmt))
10229 {
10230 struct PendingMessage *root = pm->frag_parent;
10231
10232 while (NULL != root->frag_parent)
10233 root = root->frag_parent;
10234 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10235 "Next attempt for root message <%" PRIu64 "> set to %s\n",
10236 root->logging_uuid,
10237 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
10238 root->next_attempt = next_attempt;
10239 reorder_root_pm (root, next_attempt);
10240 }
10241 else
10242 {
10243 struct PendingMessage *root = pm->frag_parent;
10244
10245 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
10246 root = root->frag_parent;
10247
10248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10249 "frag_count next atempt %u\n",
10250 root->frag_count);
10251
10252 if (GNUNET_NO == root->frags_in_flight)
10253 {
10254 root->next_attempt = next_attempt;
10255 harmonize_flight_round (root);
10256 root->frags_in_flight_round++;
10257 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10258 "Next attempt for fragmented message <%" PRIu64 "> (<%" PRIu64
10259 ">)set to %" PRIu64 "\n",
10260 pm->logging_uuid,
10261 root->logging_uuid,
10262 next_attempt.abs_value_us);
10263 }
10264
10265 pm->next_attempt = root->next_attempt;
10266 pm->frags_in_flight_round = root->frags_in_flight_round;
10267 harmonize_flight_round (pm);
10268
10269 if (root->bytes_msg == root->frag_off)
10270 root->frags_in_flight = check_next_attempt_tree (root, root);
10271 else
10272 root->frags_in_flight = GNUNET_YES;
10273
10274 if (GNUNET_NO == root->frags_in_flight)
10275 {
10276 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10277 "We have no fragments in flight for message %" PRIu64
10278 ", reorder root! Next attempt is %" PRIu64 "\n",
10279 root->logging_uuid,
10280 root->next_attempt.abs_value_us);
10281 if (PMT_DV_BOX == root->pmt)
10282 root = root->frag_parent;
10283 reorder_root_pm (root, root->next_attempt);
10284 // root->next_attempt = GNUNET_TIME_UNIT_ZERO_ABS;
10285 }
10286 else
10287 {
10288 double factor = ((double) root->frag_count - 1)
10289 / (double) root->frag_count;
10290 struct GNUNET_TIME_Relative s1;
10291 struct GNUNET_TIME_Relative s2;
10292 struct GNUNET_TIME_Relative plus_mean =
10293 GNUNET_TIME_absolute_get_remaining (root->next_attempt);
10294 struct GNUNET_TIME_Relative plus = GNUNET_TIME_absolute_get_remaining (
10295 next_attempt);
10296
10297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10298 "frag_count %u after factor\n",
10299 root->frag_count);
10300 s1 = GNUNET_TIME_relative_multiply_double (plus_mean,
10301 factor);
10302 s2 = GNUNET_TIME_relative_divide (plus,
10303 root->frag_count);
10304 plus_mean = GNUNET_TIME_relative_add (s1, s2);
10305 root->next_attempt = GNUNET_TIME_relative_to_absolute (plus_mean);
10306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10307 "We have fragments in flight for message %" PRIu64
10308 ", do not reorder root! Actual next attempt %" PRIu64 "\n",
10309 root->logging_uuid,
10310 root->next_attempt.abs_value_us);
10311 }
10312 }
10313}
10314
10315
10316/**
10317 * Context for #select_best_pending_from_link().
10318 */
10319struct PendingMessageScoreContext
10320{
10321 /**
10322 * Set to the best message that was found, NULL for none.
10323 */
10324 struct PendingMessage *best;
10325
10326 /**
10327 * DVH that @e best should take, or NULL for direct transmission.
10328 */
10329 struct DistanceVectorHop *dvh;
10330
10331 /**
10332 * What is the estimated total overhead for this message?
10333 */
10334 size_t real_overhead;
10335
10336 /**
10337 * Number of pending messages we seriously considered this time.
10338 */
10339 unsigned int consideration_counter;
10340
10341 /**
10342 * Did we have to fragment?
10343 */
10344 int frag;
10345
10346 /**
10347 * Did we have to reliability box?
10348 */
10349 int relb;
10350
10351 /**
10352 * There are pending messages, but it was to early to send one of them.
10353 */
10354 int to_early;
10355
10356 /**
10357 * There is a pending messages we are sending fragments at the moment.
10358 */
10359 unsigned int frags_in_flight;
10360
10361 /**
10362 * When will we try to transmit the message again for which it was to early to retry.
10363 */
10364 struct GNUNET_TIME_Relative to_early_retry_delay;
10365};
10366
10367
10368/**
10369 * Select the best pending message from @a vl for transmission
10370 * via @a queue.
10371 *
10372 * @param[in,out] sc best message so far (NULL for none), plus scoring data
10373 * @param queue the queue that will be used for transmission
10374 * @param vl the virtual link providing the messages
10375 * @param dvh path we are currently considering, or NULL for none
10376 * @param overhead number of bytes of overhead to be expected
10377 * from DV encapsulation (0 for without DV)
10378 */
10379static void
10380select_best_pending_from_link (struct PendingMessageScoreContext *sc,
10381 struct Queue *queue,
10382 struct VirtualLink *vl,
10383 struct DistanceVectorHop *dvh,
10384 size_t overhead)
10385{
10386 struct GNUNET_TIME_Absolute now;
10387
10388 now = GNUNET_TIME_absolute_get ();
10389 sc->to_early = GNUNET_NO;
10390 sc->frags_in_flight = GNUNET_NO;
10391 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
10392 pos = pos->next_vl)
10393 {
10394 size_t real_overhead = overhead;
10395 int frag;
10396 int relb;
10397
10398 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
10399 {
10400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10401 "DV messages must not be DV-routed to next hop!\n");
10402 continue; /* DV messages must not be DV-routed to next hop! */
10403 }
10404 if (pos->next_attempt.abs_value_us > now.abs_value_us)
10405 {
10406 if (GNUNET_YES == pos->frags_in_flight)
10407 {
10408 sc->frags_in_flight = GNUNET_YES;
10409 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10410 "Fragments in flight for message %" PRIu64 "\n",
10411 pos->logging_uuid);
10412 }
10413 else
10414 {
10415 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10416 "Maybe too early, because message are sorted by next_attempt, if there are no fragments in flight.Checked message %"
10417 PRIu64 "\n",
10418 pos->logging_uuid);
10419 sc->to_early = GNUNET_YES;
10420 sc->to_early_retry_delay = GNUNET_TIME_absolute_get_remaining (
10421 pos->next_attempt);
10422 continue;
10423 }
10424 // break; /* too early for all messages, they are sorted by next_attempt */
10425 }
10426 if (NULL != pos->qe)
10427 {
10428 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10429 "not eligible\n");
10430 continue; /* not eligible */
10431 }
10432 sc->consideration_counter++;
10433 /* determine if we have to fragment, if so add fragmentation
10434 overhead! */
10435 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10436 "check %" PRIu64 " for sc->best\n",
10437 pos->logging_uuid);
10438 frag = GNUNET_NO;
10439 if (((0 != queue->mtu) &&
10440 (pos->bytes_msg + real_overhead > queue->mtu)) ||
10441 (pos->bytes_msg > UINT16_MAX - sizeof(struct
10442 GNUNET_TRANSPORT_SendMessageTo))
10443 ||
10444 (NULL != pos->head_frag /* fragments already exist, should
10445 respect that even if MTU is UINT16_MAX for
10446 this queue */))
10447 {
10448 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10449 "fragment msg with size %u, realoverhead is %lu\n",
10450 pos->bytes_msg,
10451 real_overhead);
10452 frag = GNUNET_YES;
10453 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
10454 {
10455 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
10456 header without the ACK UUID when using a *reliable* channel! */
10457 }
10458 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
10459 }
10460 /* determine if we have to reliability-box, if so add reliability box
10461 overhead */
10462 relb = GNUNET_NO;
10463 if ((GNUNET_NO == frag) &&
10464 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
10465 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
10466 {
10467 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
10468
10469 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
10470 {
10471 frag = GNUNET_YES;
10472 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
10473 }
10474 else
10475 {
10476 relb = GNUNET_YES;
10477 }
10478 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10479 "Create reliability box of msg with size %u, realoverhead is %lu %u %u %u\n",
10480 pos->bytes_msg,
10481 real_overhead,
10482 queue->mtu,
10483 frag,
10484 relb);
10485 }
10486
10487 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
10488 message would beat it! */
10489 if (GNUNET_NO == sc->frags_in_flight && NULL != sc->best)
10490 {
10491 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
10492 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
10493 experimentally validated. There may be some huge potential for
10494 improvement here. Also, we right now only compare how well the
10495 given message fits _this_ queue, and do not consider how well other
10496 queues might suit the message. Taking other queues into consideration
10497 may further improve the result, but could also be expensive
10498 in terms of CPU time. */
10499 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
10500 long long pm_score = frag * 40 + relb * 20 + real_overhead;
10501 long long time_delta =
10502 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
10503 / 1000LL;
10504
10505 /* "time_delta" considers which message has been 'ready' for transmission
10506 for longer, if a message has a preference for low latency, increase
10507 the weight of the time_delta by 10x if it is favorable for that message */
10508 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
10509 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
10510 time_delta *= 10; /* increase weight (always, both are low latency) */
10511 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
10512 (time_delta > 0))
10513 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
10514 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
10515 (time_delta < 0))
10516 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
10517 if (0 != queue->mtu)
10518 {
10519 /* Grant bonus if we are below MTU, larger bonus the closer we will
10520 be to the MTU */
10521 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
10522 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
10523 if (queue->mtu > real_overhead + pos->bytes_msg)
10524 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
10525 }
10526 if (sc_score + time_delta > pm_score)
10527 {
10528 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10529 "sc_score of %" PRIu64 " larger, keep sc->best %" PRIu64
10530 "\n",
10531 pos->logging_uuid,
10532 sc->best->logging_uuid);
10533 continue; /* sc_score larger, keep sc->best */
10534 }
10535 }
10536 sc->best = pos;
10537 sc->dvh = dvh;
10538 sc->frag = frag;
10539 sc->relb = relb;
10540 sc->real_overhead = real_overhead;
10541 }
10542}
10543
10544
10545/**
10546 * Function to call to further operate on the now DV encapsulated
10547 * message @a hdr, forwarding it via @a next_hop under respect of
10548 * @a options.
10549 *
10550 * @param cls a `struct PendingMessageScoreContext`
10551 * @param next_hop next hop of the DV path
10552 * @param hdr encapsulated message, technically a `struct TransportDVBoxMessage`
10553 * @param options options of the original message
10554 */
10555static void
10556extract_box_cb (void *cls,
10557 struct Neighbour *next_hop,
10558 const struct GNUNET_MessageHeader *hdr,
10559 enum RouteMessageOptions options)
10560{
10561 struct PendingMessageScoreContext *sc = cls;
10562 struct PendingMessage *pm = sc->best;
10563 struct PendingMessage *bpm;
10564 uint16_t bsize = ntohs (hdr->size);
10565
10566 GNUNET_assert (NULL == pm->bpm);
10567 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
10568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10569 "5 created pm %p storing vl %p from pm %p\n",
10570 bpm,
10571 pm->vl,
10572 pm);
10573 bpm->logging_uuid = logging_uuid_gen++;
10574 bpm->pmt = PMT_DV_BOX;
10575 bpm->vl = pm->vl;
10576 bpm->timeout = pm->timeout;
10577 bpm->bytes_msg = bsize;
10578 bpm->frag_parent = pm;
10579 set_pending_message_uuid (bpm);
10580 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10581 "Creating DV Box %" PRIu64 " for original message %" PRIu64
10582 " (next hop is %s)\n",
10583 bpm->logging_uuid,
10584 pm->logging_uuid,
10585 GNUNET_i2s (&next_hop->pid));
10586 memcpy (&bpm[1], hdr, bsize);
10587 pm->bpm = bpm;
10588}
10589
10590
10591/**
10592 * We believe we are ready to transmit a `struct PendingMessage` on a
10593 * queue, the big question is which one! We need to see if there is
10594 * one pending that is allowed by flow control and congestion control
10595 * and (ideally) matches our queue's performance profile.
10596 *
10597 * If such a message is found, we give the message to the communicator
10598 * for transmission (updating the tracker, and re-scheduling ourselves
10599 * if applicable).
10600 *
10601 * If no such message is found, the queue's `idle` field must be set
10602 * to #GNUNET_YES.
10603 *
10604 * @param cls the `struct Queue` to process transmissions for
10605 */
10606static void
10607transmit_on_queue (void *cls)
10608{
10609 struct Queue *queue = cls;
10610 struct Neighbour *n = queue->neighbour;
10611 struct PendingMessageScoreContext sc;
10612 struct PendingMessage *pm;
10613
10614 queue->transmit_task = NULL;
10615 if (NULL == n->vl)
10616 {
10617 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10618 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
10619 GNUNET_i2s (&n->pid),
10620 queue->address);
10621 queue->idle = GNUNET_YES;
10622 return;
10623 }
10624 memset (&sc, 0, sizeof(sc));
10625 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
10626 if (NULL == sc.best)
10627 {
10628 /* Also look at DVH that have the n as first hop! */
10629 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
10630 dvh = dvh->next_neighbour)
10631 {
10632 select_best_pending_from_link (&sc,
10633 queue,
10634 dvh->dv->vl,
10635 dvh,
10636 sizeof(struct GNUNET_PeerIdentity)
10637 * (1 + dvh->distance)
10638 + sizeof(struct TransportDVBoxMessage)
10639 + sizeof(struct TransportDVBoxPayloadP));
10640 }
10641 }
10642 if (NULL == sc.best)
10643 {
10644 /* no message pending, nothing to do here! */
10645 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10646 "No pending messages, queue `%s' to %s now idle\n",
10647 queue->address,
10648 GNUNET_i2s (&n->pid));
10649 if (GNUNET_YES == sc.to_early)
10650 schedule_transmit_on_queue (sc.to_early_retry_delay,
10651 queue,
10652 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10653 queue->idle = GNUNET_YES;
10654 return;
10655 }
10656 /* There is a message pending, we are certainly not idle */
10657 queue->idle = GNUNET_NO;
10658
10659 /* Given selection in `sc`, do transmission */
10660 pm = sc.best;
10661 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10662 "Selected message <%" PRIu64 ">\n",
10663 pm->logging_uuid);
10664 if (NULL != sc.dvh)
10665 {
10666 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10667 "Is this %u a DV box?\n",
10668 pm->pmt);
10669 GNUNET_assert (PMT_DV_BOX != pm->pmt);
10670 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
10671 {
10672 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10673 "Discard old box, because we have a new DV path.\n");
10674 free_pending_message (sc.best->bpm);
10675 sc.best->bpm = NULL;
10676 }
10677
10678 if (NULL == sc.best->bpm)
10679 {
10680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10681 "encapsulate_for_dv 2\n");
10682 encapsulate_for_dv (sc.dvh->dv,
10683 1,
10684 &sc.dvh,
10685 (const struct GNUNET_MessageHeader *) &sc.best[1],
10686 &extract_box_cb,
10687 &sc,
10688 RMO_NONE,
10689 GNUNET_NO);
10690 GNUNET_assert (NULL != sc.best->bpm);
10691 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10692 "%lu %lu %lu %lu %u\n",
10693 sizeof(struct GNUNET_PeerIdentity),
10694 sizeof(struct TransportDVBoxMessage),
10695 sizeof(struct TransportDVBoxPayloadP),
10696 sizeof(struct TransportFragmentBoxMessage),
10697 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
10698 sc.best->bpm->used_dvh = sc.dvh;
10699 }
10700 pm = sc.best->bpm;
10701 }
10702 if (GNUNET_YES == sc.frag)
10703 {
10704 pm = fragment_message (queue, sc.dvh, pm);
10705 if (NULL == pm)
10706 {
10707 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10708 "Fragmentation failed queue %s to %s for <%" PRIu64
10709 ">, trying again\n",
10710 queue->address,
10711 GNUNET_i2s (&n->pid),
10712 sc.best->logging_uuid);
10713 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10714 queue,
10715 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10716 return;
10717 }
10718 }
10719 else if (GNUNET_YES == sc.relb)
10720 {
10721 pm = reliability_box_message (queue, sc.dvh, pm);
10722 if (NULL == pm)
10723 {
10724 /* Reliability boxing failed, try next message... */
10725 GNUNET_log (
10726 GNUNET_ERROR_TYPE_DEBUG,
10727 "Reliability boxing failed queue %s to %s for <%" PRIu64
10728 ">, trying again\n",
10729 queue->address,
10730 GNUNET_i2s (&n->pid),
10731 sc.best->logging_uuid);
10732 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10733 queue,
10734 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10735 return;
10736 }
10737 }
10738
10739 /* Pass 'pm' for transission to the communicator */
10740 GNUNET_log (
10741 GNUNET_ERROR_TYPE_DEBUG,
10742 "Passing message <%" PRIu64
10743 "> to queue %s for peer %s (considered %u others)\n",
10744 pm->logging_uuid,
10745 queue->address,
10746 GNUNET_i2s (&n->pid),
10747 sc.consideration_counter);
10748
10749 /* Flow control: increment amount of traffic sent; if we are routing
10750 via DV (and thus the ultimate target of the pending message is for
10751 a different virtual link than the one of the queue), then we need
10752 to use up not only the window of the direct link but also the
10753 flow control window for the DV link! */
10754 pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
10755
10756 if (pm->vl != queue->neighbour->vl)
10757 {
10758 /* If the virtual link of the queue differs, this better be distance
10759 vector routing! */
10760 GNUNET_assert (NULL != sc.dvh);
10761 /* If we do distance vector routing, we better not do this for a
10762 message that was itself DV-routed */
10763 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
10764 /* We use the size of the unboxed message here, to avoid counting
10765 the DV-Box header which is eaten up on the way by intermediaries */
10766 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
10767 }
10768 else
10769 {
10770 GNUNET_assert (NULL == sc.dvh);
10771 }
10772
10773 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
10774
10775 /* Check if this transmission somehow conclusively finished handing 'pm'
10776 even without any explicit ACKs */
10777 if ((PMT_CORE == pm->pmt) ||
10778 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
10779 {
10780 completed_pending_message (pm);
10781 }
10782 else
10783 {
10784 struct GNUNET_TIME_Relative wait_duration;
10785 unsigned int wait_multiplier;
10786
10787 if (PMT_FRAGMENT_BOX == pm->pmt)
10788 {
10789 struct PendingMessage *root;
10790
10791 root = pm->frag_parent;
10792 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
10793 root = root->frag_parent;
10794
10795 wait_multiplier = (unsigned int) ceil ((double) root->bytes_msg
10796 / ((double) root->frag_off
10797 / (double) root->frag_count))
10798 * 4;
10799 }
10800 else
10801 {
10802 // No fragments, we use 4 RTT before retransmitting.
10803 wait_multiplier = 4;
10804 }
10805
10806 // Depending on how much pending message the VirtualLink is queueing, we wait longer.
10807 // wait_multiplier = wait_multiplier * pm->vl->pending_msg_num;
10808
10809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10810 "Wait multiplier %u\n",
10811 wait_multiplier);
10812
10813 /* Message not finished, waiting for acknowledgement.
10814 Update time by which we might retransmit 's' based on queue
10815 characteristics (i.e. RTT); it takes one RTT for the message to
10816 arrive and the ACK to come back in the best case; but the other
10817 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
10818 retransmitting.
10819
10820 OPTIMIZE: Note that in the future this heuristic should likely
10821 be improved further (measure RTT stability, consider message
10822 urgency and size when delaying ACKs, etc.) */
10823
10824 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
10825 queue->pd.aged_rtt.rel_value_us)
10826 wait_duration = queue->pd.aged_rtt;
10827 else
10828 {
10829 wait_duration = DEFAULT_ACK_WAIT_DURATION;
10830 wait_multiplier = 4;
10831 }
10832 struct GNUNET_TIME_Absolute next = GNUNET_TIME_relative_to_absolute (
10833 GNUNET_TIME_relative_multiply (
10834 wait_duration, wait_multiplier));
10835 struct GNUNET_TIME_Relative plus = GNUNET_TIME_relative_multiply (
10836 wait_duration, wait_multiplier);
10837 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10838 "Waiting %s for ACK until %s\n",
10839 GNUNET_STRINGS_relative_time_to_string (plus, GNUNET_NO),
10840 GNUNET_STRINGS_absolute_time_to_string (next));
10841 update_pm_next_attempt (pm,
10842 GNUNET_TIME_relative_to_absolute (
10843 GNUNET_TIME_relative_multiply (wait_duration,
10844 wait_multiplier)));
10845 }
10846 /* finally, re-schedule queue transmission task itself */
10847 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10848 queue,
10849 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10850}
10851
10852
10853/**
10854 * Queue to a peer went down. Process the request.
10855 *
10856 * @param cls the client
10857 * @param dqm the send message that was sent
10858 */
10859static void
10860handle_del_queue_message (void *cls,
10861 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
10862{
10863 struct TransportClient *tc = cls;
10864
10865 if (CT_COMMUNICATOR != tc->type)
10866 {
10867 GNUNET_break (0);
10868 GNUNET_SERVICE_client_drop (tc->client);
10869 return;
10870 }
10871 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
10872 queue = queue->next_client)
10873 {
10874 struct Neighbour *neighbour = queue->neighbour;
10875
10876 if ((ntohl (dqm->qid) != queue->qid) ||
10877 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
10878 continue;
10879 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10880 "Dropped queue %s to peer %s\n",
10881 queue->address,
10882 GNUNET_i2s (&neighbour->pid));
10883 free_queue (queue);
10884 GNUNET_SERVICE_client_continue (tc->client);
10885 return;
10886 }
10887 GNUNET_break (0);
10888 GNUNET_SERVICE_client_drop (tc->client);
10889}
10890
10891
10892static void
10893free_queue_entry (struct QueueEntry *qe,
10894 struct TransportClient *tc)
10895{
10896 struct PendingMessage *pm;
10897
10898 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
10899 qe->queue->queue_tail,
10900 qe);
10901 qe->queue->queue_length--;
10902 tc->details.communicator.total_queue_length--;
10903 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10904 "Received ACK on queue %s (QID %u) to peer %s (new length: %u/%u)\n",
10905 qe->queue->address,
10906 qe->queue->qid,
10907 GNUNET_i2s (&qe->queue->neighbour->pid),
10908 qe->queue->queue_length,
10909 tc->details.communicator.total_queue_length);
10910
10911 /* if applicable, resume transmissions that waited on ACK */
10912 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
10913 tc->details.communicator.total_queue_length)
10914 {
10915 /* Communicator dropped below threshold, resume all queues
10916 incident with this client! */
10917 GNUNET_STATISTICS_update (
10918 GST_stats,
10919 "# Transmission throttled due to communicator queue limit",
10920 -1,
10921 GNUNET_NO);
10922 for (struct Queue *queue = tc->details.communicator.queue_head;
10923 NULL != queue;
10924 queue = queue->next_client)
10925 {
10926 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10927 queue,
10928 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10929 }
10930 }
10931 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
10932 {
10933 /* queue dropped below threshold; only resume this one queue */
10934 GNUNET_STATISTICS_update (GST_stats,
10935 "# Transmission throttled due to queue queue limit",
10936 -1,
10937 GNUNET_NO);
10938 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10939 qe->queue,
10940 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10941 }
10942 else if (1 == qe->queue->q_capacity)
10943 {
10944 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
10945 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10946 "Transmission rescheduled due to communicator message queue with qid %u has capacity %"
10947 PRIu64 ".\n",
10948 qe->queue->qid,
10949 qe->queue->q_capacity);
10950 /* message queue has capacity; only resume this one queue */
10951 /* queue dropped below threshold; only resume this one queue */
10952 GNUNET_STATISTICS_update (GST_stats,
10953 "# Transmission throttled due to message queue capacity",
10954 -1,
10955 GNUNET_NO);
10956 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10957 qe->queue,
10958 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10959 }
10960
10961 if (NULL != (pm = qe->pm))
10962 {
10963 struct VirtualLink *vl;
10964
10965 // GNUNET_assert (qe == pm->qe);
10966 pm->qe = NULL;
10967 /* If waiting for this communicator may have blocked transmission
10968 of pm on other queues for this neighbour, force schedule
10969 transmit on queue for queues of the neighbour */
10970 if (NULL == pm->frag_parent)
10971 {
10972 vl = pm->vl;
10973 if ((NULL != vl) &&
10974 (NULL != vl->pending_msg_head) &&
10975 (vl->pending_msg_head == pm))
10976 check_vl_transmission (vl);
10977 }
10978 }
10979 GNUNET_free (qe);
10980}
10981
10982
10983/**
10984 * Message was transmitted. Process the request.
10985 *
10986 * @param cls the client
10987 * @param sma the send message that was sent
10988 */
10989static void
10990handle_send_message_ack (void *cls,
10991 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
10992{
10993 struct TransportClient *tc = cls;
10994 struct QueueEntry *qe;
10995
10996 if (CT_COMMUNICATOR != tc->type)
10997 {
10998 GNUNET_break (0);
10999 GNUNET_SERVICE_client_drop (tc->client);
11000 return;
11001 }
11002
11003 /* find our queue entry matching the ACK */
11004 qe = NULL;
11005 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11006 "Looking for queue for PID %s\n",
11007 GNUNET_i2s (&sma->receiver));
11008 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
11009 queue = queue->next_client)
11010 {
11011 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
11012 continue;
11013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11014 "Found PID %s\n",
11015 GNUNET_i2s (&queue->neighbour->pid));
11016
11017
11018 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
11019 qep = qep->next)
11020 {
11021 if (qep->mid != GNUNET_ntohll (sma->mid) || queue->qid != ntohl (
11022 sma->qid))
11023 continue;
11024 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11025 "QueueEntry MID: %" PRIu64 " on queue QID: %u, Ack MID: %"
11026 PRIu64 " Ack QID %u\n",
11027 qep->mid,
11028 queue->qid,
11029 GNUNET_ntohll (sma->mid),
11030 ntohl (sma->qid));
11031 qe = qep;
11032 if ((NULL != qe->pm) && (qe->pm->qe != qe))
11033 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11034 "For pending message %" PRIu64 " we had retransmissions.\n",
11035 qe->pm->logging_uuid);
11036 break;
11037 }
11038 }
11039 if (NULL == qe)
11040 {
11041 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11042 "No QueueEntry found for Ack MID %" PRIu64 " QID: %u\n",
11043 GNUNET_ntohll (sma->mid),
11044 ntohl (sma->qid));
11045 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
11046 // Update: Maybe QueueEntry was accidentally freed during freeing PendingMessage.
11047 /* this should never happen */
11048 // GNUNET_break (0);
11049 // GNUNET_SERVICE_client_drop (tc->client);
11050 GNUNET_SERVICE_client_continue (tc->client);
11051 return;
11052 }
11053 free_queue_entry (qe, tc);
11054 GNUNET_SERVICE_client_continue (tc->client);
11055}
11056
11057
11058/**
11059 * Iterator telling new MONITOR client about all existing
11060 * queues to peers.
11061 *
11062 * @param cls the new `struct TransportClient`
11063 * @param pid a connected peer
11064 * @param value the `struct Neighbour` with more information
11065 * @return #GNUNET_OK (continue to iterate)
11066 */
11067static int
11068notify_client_queues (void *cls,
11069 const struct GNUNET_PeerIdentity *pid,
11070 void *value)
11071{
11072 struct TransportClient *tc = cls;
11073 struct Neighbour *neighbour = value;
11074
11075 GNUNET_assert (CT_MONITOR == tc->type);
11076 for (struct Queue *q = neighbour->queue_head; NULL != q;
11077 q = q->next_neighbour)
11078 {
11079 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
11080 .cs = q->cs,
11081 .num_msg_pending = q->num_msg_pending,
11082 .num_bytes_pending = q->num_bytes_pending };
11083
11084 notify_monitor (tc, pid, q->address, q->nt, &me);
11085 }
11086 return GNUNET_OK;
11087}
11088
11089
11090/**
11091 * Initialize a monitor client.
11092 *
11093 * @param cls the client
11094 * @param start the start message that was sent
11095 */
11096static void
11097handle_monitor_start (void *cls,
11098 const struct GNUNET_TRANSPORT_MonitorStart *start)
11099{
11100 struct TransportClient *tc = cls;
11101
11102 if (CT_NONE != tc->type)
11103 {
11104 GNUNET_break (0);
11105 GNUNET_SERVICE_client_drop (tc->client);
11106 return;
11107 }
11108 tc->type = CT_MONITOR;
11109 tc->details.monitor.peer = start->peer;
11110 tc->details.monitor.one_shot = ntohl (start->one_shot);
11111 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &notify_client_queues, tc);
11112 GNUNET_SERVICE_client_mark_monitor (tc->client);
11113 GNUNET_SERVICE_client_continue (tc->client);
11114}
11115
11116
11117/**
11118 * Find transport client providing communication service
11119 * for the protocol @a prefix.
11120 *
11121 * @param prefix communicator name
11122 * @return NULL if no such transport client is available
11123 */
11124static struct TransportClient *
11125lookup_communicator (const char *prefix)
11126{
11127 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
11128 {
11129 if (CT_COMMUNICATOR != tc->type)
11130 continue;
11131 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
11132 return tc;
11133 }
11134 GNUNET_log (
11135 GNUNET_ERROR_TYPE_WARNING,
11136 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
11137 prefix);
11138 return NULL;
11139}
11140
11141
11142/**
11143 * Signature of a function called with a communicator @a address of a peer
11144 * @a pid that an application wants us to connect to.
11145 *
11146 * @param pid target peer
11147 * @param address the address to try
11148 */
11149static void
11150suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
11151{
11152 static uint32_t idgen;
11153 struct TransportClient *tc;
11154 char *prefix;
11155 struct GNUNET_TRANSPORT_CreateQueue *cqm;
11156 struct GNUNET_MQ_Envelope *env;
11157 size_t alen;
11158
11159 prefix = GNUNET_HELLO_address_to_prefix (address);
11160 if (NULL == prefix)
11161 {
11162 GNUNET_break (0); /* We got an invalid address!? */
11163 return;
11164 }
11165 tc = lookup_communicator (prefix);
11166 if (NULL == tc)
11167 {
11168 GNUNET_STATISTICS_update (GST_stats,
11169 "# Suggestions ignored due to missing communicator",
11170 1,
11171 GNUNET_NO);
11172 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
11173 "Cannot connect to %s at `%s', no matching communicator present\n",
11174 GNUNET_i2s (pid),
11175 address);
11176 GNUNET_free (prefix);
11177 return;
11178 }
11179 /* forward suggestion for queue creation to communicator */
11180 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11181 "Request #%u for `%s' communicator to create queue to `%s' at `%s'\n",
11182 (unsigned int) idgen,
11183 prefix,
11184 GNUNET_i2s (pid),
11185 address);
11186 GNUNET_free (prefix);
11187 alen = strlen (address) + 1;
11188 env =
11189 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
11190 cqm->request_id = htonl (idgen++);
11191 cqm->receiver = *pid;
11192 memcpy (&cqm[1], address, alen);
11193 GNUNET_MQ_send (tc->mq, env);
11194}
11195
11196
11197/**
11198 * The queue @a q (which matches the peer and address in @a vs) is
11199 * ready for queueing. We should now queue the validation request.
11200 *
11201 * @param q queue to send on
11202 * @param vs state to derive validation challenge from
11203 */
11204static void
11205validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
11206{
11207 struct TransportValidationChallengeMessage tvc;
11208 struct GNUNET_TIME_Absolute monotonic_time;
11209
11210 if (NULL != vs->revalidation_task)
11211 {
11212 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
11213 vs->revalidation_task = NULL;
11214 }
11215 /*memcpy (&hkey,
11216 &hc,
11217 sizeof (hkey));*/
11218 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11219 "Remove key %s for address %s map size %u contains %u\n",
11220 GNUNET_h2s (&vs->hc),
11221 vs->address,
11222 GNUNET_CONTAINER_multihashmap_size (revalidation_map),
11223 GNUNET_CONTAINER_multihashmap_contains (revalidation_map,
11224 &vs->hc));
11225 GNUNET_CONTAINER_multihashmap_remove (revalidation_map, &vs->hc, vs);
11226
11227 monotonic_time = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
11228 if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us ==
11229 vs->last_challenge_use.abs_value_us)
11230 {
11231 vs->first_challenge_use = monotonic_time;
11232 }
11233 vs->last_challenge_use = monotonic_time;
11234 tvc.header.type =
11235 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
11236 tvc.header.size = htons (sizeof(tvc));
11237 tvc.reserved = htonl (0);
11238 tvc.challenge = vs->challenge;
11239 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
11240 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
11241 "Sending address validation challenge %s to %s\n",
11242 GNUNET_sh2s (&tvc.challenge.value),
11243 GNUNET_i2s (&q->neighbour->pid));
11244 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
11245}
11246
11247
11248/**
11249 * Task run periodically to validate some address based on #validation_heap.
11250 *
11251 * @param cls NULL
11252 */
11253static void
11254validation_start_cb (void *cls)
11255{
11256 struct ValidationState *vs;
11257 struct Queue *q;
11258 const struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get_monotonic (
11259 GST_cfg);
11260
11261 (void) cls;
11262 validation_task = NULL;
11263 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
11264 /* drop validations past their expiration */
11265 while (
11266 (NULL != vs) &&
11267 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
11268 {
11269 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11270 "Validation response %s cleaned up\n",
11271 GNUNET_sh2s (&vs->challenge.value));
11272 free_validation_state (vs);
11273 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
11274 }
11275 if (NULL == vs)
11276 {
11277 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
11278 "Address validation task not scheduled anymore, nothing to do\n");
11279 return; /* woopsie, no more addresses known, should only
11280 happen if we're really a lonely peer */
11281 }
11282 q = find_queue (&vs->pid, vs->address);
11283 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
11284 {
11285 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11286 "To early to start next address validation for challenge %s\n",
11287 GNUNET_sh2s (&vs->challenge.value));
11288 return;
11289 }
11290 if (NULL == q)
11291 {
11292 vs->awaiting_queue = GNUNET_YES;
11293 suggest_to_connect (&vs->pid, vs->address);
11294 }
11295 else
11296 validation_transmit_on_queue (q, vs);
11297 /* Finally, reschedule next attempt */
11298 vs->challenge_backoff =
11299 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
11300 MAX_VALIDATION_CHALLENGE_FREQ);
11301 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11302 "Address validation task will run again in %s\n",
11303 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
11304 GNUNET_YES));
11305 update_next_challenge_time (vs,
11306 GNUNET_TIME_relative_to_absolute (
11307 vs->challenge_backoff));
11308}
11309
11310
11311/**
11312 * Closure for #check_connection_quality.
11313 */
11314struct QueueQualityContext
11315{
11316 /**
11317 * Set to the @e k'th queue encountered.
11318 */
11319 struct Queue *q;
11320
11321 /**
11322 * Set to the number of quality queues encountered.
11323 */
11324 unsigned int quality_count;
11325
11326 /**
11327 * Set to the total number of queues encountered.
11328 */
11329 unsigned int num_queues;
11330
11331 /**
11332 * Decremented for each queue, for selection of the
11333 * k-th queue in @e q.
11334 */
11335 unsigned int k;
11336};
11337
11338
11339/**
11340 * Check whether any queue to the given neighbour is
11341 * of a good "quality" and if so, increment the counter.
11342 * Also counts the total number of queues, and returns
11343 * the k-th queue found.
11344 *
11345 * @param cls a `struct QueueQualityContext *` with counters
11346 * @param pid peer this is about
11347 * @param value a `struct Neighbour`
11348 * @return #GNUNET_OK (continue to iterate)
11349 */
11350static int
11351check_connection_quality (void *cls,
11352 const struct GNUNET_PeerIdentity *pid,
11353 void *value)
11354{
11355 struct QueueQualityContext *ctx = cls;
11356 struct Neighbour *n = value;
11357 int do_inc;
11358
11359 (void) pid;
11360 do_inc = GNUNET_NO;
11361 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
11362 {
11363 ctx->num_queues++;
11364 if (0 == ctx->k--)
11365 ctx->q = q;
11366 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
11367 statistics and consider those as well here? */
11368 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
11369 do_inc = GNUNET_YES;
11370 }
11371 if (GNUNET_YES == do_inc)
11372 ctx->quality_count++;
11373 return GNUNET_OK;
11374}
11375
11376
11377/**
11378 * Task run when we CONSIDER initiating a DV learn
11379 * process. We first check that sending out a message is
11380 * even possible (queues exist), then that it is desirable
11381 * (if not, reschedule the task for later), and finally
11382 * we may then begin the job. If there are too many
11383 * entries in the #dvlearn_map, we purge the oldest entry
11384 * using #lle_tail.
11385 *
11386 * @param cls NULL
11387 */
11388static void
11389start_dv_learn (void *cls)
11390{
11391 struct LearnLaunchEntry *lle;
11392 struct QueueQualityContext qqc;
11393 struct TransportDVLearnMessage dvl;
11394
11395 (void) cls;
11396 dvlearn_task = NULL;
11397 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
11398 return; /* lost all connectivity, cannot do learning */
11399 qqc.quality_count = 0;
11400 qqc.num_queues = 0;
11401 qqc.k = GNUNET_CONTAINER_multipeermap_size (neighbours);
11402 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
11403 &check_connection_quality,
11404 &qqc);
11405 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
11406 {
11407 struct GNUNET_TIME_Relative delay;
11408 unsigned int factor;
11409
11410 /* scale our retries by how far we are above the threshold */
11411 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
11412 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
11413 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11414 "At connection quality %u, will launch DV learn in %s\n",
11415 qqc.quality_count,
11416 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
11417 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
11418 return;
11419 }
11420 /* remove old entries in #dvlearn_map if it has grown too big */
11421 while (MAX_DV_LEARN_PENDING <=
11422 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
11423 {
11424 lle = lle_tail;
11425 GNUNET_assert (GNUNET_YES ==
11426 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
11427 &lle->challenge.value,
11428 lle));
11429 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
11430 GNUNET_free (lle);
11431 }
11432 /* setup data structure for learning */
11433 lle = GNUNET_new (struct LearnLaunchEntry);
11434 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
11435 &lle->challenge,
11436 sizeof(lle->challenge));
11437 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11438 "Starting launch DV learn with challenge %s\n",
11439 GNUNET_sh2s (&lle->challenge.value));
11440 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
11441 GNUNET_break (GNUNET_YES ==
11442 GNUNET_CONTAINER_multishortmap_put (
11443 dvlearn_map,
11444 &lle->challenge.value,
11445 lle,
11446 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
11447 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
11448 dvl.header.size = htons (sizeof(dvl));
11449 dvl.num_hops = htons (0);
11450 dvl.bidirectional = htons (0);
11451 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
11452 dvl.monotonic_time =
11453 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
11454 {
11455 struct DvInitPS dvip = {
11456 .purpose.purpose = htonl (
11457 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
11458 .purpose.size = htonl (sizeof(dvip)),
11459 .monotonic_time = dvl.monotonic_time,
11460 .challenge = lle->challenge
11461 };
11462
11463 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
11464 &dvip,
11465 &dvl.init_sig);
11466 }
11467 dvl.initiator = GST_my_identity;
11468 dvl.challenge = lle->challenge;
11469
11470 qqc.quality_count = 0;
11471 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
11472 qqc.num_queues = 0;
11473 qqc.q = NULL;
11474 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
11475 &check_connection_quality,
11476 &qqc);
11477 GNUNET_assert (NULL != qqc.q);
11478
11479 /* Do this as close to transmission time as possible! */
11480 lle->launch_time = GNUNET_TIME_absolute_get ();
11481
11482 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
11483 /* reschedule this job, randomizing the time it runs (but no
11484 actual backoff!) */
11485 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
11486 DV_LEARN_BASE_FREQUENCY),
11487 &start_dv_learn,
11488 NULL);
11489}
11490
11491
11492/**
11493 * Get the IP address without the port number.
11494 *
11495 * @param address The string contains a communicator prefix, IP address and port
11496 * like this 'tcp-92.68.150.1:55452'.
11497 * @return String with IP address only.
11498 */
11499static char *
11500get_address_without_port (const char *address)
11501{
11502 const char *colon;
11503 char *colon_rest;
11504 size_t colon_rest_length;
11505 char *address_without_port;
11506
11507 colon = strchr (address,':');
11508 colon_rest = GNUNET_strndup (address, colon - address);
11509 colon_rest_length = strlen (colon_rest);
11510 address_without_port = GNUNET_strndup (&colon_rest[4], colon_rest_length - 4);
11511 GNUNET_free (colon_rest);
11512
11513 return address_without_port;
11514}
11515
11516
11517/**
11518 * A new queue has been created, check if any address validation
11519 * requests have been waiting for it.
11520 *
11521 * @param cls a `struct Queue`
11522 * @param pid peer concerned (unused)
11523 * @param value a `struct ValidationState`
11524 * @return #GNUNET_NO if a match was found and we can stop looking
11525 */
11526static int
11527check_validation_request_pending (void *cls,
11528 const struct GNUNET_PeerIdentity *pid,
11529 void *value)
11530{
11531 struct Queue *q = cls;
11532 struct ValidationState *vs = value;
11533 char *address_without_port_vs;
11534 char *address_without_port_q;
11535 int success = GNUNET_YES;
11536
11537 //TODO Check if this is really necessary.
11538 address_without_port_vs = get_address_without_port (vs->address);
11539 address_without_port_q = get_address_without_port (q->address);
11540
11541 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11542 "Check validation request pending for `%s' at `%s'/`%s' (vs)/(q)\n",
11543 GNUNET_i2s (pid),
11544 address_without_port_vs,
11545 address_without_port_q);
11546 (void) pid;
11547 if ((GNUNET_YES == vs->awaiting_queue) &&
11548 (0 == strcmp (address_without_port_vs, address_without_port_q)))
11549 {
11550
11551 vs->awaiting_queue = GNUNET_NO;
11552 validation_transmit_on_queue (q, vs);
11553 success = GNUNET_NO;
11554 }
11555
11556 GNUNET_free (address_without_port_vs);
11557 GNUNET_free (address_without_port_q);
11558 return success;
11559}
11560
11561
11562/**
11563 * Function called with the monotonic time of a DV initiator
11564 * by PEERSTORE. Updates the time.
11565 *
11566 * @param cls a `struct Neighbour`
11567 * @param record the information found, NULL for the last call
11568 * @param emsg error message
11569 */
11570static void
11571neighbour_dv_monotime_cb (void *cls,
11572 const struct GNUNET_PEERSTORE_Record *record,
11573 const char *emsg)
11574{
11575 struct Neighbour *n = cls;
11576 struct GNUNET_TIME_AbsoluteNBO *mtbe;
11577
11578 (void) emsg;
11579 if (NULL == record)
11580 {
11581 /* we're done with #neighbour_dv_monotime_cb() invocations,
11582 continue normal processing */
11583 n->get = NULL;
11584 n->dv_monotime_available = GNUNET_YES;
11585 return;
11586 }
11587 if (0 == record->value_size)
11588 {
11589 GNUNET_PEERSTORE_iteration_next (n->get, 1);
11590 GNUNET_break (0);
11591 return;
11592 }
11593 mtbe = record->value;
11594 n->last_dv_learn_monotime =
11595 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
11596 GNUNET_TIME_absolute_ntoh (*mtbe));
11597 GNUNET_PEERSTORE_iteration_next (n->get, 1);
11598}
11599
11600
11601static void
11602iterate_address_and_compare_cb (void *cls,
11603 const struct GNUNET_PeerIdentity *pid,
11604 const char *uri)
11605{
11606 struct Queue *queue = cls;
11607 struct Neighbour *neighbour = queue->neighbour;
11608 const char *dash;
11609 const char *slash;
11610 char *address_uri;
11611 char *prefix;
11612 char *uri_without_port;
11613 char *address_uri_without_port;
11614
11615 slash = strrchr (uri, '/');
11616 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
11617 GNUNET_assert (NULL != slash);
11618 slash++;
11619 GNUNET_asprintf (&address_uri,
11620 "%s-%s",
11621 prefix,
11622 slash);
11623
11624 address_uri_without_port = get_address_without_port (queue->address);
11625 uri_without_port = get_address_without_port (address_uri);
11626 if (0 == strcmp (uri_without_port, address_uri_without_port))
11627 {
11628 queue->is_global_natted = GNUNET_NO;
11629 }
11630
11631 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11632 "not global natted %u %s %s %s %s %s %u\n",
11633 queue->is_global_natted,
11634 uri,
11635 queue->address,
11636 uri_without_port,
11637 address_uri_without_port,
11638 prefix,
11639 GNUNET_NO);
11640 GNUNET_free (prefix);
11641 GNUNET_free (address_uri);
11642 GNUNET_free (address_uri_without_port);
11643 GNUNET_free (uri_without_port);
11644}
11645
11646
11647static void
11648check_for_global_natted_error_cb (void *cls)
11649{
11650 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
11651 "Error in PEERSTORE monitoring for checking global natted\n");
11652}
11653
11654
11655static void
11656check_for_global_natted_sync_cb (void *cls)
11657{
11658 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
11659 "Done with initial PEERSTORE iteration during monitoring for checking global natted\n");
11660}
11661
11662
11663struct TransportGlobalNattedAddressClosure
11664{
11665 /**
11666 * The address to search for.
11667 */
11668 char *addr;
11669
11670 /**
11671 * The struct TransportGlobalNattedAddress to set.
11672 */
11673 struct TransportGlobalNattedAddress *tgna;
11674};
11675
11676
11677static enum GNUNET_GenericReturnValue
11678contains_address (void *cls,
11679 const struct GNUNET_PeerIdentity *pid,
11680 void *value)
11681{
11682 struct TransportGlobalNattedAddressClosure *tgna_cls = cls;
11683 struct TransportGlobalNattedAddress *tgna = value;
11684 char *addr = (char *) &tgna[1];
11685
11686 if (strlen(tgna_cls->addr) == ntohl (tgna->address_length)
11687 && 0 == strncmp (addr, tgna_cls->addr, ntohl (tgna->address_length)))
11688 {
11689 tgna_cls->tgna = tgna;
11690 return GNUNET_NO;
11691 }
11692 return GNUNET_YES;
11693}
11694
11695
11696static void
11697check_for_global_natted (void *cls,
11698 const struct GNUNET_PEERSTORE_Record *record,
11699 const char *emsg)
11700{
11701 struct Queue *queue = cls;
11702 struct Neighbour *neighbour = queue->neighbour;
11703 struct GNUNET_HELLO_Builder *builder;
11704 struct GNUNET_MessageHeader *hello;
11705 struct TransportGlobalNattedAddressClosure tgna_cls;
11706 size_t address_len_without_port;
11707
11708 if (NULL != emsg)
11709 {
11710 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
11711 "Got failure from PEERSTORE: %s\n",
11712 emsg);
11713 return;
11714 }
11715 if (NULL == record)
11716 {
11717 queue->mo = NULL;
11718 return;
11719 }
11720 if (0 == record->value_size)
11721 {
11722 GNUNET_PEERSTORE_monitor_next (queue->mo, 1);
11723 GNUNET_break (0);
11724 return;
11725 }
11726 queue->is_global_natted = GNUNET_YES;
11727 hello = record->value;
11728 builder = GNUNET_HELLO_builder_from_msg (hello);
11729 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11730 "before not global natted %u\n",
11731 queue->is_global_natted);
11732 GNUNET_HELLO_builder_iterate (builder,
11733 &iterate_address_and_compare_cb,
11734 queue);
11735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11736 "after not global natted %u\n",
11737 queue->is_global_natted);
11738 GNUNET_HELLO_builder_free (builder);
11739
11740 tgna_cls.addr = get_address_without_port (queue->address);
11741 tgna_cls.tgna = NULL;
11742 address_len_without_port = strlen (tgna_cls.addr);
11743 GNUNET_CONTAINER_multipeermap_get_multiple (neighbour->natted_addresses,
11744 &neighbour->pid,
11745 &contains_address,
11746 &tgna_cls);
11747 if (NULL != tgna_cls.tgna)
11748 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11749 " tgna_cls.tgna tgna %p %u %u %u\n",
11750 tgna_cls.tgna,
11751 neighbour->size_of_global_addresses,
11752 ntohl (tgna_cls.tgna->address_length),
11753 neighbour->number_of_addresses);
11754 if (NULL == tgna_cls.tgna && GNUNET_YES == queue->is_global_natted)
11755 {
11756 struct TransportGlobalNattedAddress *tgna;
11757
11758 tgna = GNUNET_malloc (sizeof (struct TransportGlobalNattedAddress) + address_len_without_port);
11759 tgna->address_length = htonl (address_len_without_port);
11760 GNUNET_memcpy (&tgna[1], tgna_cls.addr, address_len_without_port);
11761 GNUNET_CONTAINER_multipeermap_put (neighbour->natted_addresses,
11762 &neighbour->pid,
11763 tgna,
11764 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
11765 neighbour->number_of_addresses++;
11766 neighbour->size_of_global_addresses += address_len_without_port;
11767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11768 "Created tgna %p\n",
11769 tgna);
11770 }
11771 else if (NULL != tgna_cls.tgna && GNUNET_NO == queue->is_global_natted)
11772 {
11773 GNUNET_CONTAINER_multipeermap_remove (neighbour->natted_addresses,
11774 &neighbour->pid,
11775 tgna_cls.tgna);
11776 GNUNET_assert (neighbour->size_of_global_addresses >= ntohl (tgna_cls.tgna->address_length));
11777 neighbour->size_of_global_addresses -= ntohl (tgna_cls.tgna->address_length);
11778 GNUNET_assert (0 < neighbour->number_of_addresses);
11779 neighbour->number_of_addresses--;
11780 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11781 "removed tgna %p\n",
11782 tgna_cls.tgna);
11783 GNUNET_free (tgna_cls.tgna);
11784 }
11785 GNUNET_free (tgna_cls.addr);
11786 GNUNET_PEERSTORE_monitor_next (queue->mo, 1);
11787}
11788
11789
11790/**
11791 * New queue became available. Process the request.
11792 *
11793 * @param cls the client
11794 * @param aqm the send message that was sent
11795 */
11796static void
11797handle_add_queue_message (void *cls,
11798 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
11799{
11800 struct TransportClient *tc = cls;
11801 struct Queue *queue;
11802 struct Neighbour *neighbour;
11803 struct GNUNET_TIME_Absolute validated_until = GNUNET_TIME_UNIT_ZERO_ABS;
11804 const char *addr;
11805 uint16_t addr_len;
11806
11807 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
11808 {
11809 /* MTU so small as to be useless for transmissions,
11810 required for #fragment_message()! */
11811 GNUNET_break_op (0);
11812 GNUNET_SERVICE_client_drop (tc->client);
11813 return;
11814 }
11815 /* This may simply be a queue update */
11816 for (queue = tc->details.communicator.queue_head;
11817 NULL != queue;
11818 queue = queue->next_client)
11819 {
11820 validated_until = queue->validated_until;
11821 if (queue->qid != ntohl (aqm->qid))
11822 continue;
11823 break;
11824 }
11825
11826 if (NULL != queue)
11827 {
11828 neighbour = queue->neighbour;
11829 }
11830 else
11831 {
11832 neighbour = lookup_neighbour (&aqm->receiver);
11833 if (NULL == neighbour)
11834 {
11835 neighbour = GNUNET_new (struct Neighbour);
11836 neighbour->natted_addresses = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
11837 neighbour->pid = aqm->receiver;
11838 GNUNET_assert (GNUNET_OK ==
11839 GNUNET_CONTAINER_multipeermap_put (
11840 neighbours,
11841 &neighbour->pid,
11842 neighbour,
11843 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
11844 neighbour->get =
11845 GNUNET_PEERSTORE_iteration_start (peerstore,
11846 "transport",
11847 &neighbour->pid,
11848 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
11849 &neighbour_dv_monotime_cb,
11850 neighbour);
11851 }
11852 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
11853 addr = (const char *) &aqm[1];
11854 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11855 "New queue %s to %s available with QID %u and q_len %" PRIu64
11856 " and mtu %u\n",
11857 addr,
11858 GNUNET_i2s (&aqm->receiver),
11859 ntohl (aqm->qid),
11860 GNUNET_ntohll (aqm->q_len),
11861 ntohl (aqm->mtu));
11862 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
11863 queue->tc = tc;
11864 if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us != validated_until.abs_value_us)
11865 {
11866 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11867 "New queue with QID %u inherit validated until\n",
11868 ntohl (aqm->qid));
11869 queue->validated_until = validated_until;
11870 }
11871 queue->address = (const char *) &queue[1];
11872 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
11873 queue->qid = ntohl (aqm->qid);
11874 queue->neighbour = neighbour;
11875 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (aqm->q_len))
11876 queue->unlimited_length = GNUNET_YES;
11877 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
11878 memcpy (&queue[1], addr, addr_len);
11879 /* notify monitors about new queue */
11880 {
11881 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
11882
11883 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
11884 }
11885 GNUNET_CONTAINER_MDLL_insert (neighbour,
11886 neighbour->queue_head,
11887 neighbour->queue_tail,
11888 queue);
11889 GNUNET_CONTAINER_MDLL_insert (client,
11890 tc->details.communicator.queue_head,
11891 tc->details.communicator.queue_tail,
11892 queue);
11893
11894 }
11895 queue->mtu = ntohl (aqm->mtu);
11896 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
11897 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
11898 queue->idle = GNUNET_YES;
11899 queue->mo = GNUNET_PEERSTORE_monitor_start (GST_cfg,
11900 GNUNET_YES,
11901 "peerstore",
11902 &neighbour->pid,
11903 GNUNET_PEERSTORE_HELLO_KEY,
11904 &check_for_global_natted_error_cb,
11905 NULL,
11906 &check_for_global_natted_sync_cb,
11907 NULL,
11908 &check_for_global_natted,
11909 queue);
11910 /* check if valdiations are waiting for the queue */
11911 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (validation_map,
11912 &aqm->receiver))
11913 {
11914 if (GNUNET_SYSERR != GNUNET_CONTAINER_multipeermap_get_multiple (
11915 validation_map,
11916 &aqm->
11917 receiver,
11918 &
11919 check_validation_request_pending,
11920 queue))
11921 start_address_validation (&aqm->receiver, queue->address);
11922 }
11923 else
11924 start_address_validation (&aqm->receiver, queue->address);
11925 /* look for traffic for this queue */
11926 // TODO Check whether this makes any sense at all.
11927 /*schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
11928 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);*/
11929 /* might be our first queue, try launching DV learning */
11930 if (NULL == dvlearn_task)
11931 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
11932 GNUNET_SERVICE_client_continue (tc->client);
11933}
11934
11935
11936/**
11937 * @brief Handle updates to queues.
11938 *
11939 * @param cls the transport client.
11940 * @param msg Message struct.
11941 */
11942static void
11943handle_update_queue_message (void *cls,
11944 const struct
11945 GNUNET_TRANSPORT_UpdateQueueMessage *msg)
11946{
11947 struct TransportClient *tc = cls;
11948 struct Queue *target_queue = NULL;
11949
11950 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11951 "Received queue update message for %u with q_len %llu and mtu %u\n",
11952 ntohl (msg->qid),
11953 (unsigned long long) GNUNET_ntohll (msg->q_len),
11954 ntohl (msg->mtu));
11955 for (target_queue = tc->details.communicator.queue_head;
11956 NULL != target_queue;
11957 target_queue = target_queue->next_client)
11958 {
11959 if (ntohl (msg->qid) == target_queue->qid)
11960 break;
11961 }
11962 if (NULL == target_queue)
11963 {
11964 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
11965 "Queue to update no longer exists! Discarding update.\n");
11966 return;
11967 }
11968
11969 target_queue->nt = msg->nt;
11970 target_queue->mtu = ntohl (msg->mtu);
11971 target_queue->cs = msg->cs;
11972 target_queue->priority = ntohl (msg->priority);
11973 /* The update message indicates how many messages
11974 * the queue should be able to handle.
11975 */
11976 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (msg->q_len))
11977 target_queue->unlimited_length = GNUNET_YES;
11978 else
11979 target_queue->unlimited_length = GNUNET_NO;
11980 target_queue->q_capacity += GNUNET_ntohll (msg->q_len);
11981 if (0 < target_queue->q_capacity)
11982 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
11983 target_queue,
11984 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
11985 GNUNET_SERVICE_client_continue (tc->client);
11986}
11987
11988
11989/**
11990 * Communicator tells us that our request to create a queue "worked", that
11991 * is setting up the queue is now in process.
11992 *
11993 * @param cls the `struct TransportClient`
11994 * @param cqr confirmation message
11995 */
11996static void
11997handle_queue_create_ok (void *cls,
11998 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
11999{
12000 struct TransportClient *tc = cls;
12001
12002 if (CT_COMMUNICATOR != tc->type)
12003 {
12004 GNUNET_break (0);
12005 GNUNET_SERVICE_client_drop (tc->client);
12006 return;
12007 }
12008 GNUNET_STATISTICS_update (GST_stats,
12009 "# Suggestions succeeded at communicator",
12010 1,
12011 GNUNET_NO);
12012 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12013 "Request #%u for communicator to create queue succeeded\n",
12014 (unsigned int) ntohs (cqr->request_id));
12015 GNUNET_SERVICE_client_continue (tc->client);
12016}
12017
12018
12019/**
12020 * Communicator tells us that our request to create a queue failed. This
12021 * usually indicates that the provided address is simply invalid or that the
12022 * communicator's resources are exhausted.
12023 *
12024 * @param cls the `struct TransportClient`
12025 * @param cqr failure message
12026 */
12027static void
12028handle_queue_create_fail (
12029 void *cls,
12030 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
12031{
12032 struct TransportClient *tc = cls;
12033
12034 if (CT_COMMUNICATOR != tc->type)
12035 {
12036 GNUNET_break (0);
12037 GNUNET_SERVICE_client_drop (tc->client);
12038 return;
12039 }
12040 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12041 "Request #%u for communicator to create queue failed\n",
12042 (unsigned int) ntohs (cqr->request_id));
12043 GNUNET_STATISTICS_update (GST_stats,
12044 "# Suggestions failed in queue creation at communicator",
12045 1,
12046 GNUNET_NO);
12047 GNUNET_SERVICE_client_continue (tc->client);
12048}
12049
12050
12051/**
12052 * We have received a `struct ExpressPreferenceMessage` from an application
12053 * client.
12054 *
12055 * @param cls handle to the client
12056 * @param msg the start message
12057 */
12058static void
12059handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
12060{
12061 struct TransportClient *tc = cls;
12062 struct PeerRequest *pr;
12063
12064 if (CT_APPLICATION != tc->type)
12065 {
12066 GNUNET_break (0);
12067 GNUNET_SERVICE_client_drop (tc->client);
12068 return;
12069 }
12070 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
12071 &msg->peer);
12072 if (NULL == pr)
12073 {
12074 GNUNET_break (0);
12075 GNUNET_SERVICE_client_drop (tc->client);
12076 return;
12077 }
12078 (void) stop_peer_request (tc, &pr->pid, pr);
12079 GNUNET_SERVICE_client_continue (tc->client);
12080}
12081
12082
12083static void
12084hello_for_client_cb (void *cls,
12085 const struct GNUNET_PeerIdentity *pid,
12086 const char *uri)
12087{
12088 (void) cls;
12089 struct Queue *q;
12090 int pfx_len;
12091 const char *eou;
12092 char *address;
12093
12094 eou = strstr (uri,
12095 "://");
12096 pfx_len = eou - uri;
12097 eou += 3;
12098 GNUNET_asprintf (&address,
12099 "%.*s-%s",
12100 pfx_len,
12101 uri,
12102 eou);
12103
12104 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12105 "hello for client %s\n",
12106 address);
12107
12108 q = find_queue (pid, address);
12109 if (NULL == q)
12110 {
12111 suggest_to_connect (pid, address);
12112 }
12113 else
12114 start_address_validation (pid, address);
12115 GNUNET_free (address);
12116}
12117
12118
12119/**
12120 * Function called by PEERSTORE for each matching record.
12121 *
12122 * @param cls closure, a `struct PeerRequest`
12123 * @param record peerstore record information
12124 * @param emsg error message, or NULL if no errors
12125 */
12126static void
12127handle_hello_for_client (void *cls,
12128 const struct GNUNET_PEERSTORE_Record *record,
12129 const char *emsg)
12130{
12131 struct PeerRequest *pr = cls;
12132 struct GNUNET_HELLO_Builder *builder;
12133 struct GNUNET_MessageHeader *hello;
12134
12135 if (NULL != emsg)
12136 {
12137 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
12138 "Got failure from PEERSTORE: %s\n",
12139 emsg);
12140 return;
12141 }
12142 hello = record->value;
12143 if (0 == GNUNET_memcmp (&record->peer, &GST_my_identity))
12144 {
12145 GNUNET_PEERSTORE_monitor_next (pr->nc, 1);
12146 return;
12147 }
12148 builder = GNUNET_HELLO_builder_from_msg (hello);
12149 GNUNET_HELLO_builder_iterate (builder,
12150 hello_for_client_cb,
12151 NULL);
12152 GNUNET_HELLO_builder_free (builder);
12153}
12154
12155
12156static void
12157hello_for_client_error_cb (void *cls)
12158{
12159 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
12160 "Error in PEERSTORE monitoring\n");
12161}
12162
12163
12164static void
12165hello_for_client_sync_cb (void *cls)
12166{
12167 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
12168 "Done with initial PEERSTORE iteration during monitoring\n");
12169}
12170
12171
12172/**
12173 * We have received a `struct ExpressPreferenceMessage` from an application
12174 * client.
12175 *
12176 * @param cls handle to the client
12177 * @param msg the start message
12178 */
12179static void
12180handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
12181{
12182 struct TransportClient *tc = cls;
12183 struct PeerRequest *pr;
12184
12185 if (CT_NONE == tc->type)
12186 {
12187 tc->type = CT_APPLICATION;
12188 tc->details.application.requests =
12189 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
12190 }
12191 if (CT_APPLICATION != tc->type)
12192 {
12193 GNUNET_break (0);
12194 GNUNET_SERVICE_client_drop (tc->client);
12195 return;
12196 }
12197 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12198 "Client suggested we talk to %s with preference %d at rate %u\n",
12199 GNUNET_i2s (&msg->peer),
12200 (int) ntohl (msg->pk),
12201 (int) ntohl (msg->bw.value__));
12202 pr = GNUNET_new (struct PeerRequest);
12203 pr->tc = tc;
12204 pr->pid = msg->peer;
12205 pr->bw = msg->bw;
12206 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
12207 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
12208 tc->details.application.requests,
12209 &pr->pid,
12210 pr,
12211 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
12212 {
12213 GNUNET_break (0);
12214 GNUNET_free (pr);
12215 GNUNET_SERVICE_client_drop (tc->client);
12216 return;
12217 }
12218 pr->nc =
12219 GNUNET_PEERSTORE_monitor_start (GST_cfg,
12220 GNUNET_YES,
12221 "peerstore",
12222 NULL,
12223 GNUNET_PEERSTORE_HELLO_KEY,
12224 &hello_for_client_error_cb,
12225 NULL,
12226 &hello_for_client_sync_cb,
12227 NULL,
12228 &handle_hello_for_client,
12229 pr);
12230 GNUNET_SERVICE_client_continue (tc->client);
12231}
12232
12233
12234/**
12235 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
12236 * messages.
12237 *
12238 * @param cls a `struct TransportClient *`
12239 * @param m message to verify
12240 * @return #GNUNET_OK on success
12241 */
12242static int
12243check_request_hello_validation (void *cls,
12244 const struct RequestHelloValidationMessage *m)
12245{
12246 (void) cls;
12247 GNUNET_MQ_check_zero_termination (m);
12248 return GNUNET_OK;
12249}
12250
12251
12252/**
12253 * A client encountered an address of another peer. Consider validating it,
12254 * and if validation succeeds, persist it to PEERSTORE.
12255 *
12256 * @param cls a `struct TransportClient *`
12257 * @param m message to verify
12258 */
12259static void
12260handle_request_hello_validation (void *cls,
12261 const struct RequestHelloValidationMessage *m)
12262{
12263 struct TransportClient *tc = cls;
12264 struct Queue *q;
12265
12266 q = find_queue (&m->peer, (const char *) &m[1]);
12267 if (NULL == q)
12268 {
12269 suggest_to_connect (&m->peer, (const char *) &m[1]);
12270 }
12271 else
12272 start_address_validation (&m->peer, (const char *) &m[1]);
12273 GNUNET_SERVICE_client_continue (tc->client);
12274}
12275
12276
12277/**
12278 * Free neighbour entry.
12279 *
12280 * @param cls NULL
12281 * @param pid unused
12282 * @param value a `struct Neighbour`
12283 * @return #GNUNET_OK (always)
12284 */
12285static int
12286free_neighbour_cb (void *cls,
12287 const struct GNUNET_PeerIdentity *pid,
12288 void *value)
12289{
12290 struct Neighbour *neighbour = value;
12291
12292 (void) cls;
12293 (void) pid;
12294 GNUNET_break (0); // should this ever happen?
12295 free_neighbour (neighbour);
12296
12297 return GNUNET_OK;
12298}
12299
12300
12301/**
12302 * Free DV route entry.
12303 *
12304 * @param cls NULL
12305 * @param pid unused
12306 * @param value a `struct DistanceVector`
12307 * @return #GNUNET_OK (always)
12308 */
12309static int
12310free_dv_routes_cb (void *cls,
12311 const struct GNUNET_PeerIdentity *pid,
12312 void *value)
12313{
12314 struct DistanceVector *dv = value;
12315
12316 (void) cls;
12317 (void) pid;
12318 free_dv_route (dv);
12319
12320 return GNUNET_OK;
12321}
12322
12323
12324/**
12325 * Free validation state.
12326 *
12327 * @param cls NULL
12328 * @param pid unused
12329 * @param value a `struct ValidationState`
12330 * @return #GNUNET_OK (always)
12331 */
12332static int
12333free_validation_state_cb (void *cls,
12334 const struct GNUNET_PeerIdentity *pid,
12335 void *value)
12336{
12337 struct ValidationState *vs = value;
12338
12339 (void) cls;
12340 (void) pid;
12341 free_validation_state (vs);
12342 return GNUNET_OK;
12343}
12344
12345
12346/**
12347 * Free pending acknowledgement.
12348 *
12349 * @param cls NULL
12350 * @param key unused
12351 * @param value a `struct PendingAcknowledgement`
12352 * @return #GNUNET_OK (always)
12353 */
12354static int
12355free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
12356{
12357 struct PendingAcknowledgement *pa = value;
12358
12359 (void) cls;
12360 (void) key;
12361 free_pending_acknowledgement (pa);
12362 return GNUNET_OK;
12363}
12364
12365
12366/**
12367 * Free acknowledgement cummulator.
12368 *
12369 * @param cls NULL
12370 * @param pid unused
12371 * @param value a `struct AcknowledgementCummulator`
12372 * @return #GNUNET_OK (always)
12373 */
12374static int
12375free_ack_cummulator_cb (void *cls,
12376 const struct GNUNET_PeerIdentity *pid,
12377 void *value)
12378{
12379 struct AcknowledgementCummulator *ac = value;
12380
12381 (void) cls;
12382 (void) pid;
12383 GNUNET_SCHEDULER_cancel (ac->task);
12384 GNUNET_free (ac);
12385 return GNUNET_OK;
12386}
12387
12388
12389/**
12390 * Function called when the service shuts down. Unloads our plugins
12391 * and cancels pending validations.
12392 *
12393 * @param cls closure, unused
12394 */
12395static void
12396do_shutdown (void *cls)
12397{
12398 struct LearnLaunchEntry *lle;
12399 (void) cls;
12400
12401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12402 "shutdown logic\n");
12403 GNUNET_NAT_unregister (nh);
12404 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
12405 &free_neighbour_cb, NULL);
12406 if (NULL != validation_task)
12407 {
12408 GNUNET_SCHEDULER_cancel (validation_task);
12409 validation_task = NULL;
12410 }
12411 if (NULL != dvlearn_task)
12412 {
12413 GNUNET_SCHEDULER_cancel (dvlearn_task);
12414 dvlearn_task = NULL;
12415 }
12416 if (NULL != GST_stats)
12417 {
12418 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
12419 GST_stats = NULL;
12420 }
12421 if (NULL != GST_my_hello)
12422 {
12423 GNUNET_HELLO_builder_free (GST_my_hello);
12424 GST_my_hello = NULL;
12425 }
12426 if (NULL != GST_my_private_key)
12427 {
12428 GNUNET_free (GST_my_private_key);
12429 GST_my_private_key = NULL;
12430 }
12431 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
12432 &free_ack_cummulator_cb,
12433 NULL);
12434 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
12435 ack_cummulators = NULL;
12436 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
12437 &free_pending_ack_cb,
12438 NULL);
12439 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
12440 pending_acks = NULL;
12441 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
12442 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
12443 neighbours = NULL;
12444 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
12445 GNUNET_CONTAINER_multipeermap_destroy (links);
12446 links = NULL;
12447 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
12448 &free_backtalker_cb,
12449 NULL);
12450 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
12451 backtalkers = NULL;
12452 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
12453 &free_validation_state_cb,
12454 NULL);
12455 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
12456 validation_map = NULL;
12457 GNUNET_CONTAINER_multihashmap_destroy (revalidation_map);
12458 revalidation_map = NULL;
12459 while (NULL != ir_head)
12460 free_incoming_request (ir_head);
12461 GNUNET_assert (0 == ir_total);
12462 while (NULL != (lle = lle_head))
12463 {
12464 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
12465 GNUNET_free (lle);
12466 }
12467 if (NULL != peerstore)
12468 {
12469 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12470 "Disconnecting from PEERSTORE service\n");
12471 GNUNET_PEERSTORE_disconnect (peerstore);
12472 peerstore = NULL;
12473 }
12474 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
12475 dvlearn_map = NULL;
12476 GNUNET_CONTAINER_heap_destroy (validation_heap);
12477 validation_heap = NULL;
12478 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
12479 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
12480 dv_routes = NULL;
12481 GNUNET_SCHEDULER_shutdown ();
12482}
12483
12484
12485static void
12486shutdown_task (void *cls)
12487{
12488 in_shutdown = GNUNET_YES;
12489
12490 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12491 "Shutdown task executed\n");
12492 if (NULL != clients_head)
12493 {
12494 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
12495 {
12496 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
12497 "client still connected: %u\n",
12498 tc->type);
12499 }
12500 }
12501 else
12502 do_shutdown (cls);
12503
12504}
12505
12506
12507/**
12508 * Initiate transport service.
12509 *
12510 * @param cls closure
12511 * @param c configuration to use
12512 * @param service the initialized service
12513 */
12514static void
12515run (void *cls,
12516 const struct GNUNET_CONFIGURATION_Handle *c,
12517 struct GNUNET_SERVICE_Handle *service)
12518{
12519 (void) cls;
12520 (void) service;
12521 /* setup globals */
12522 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
12523 in_shutdown = GNUNET_NO;
12524 GST_cfg = c;
12525 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
12526 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
12527 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
12528 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
12529 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
12530 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
12531 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
12532 GNUNET_YES);
12533 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
12534 revalidation_map = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
12535 validation_heap =
12536 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
12537 GST_my_private_key =
12538 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
12539 if (NULL == GST_my_private_key)
12540 {
12541 GNUNET_log (
12542 GNUNET_ERROR_TYPE_ERROR,
12543 _ (
12544 "Transport service is lacking key configuration settings. Exiting.\n"));
12545 GNUNET_SCHEDULER_shutdown ();
12546 return;
12547 }
12548 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
12549 &GST_my_identity.public_key);
12550 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
12551 "My identity is `%s'\n",
12552 GNUNET_i2s_full (&GST_my_identity));
12553 GST_my_hello = GNUNET_HELLO_builder_new (&GST_my_identity);
12554 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
12555 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
12556 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
12557 nh = GNUNET_NAT_register (GST_cfg,
12558 "transport",
12559 0,
12560 0,
12561 NULL,
12562 0,
12563 NULL,
12564 NULL,
12565 NULL);
12566 if (NULL == peerstore)
12567 {
12568 GNUNET_break (0);
12569 GNUNET_SCHEDULER_shutdown ();
12570 return;
12571 }
12572}
12573
12574
12575/**
12576 * Define "main" method using service macro.
12577 */
12578GNUNET_SERVICE_MAIN (
12579 "transport",
12580 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
12581 &run,
12582 &client_connect_cb,
12583 &client_disconnect_cb,
12584 NULL,
12585 /* communication with applications */
12586 GNUNET_MQ_hd_fixed_size (suggest,
12587 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
12588 struct ExpressPreferenceMessage,
12589 NULL),
12590 GNUNET_MQ_hd_fixed_size (suggest_cancel,
12591 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
12592 struct ExpressPreferenceMessage,
12593 NULL),
12594 GNUNET_MQ_hd_var_size (request_hello_validation,
12595 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
12596 struct RequestHelloValidationMessage,
12597 NULL),
12598 /* communication with core */
12599 GNUNET_MQ_hd_fixed_size (client_start,
12600 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
12601 struct StartMessage,
12602 NULL),
12603 GNUNET_MQ_hd_var_size (client_send,
12604 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
12605 struct OutboundMessage,
12606 NULL),
12607 GNUNET_MQ_hd_fixed_size (client_recv_ok,
12608 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
12609 struct RecvOkMessage,
12610 NULL),
12611 /* communication with communicators */
12612 GNUNET_MQ_hd_var_size (communicator_available,
12613 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
12614 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
12615 NULL),
12616 GNUNET_MQ_hd_var_size (communicator_backchannel,
12617 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
12618 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
12619 NULL),
12620 GNUNET_MQ_hd_var_size (add_address,
12621 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
12622 struct GNUNET_TRANSPORT_AddAddressMessage,
12623 NULL),
12624 GNUNET_MQ_hd_fixed_size (del_address,
12625 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
12626 struct GNUNET_TRANSPORT_DelAddressMessage,
12627 NULL),
12628 GNUNET_MQ_hd_var_size (incoming_msg,
12629 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
12630 struct GNUNET_TRANSPORT_IncomingMessage,
12631 NULL),
12632 GNUNET_MQ_hd_fixed_size (queue_create_ok,
12633 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
12634 struct GNUNET_TRANSPORT_CreateQueueResponse,
12635 NULL),
12636 GNUNET_MQ_hd_fixed_size (queue_create_fail,
12637 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
12638 struct GNUNET_TRANSPORT_CreateQueueResponse,
12639 NULL),
12640 GNUNET_MQ_hd_var_size (add_queue_message,
12641 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
12642 struct GNUNET_TRANSPORT_AddQueueMessage,
12643 NULL),
12644 GNUNET_MQ_hd_fixed_size (update_queue_message,
12645 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE,
12646 struct GNUNET_TRANSPORT_UpdateQueueMessage,
12647 NULL),
12648 GNUNET_MQ_hd_fixed_size (del_queue_message,
12649 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
12650 struct GNUNET_TRANSPORT_DelQueueMessage,
12651 NULL),
12652 GNUNET_MQ_hd_fixed_size (send_message_ack,
12653 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
12654 struct GNUNET_TRANSPORT_SendMessageToAck,
12655 NULL),
12656 /* communication with monitors */
12657 GNUNET_MQ_hd_fixed_size (monitor_start,
12658 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
12659 struct GNUNET_TRANSPORT_MonitorStart,
12660 NULL),
12661 GNUNET_MQ_handler_end ());
12662
12663
12664/* end of file gnunet-service-transport.c */
diff --git a/src/service/transport/gnunet-service-transport.h b/src/service/transport/gnunet-service-transport.h
new file mode 100644
index 000000000..ea9e71e4b
--- /dev/null
+++ b/src/service/transport/gnunet-service-transport.h
@@ -0,0 +1,234 @@
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/service/transport/gnunet-transport-certificate-creation.in b/src/service/transport/gnunet-transport-certificate-creation.in
new file mode 100644
index 000000000..771422a7a
--- /dev/null
+++ b/src/service/transport/gnunet-transport-certificate-creation.in
@@ -0,0 +1,158 @@
1#!/bin/sh
2#
3# This shell script will generate an X509 certificate for
4# your gnunet-transport HTTPS
5#
6# The current version partially reuses and recycles
7# code from build.sh by NetBSD (although not entirely
8# used because it needs debugging):
9#
10# Copyright (c) 2001-2011 The NetBSD Foundation, Inc.
11# All rights reserved.
12#
13# This code is derived from software contributed to
14# The NetBSD Foundation by Todd Vierling and Luke Mewburn.
15
16# Redistribution and use in source and binary forms, with or
17# without modification, are permitted provided that the following
18# conditions are met:
19# 1. Redistributions of source code must retain the above
20# copyright notice, this list of conditions and the following
21# disclaimer.
22# 2. Redistributions in binary form must reproduce the above
23# copyright notice, this list of conditions and the following
24# disclaimer in the documentation and/or other materials
25# provided with the distribution.
26
27# THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND
28# CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
29# INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
30# MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
31# DISCLAIMED.
32# IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS BE LIABLE FOR
33# ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
34# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
35# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
37# ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
38# LIABILITY, OR TORT
39# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
40# THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
41# OF SUCH DAMAGE.
42
43progname=${0##*/}
44
45existence() {
46 command -v "$1" >/dev/null 2>&1
47}
48
49setdefaults()
50{
51 verbosity=0
52 runcmd=
53}
54
55statusmsg()
56{
57 ${runcmd} echo " $@"
58}
59
60infomsg()
61{
62 if [ x$verbosity = x1 ]; then
63 statusmsg "INFO: $@"
64 fi
65}
66
67warningmsg()
68{
69 statusmsg "WARNING: $@"
70}
71
72errormsg()
73{
74 statusmsg "ERROR: $@"
75}
76
77linemsg()
78{
79 statusmsg "========================================="
80}
81
82
83usage()
84{
85 if [ -n "$*" ]; then
86 echo ""
87 echo "${progname}: $*"
88 fi
89 cat <<_usage_
90
91Usage: ${progname} [-hv] [-c FILE] [...]
92
93Options:
94 -c FILE Use the configuration file FILE.
95 -h Print this help message.
96 -v Print the version and exit.
97 -V be verbose
98
99_usage_
100 exit 1
101}
102
103
104generate_cert_key()
105{
106 echo ""
107 infomsg "Generating Cert and Key"
108
109 CERTTOOL=""
110 GNUTLS_CA_TEMPLATE=@PKGDATADIRECTORY@/gnunet-gns-proxy-ca.template
111 OPENSSL=0
112 if test -x $(existence gnutls-certtool)
113 #if test -z "`gnutls-certtool --version`" > /dev/null
114 then
115 if test -z "`certtool --version | grep gnutls`" > /dev/null
116 then
117 warningmsg "'gnutls-certtool' or 'certtool' command not found. Trying openssl."
118 # if test -z "`openssl version`" > /dev/null
119 if test -x $(existence openssl)
120 then
121 OPENSSL=1
122 else
123 warningmsg "Install either gnutls certtool or openssl for certificate generation!"
124 statusmsg "Cleaning up."
125 exit 1
126 fi
127 fi
128 CERTTOOL="certtool"
129 else
130 CERTTOOL="gnutls-certtool"
131 fi
132 mkdir -p `dirname $KEYFILE`
133
134 if test 1 -eq $OPENSSL
135 then
136 openssl genrsa -out $KEYFILE 1024
137 openssl req -batch -days 365 -out $CERTFILE -new -x509 -key $KEYFILE
138 else
139 $CERTTOOL --generate-privkey --outfile $KEYFILE 2>/dev/null
140 $CERTTOOL --template $GNUTLS_CA_TEMPLATE --generate-self-signed --load-privkey $KEYFILE --outfile $CERTFILE 2>/dev/null
141 fi
142 }
143
144print_version()
145{
146 GNUNET_ARM_VERSION=`gnunet-arm -v`
147 echo $GNUNET_ARM_VERSION
148}
149
150main()
151{
152 KEYFILE=$1
153 CERTFILE=$2
154 setdefaults
155 generate_cert_key
156}
157
158main "$@"
diff --git a/src/service/transport/gnunet-transport.c b/src/service/transport/gnunet-transport.c
new file mode 100644
index 000000000..b5ad43770
--- /dev/null
+++ b/src/service/transport/gnunet-transport.c
@@ -0,0 +1,1437 @@
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/service/transport/ieee80211_radiotap.h b/src/service/transport/ieee80211_radiotap.h
new file mode 100644
index 000000000..9351da9a5
--- /dev/null
+++ b/src/service/transport/ieee80211_radiotap.h
@@ -0,0 +1,276 @@
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/service/transport/meson.build b/src/service/transport/meson.build
new file mode 100644
index 000000000..1fdc47699
--- /dev/null
+++ b/src/service/transport/meson.build
@@ -0,0 +1,501 @@
1libgnunettransportapplication_src = ['transport_api2_application.c']
2libgnunettransportcore_src = ['transport_api2_core.c']
3libgnunettransportcommunicator_src = ['transport_api2_communication.c']
4libgnunettransportmonitor_src = ['transport_api2_monitor.c']
5
6gnunetservicetransport_src = ['gnunet-service-transport.c']
7gnunetcommunicatortcp_src = ['gnunet-communicator-tcp.c']
8gnunetcommunicatorudp_src = ['gnunet-communicator-udp.c']
9gnunetcommunicatorunix_src = ['gnunet-communicator-unix.c']
10
11configure_file(input : 'transport.conf.in',
12 output : 'transport.conf',
13 configuration : cdata,
14 install: true,
15 install_dir: pkgcfgdir)
16
17configure_file(input : 'gnunet-transport-certificate-creation.in',
18 output : 'gnunet-transport-certificate-creation',
19 configuration : cdata,
20 install: true,
21 install_dir: get_option('bindir'))
22
23if get_option('monolith')
24 foreach p : libgnunettransportapplication_src + libgnunettransportcore_src + libgnunettransportcommunicator_src + libgnunettransportmonitor_src + gnunetservicetransport_src
25 gnunet_src += 'transport/' + p
26 endforeach
27endif
28
29libgnunettransportapplication = library('gnunettransportapplication',
30 libgnunettransportapplication_src,
31 soversion: '0',
32 version: '0.0.0',
33 dependencies: libgnunetutil_dep,
34 include_directories: [incdir, configuration_inc],
35 install: true,
36 install_dir: get_option('libdir'))
37pkg.generate(libgnunettransportapplication, url: 'https://www.gnunet.org',
38 description : 'Provides application APIs for accessing the transport service')
39libgnunettransportapplication_dep = declare_dependency(link_with : libgnunettransportapplication)
40
41libgnunettransportcore = library('gnunettransportcore',
42 libgnunettransportcore_src,
43 soversion: '0',
44 version: '0.0.0',
45 dependencies: libgnunetutil_dep,
46 include_directories: [incdir, configuration_inc],
47 install: true,
48 install_dir: get_option('libdir'))
49pkg.generate(libgnunettransportcore, url: 'https://www.gnunet.org',
50 description : 'Provides core API for accessing the transport service')
51libgnunettransportcore_dep = declare_dependency(link_with : libgnunettransportcore)
52
53libgnunettransportcommunicator = library('gnunettransportcommunicator',
54 libgnunettransportcommunicator_src,
55 soversion: '0',
56 version: '0.0.0',
57 dependencies: libgnunetutil_dep,
58 include_directories: [incdir, configuration_inc],
59 install: true,
60 install_dir: get_option('libdir'))
61pkg.generate(libgnunettransportcommunicator, url: 'https://www.gnunet.org',
62 description : 'Provides communicator API for accessing the transport service')
63libgnunettransportcommunicator_dep = declare_dependency(link_with : libgnunettransportcommunicator)
64
65libgnunettransportmonitor = library('gnunettransportmonitor',
66 libgnunettransportmonitor_src,
67 soversion: '0',
68 version: '0.0.0',
69 dependencies: libgnunetutil_dep,
70 include_directories: [incdir, configuration_inc],
71 install: true,
72 install_dir: get_option('libdir'))
73pkg.generate(libgnunettransportmonitor, url: 'https://www.gnunet.org',
74 description : 'Provides monitor API for accessing the transport service')
75libgnunettransportmonitor_dep = declare_dependency(link_with : libgnunettransportmonitor)
76
77libgnunettransporttesting2 = library('gnunettransporttesting2',
78 [
79 'transport_api_traits.c',
80 'transport_api_cmd_connecting_peers.c',
81 'transport_api_cmd_backchannel_check.c',
82 'transport_api_cmd_start_peer.c',
83 'transport_api_cmd_stop_peer.c',
84 'testing_api_cmd_start_peer.c',
85 'testing_api_cmd_stop_peer.c',
86 'transport_api_cmd_send_simple.c',
87 'transport_api_cmd_send_simple_performance.c',
88 'transport-testing2.c',
89 'transport-testing-filenames2.c',
90 'transport-testing-loggers2.c',
91 'transport-testing-main2.c',
92 'transport-testing-send2.c',
93 'transport-testing-communicator.c',
94 ],
95 soversion: '0',
96 version: '0.0.0',
97 dependencies: [libgnunetutil_dep,
98 libgnunettransportcore_dep,
99 libgnunettransportapplication_dep,
100 libgnunetpeerstore_dep,
101 libgnunettesting_dep,
102 libgnunethello_dep],
103 include_directories: [incdir, configuration_inc],
104 install: true,
105 install_dir: get_option('libdir'))
106libgnunettransporttesting2_dep = declare_dependency(link_with : libgnunettransporttesting2)
107
108executable ('gnunet-service-transport',
109 gnunetservicetransport_src,
110 dependencies: [libgnunettransportcommunicator_dep,
111 libgnunetpeerstore_dep,
112 libgnunetstatistics_dep,
113 libgnunethello_dep,
114 libgnunetnat_dep,
115 gcrypt_dep,
116 m_dep,
117 libgnunetutil_dep],
118 include_directories: [incdir, configuration_inc],
119 install: true,
120 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
121
122executable ('gnunet-communicator-unix',
123 gnunetcommunicatorunix_src,
124 dependencies: [libgnunettransportcommunicator_dep,
125 libgnunetpeerstore_dep,
126 libgnunetstatistics_dep,
127 libgnunetnat_dep,
128 gcrypt_dep,
129 libgnunetutil_dep],
130 include_directories: [incdir, configuration_inc],
131 install: true,
132 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
133executable ('gnunet-communicator-udp',
134 gnunetcommunicatorudp_src,
135 dependencies: [libgnunettransportcommunicator_dep,
136 libgnunettransportapplication_dep,
137 libgnunetpeerstore_dep,
138 libgnunetstatistics_dep,
139 libgnunetnat_dep,
140 gcrypt_dep,
141 libgnunetutil_dep],
142 include_directories: [incdir, configuration_inc],
143 install: true,
144 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
145executable ('gnunet-communicator-tcp',
146 gnunetcommunicatortcp_src,
147 dependencies: [libgnunettransportcommunicator_dep,
148 libgnunetpeerstore_dep,
149 libgnunetstatistics_dep,
150 libgnunetnat_dep,
151 gcrypt_dep,
152 libgnunetutil_dep],
153 include_directories: [incdir, configuration_inc],
154 install: true,
155 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
156if quic_dep.found() and get_option('experimental')
157executable ('gnunet-communicator-quic',
158 gnunetcommunicatortcp_src,
159 dependencies: [libgnunettransportcommunicator_dep,
160 libgnunetpeerstore_dep,
161 libgnunetstatistics_dep,
162 libgnunetnat_dep,
163 gcrypt_dep,
164 quic_dep,
165 libgnunetutil_dep],
166 include_directories: [incdir, configuration_inc],
167 install: true,
168 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
169endif
170
171libgnunettesttransport_cmd_simplesend = library('gnunet_test_transport_plugin_cmd_simple_send',
172 ['test_transport_plugin_cmd_simple_send.c'],
173 dependencies: [
174 libgnunetutil_dep,
175 libgnunettransportapplication_dep,
176 libgnunettransporttesting2_dep,
177 libgnunettransportcore_dep,
178 libgnunettesting_dep,
179 libgnunetpeerstore_dep,
180 libgnunetstatistics_dep,
181 libgnunethello_dep,
182 libgnunetarm_dep,
183 libgnunetutil_dep
184 ],
185 include_directories: [incdir, configuration_inc],
186 install: true,
187 install_dir: get_option('libdir')/'gnunet')
188
189libgnunettesttransport_cmd_simplesendbc = library('gnunet_test_transport_plugin_cmd_simple_send_broadcast',
190 ['test_transport_plugin_cmd_simple_send_broadcast.c'],
191 dependencies: [
192 libgnunetutil_dep,
193 libgnunettransportapplication_dep,
194 libgnunettransporttesting2_dep,
195 libgnunettransportcore_dep,
196 libgnunettesting_dep,
197 libgnunetpeerstore_dep,
198 libgnunetstatistics_dep,
199 libgnunethello_dep,
200 libgnunetarm_dep,
201 libgnunetutil_dep
202 ],
203 include_directories: [incdir, configuration_inc],
204 install: true,
205 install_dir: get_option('libdir')/'gnunet')
206
207libgnunettesttransport_cmd_simplesenddv = library('gnunet_test_transport_plugin_cmd_simple_send_dv',
208 ['test_transport_plugin_cmd_simple_send_dv.c'],
209 dependencies: [
210 libgnunetutil_dep,
211 libgnunettransportapplication_dep,
212 libgnunettransporttesting2_dep,
213 libgnunettransportcore_dep,
214 libgnunettesting_dep,
215 libgnunetpeerstore_dep,
216 libgnunetstatistics_dep,
217 libgnunethello_dep,
218 libgnunetarm_dep,
219 libgnunetutil_dep
220 ],
221 include_directories: [incdir, configuration_inc],
222 install: true,
223 install_dir: get_option('libdir')/'gnunet')
224
225libgnunettesttransport_cmd_simplesendperf = library('gnunet_test_transport_plugin_cmd_simple_send_performance',
226 ['test_transport_plugin_cmd_simple_send_performance.c'],
227 dependencies: [
228 libgnunetutil_dep,
229 libgnunettransportapplication_dep,
230 libgnunettransporttesting2_dep,
231 libgnunettransportcore_dep,
232 libgnunettesting_dep,
233 libgnunetpeerstore_dep,
234 libgnunetstatistics_dep,
235 libgnunethello_dep,
236 libgnunetarm_dep,
237 libgnunetutil_dep
238 ],
239 include_directories: [incdir, configuration_inc],
240 install: true,
241 install_dir: get_option('libdir')/'gnunet')
242
243libgnunettesttransport_cmd_udpback = library('gnunet_test_transport_plugin_cmd_udp_backchannel',
244 ['test_transport_plugin_cmd_udp_backchannel.c'],
245 dependencies: [
246 libgnunetutil_dep,
247 libgnunettransporttesting2_dep,
248 libgnunettransportapplication_dep,
249 libgnunettransportcore_dep,
250 libgnunettesting_dep,
251 libgnunetpeerstore_dep,
252 libgnunetstatistics_dep,
253 libgnunethello_dep,
254 libgnunetarm_dep,
255 libgnunetutil_dep
256 ],
257 include_directories: [incdir, configuration_inc],
258 install: true,
259 install_dir: get_option('libdir')/'gnunet')
260
261libgnunettesttransport_cmd_natupnp = library('gnunet_test_transport_plugin_cmd_nat_upnp',
262 ['test_transport_plugin_cmd_nat_upnp.c'],
263 dependencies: [
264 libgnunetutil_dep,
265 libgnunettransportapplication_dep,
266 libgnunettransporttesting2_dep,
267 libgnunettransportcore_dep,
268 libgnunettesting_dep,
269 libgnunetpeerstore_dep,
270 libgnunetstatistics_dep,
271 libgnunethello_dep,
272 libgnunetarm_dep,
273 libgnunetutil_dep
274 ],
275 include_directories: [incdir, configuration_inc],
276 install: true,
277 install_dir: get_option('libdir')/'gnunet')
278
279configure_file(input : 'test_transport_defaults.conf',
280 output : 'test_transport_defaults.conf',
281 copy: true)
282
283foreach p : ['unix', 'tcp', 'udp', 'quic']
284 configure_file(input : 'test_communicator_'+p+'_basic_peer1.conf',
285 output : 'test_communicator_'+p+'_basic_peer1.conf',
286 copy: true)
287 configure_file(input : 'test_communicator_'+p+'_basic_peer2.conf',
288 output : 'test_communicator_'+p+'_basic_peer2.conf',
289 copy: true)
290endforeach
291
292foreach p : ['tcp', 'udp']
293 configure_file(input : 'test_communicator_'+p+'_rekey_peer1.conf',
294 output : 'test_communicator_'+p+'_rekey_peer1.conf',
295 copy: true)
296 configure_file(input : 'test_communicator_'+p+'_rekey_peer2.conf',
297 output : 'test_communicator_'+p+'_rekey_peer2.conf',
298 copy: true)
299endforeach
300
301configure_file(input : 'test_communicator_udp_backchannel_peer1.conf',
302 output : 'test_communicator_udp_backchannel_peer1.conf',
303 copy: true)
304configure_file(input : 'test_communicator_udp_backchannel_peer2.conf',
305 output : 'test_communicator_udp_backchannel_peer2.conf',
306 copy: true)
307
308configure_file(input : 'test_communicator_tcp_bidirect_peer1.conf',
309 output : 'test_communicator_tcp_bidirect_peer1.conf',
310 copy: true)
311configure_file(input : 'test_communicator_tcp_bidirect_peer2.conf',
312 output : 'test_communicator_tcp_bidirect_peer2.conf',
313 copy: true)
314
315testcommunicator_basic_unix = executable('test_communicator_basic-unix',
316 ['test_communicator_basic.c'],
317 dependencies: [
318 libgnunetutil_dep,
319 libgnunettransportapplication_dep,
320 libgnunettransporttesting2_dep,
321 libgnunettransportcore_dep,
322 libgnunettesting_dep,
323 libgnunetpeerstore_dep,
324 libgnunetstatistics_dep,
325 libgnunethello_dep,
326 libgnunetarm_dep,
327 libgnunetutil_dep
328 ],
329 include_directories: [incdir, configuration_inc],
330 install: false)
331testcommunicator_basic_tcp = executable('test_communicator_basic-tcp',
332 ['test_communicator_basic.c'],
333 dependencies: [
334 libgnunetutil_dep,
335 libgnunettransportapplication_dep,
336 libgnunettransporttesting2_dep,
337 libgnunettransportcore_dep,
338 libgnunettesting_dep,
339 libgnunetpeerstore_dep,
340 libgnunetstatistics_dep,
341 libgnunethello_dep,
342 libgnunetarm_dep,
343 libgnunetutil_dep
344 ],
345 include_directories: [incdir, configuration_inc],
346 install: false)
347testcommunicator_basic_udp = executable('test_communicator_basic-udp',
348 ['test_communicator_basic.c'],
349 dependencies: [
350 libgnunetutil_dep,
351 libgnunettransportapplication_dep,
352 libgnunettransporttesting2_dep,
353 libgnunettransportcore_dep,
354 libgnunettesting_dep,
355 libgnunetpeerstore_dep,
356 libgnunetstatistics_dep,
357 libgnunethello_dep,
358 libgnunetarm_dep,
359 libgnunetutil_dep
360 ],
361 include_directories: [incdir, configuration_inc],
362 install: false)
363if quic_dep.found() and get_option('experimental')
364 testcommunicator_basic_quic = executable('test_communicator_basic-quic',
365 ['test_communicator_basic.c'],
366 dependencies: [
367 libgnunetutil_dep,
368 libgnunettransportapplication_dep,
369 libgnunettransporttesting2_dep,
370 libgnunettransportcore_dep,
371 libgnunettesting_dep,
372 libgnunetpeerstore_dep,
373 libgnunetstatistics_dep,
374 libgnunethello_dep,
375 libgnunetarm_dep,
376 libgnunetutil_dep
377 ],
378 include_directories: [incdir, configuration_inc],
379 install: false)
380endif
381
382testcommunicator_rekey_tcp = executable('test_communicator_rekey-tcp',
383 ['test_communicator_basic.c'],
384 dependencies: [
385 libgnunetutil_dep,
386 libgnunettransportapplication_dep,
387 libgnunettransporttesting2_dep,
388 libgnunettransportcore_dep,
389 libgnunettesting_dep,
390 libgnunetpeerstore_dep,
391 libgnunetstatistics_dep,
392 libgnunethello_dep,
393 libgnunetarm_dep,
394 libgnunetutil_dep
395 ],
396 include_directories: [incdir, configuration_inc],
397 install: false)
398
399testcommunicator_rekey_udp = executable('test_communicator_rekey-udp',
400 ['test_communicator_basic.c'],
401 dependencies: [
402 libgnunetutil_dep,
403 libgnunettransportapplication_dep,
404 libgnunettransporttesting2_dep,
405 libgnunettransportcore_dep,
406 libgnunettesting_dep,
407 libgnunetpeerstore_dep,
408 libgnunetstatistics_dep,
409 libgnunethello_dep,
410 libgnunetarm_dep,
411 libgnunetutil_dep
412 ],
413 include_directories: [incdir, configuration_inc],
414 install: false)
415
416testcommunicator_backchannel_udp = executable('test_communicator_backchannel-udp',
417 ['test_communicator_basic.c'],
418 dependencies: [
419 libgnunetutil_dep,
420 libgnunettransportapplication_dep,
421 libgnunettransporttesting2_dep,
422 libgnunettransportcore_dep,
423 libgnunettesting_dep,
424 libgnunetpeerstore_dep,
425 libgnunetstatistics_dep,
426 libgnunethello_dep,
427 libgnunetarm_dep,
428 libgnunetutil_dep
429 ],
430 include_directories: [incdir, configuration_inc],
431 install: false)
432
433testcommunicator_bidirect_tcp = executable('test_communicator_bidirect-tcp',
434 ['test_communicator_basic.c'],
435 dependencies: [
436 libgnunetutil_dep,
437 libgnunettransportapplication_dep,
438 libgnunettransporttesting2_dep,
439 libgnunettransportcore_dep,
440 libgnunettesting_dep,
441 libgnunetpeerstore_dep,
442 libgnunetstatistics_dep,
443 libgnunethello_dep,
444 libgnunetarm_dep,
445 libgnunetutil_dep
446 ],
447 include_directories: [incdir, configuration_inc],
448 install: false)
449
450
451testtransport_test_names = [
452 'test_transport_start_testcase',
453 'test_transport_simple_send_performance',
454 'test_transport_nat_icmp_tcp',
455 'test_transport_nat_upnp',
456 'test_transport_simple_send_string',
457 'test_transport_simple_send',
458 'test_transport_simple_send_broadcast',
459 'test_transport_udp_backchannel',
460 'test_transport_simple_send_dv_circle',
461 'test_transport_simple_send_dv_inverse'
462 ]
463
464foreach t : testtransport_test_names
465
466 test_filename = t + '.sh'
467 test_file = configure_file(input : test_filename,
468 output : test_filename,
469 copy: true)
470
471 if host_machine.system() != 'darwin'
472 test(t, test_file, suite: 'transport', workdir: meson.current_build_dir(), is_parallel: false)
473 endif
474endforeach
475
476test('test_communicator_basic-unix', testcommunicator_basic_unix,
477 workdir: meson.current_build_dir(),
478 suite: ['transport', 'communicator'], is_parallel: false)
479test('test_communicator_basic-tcp', testcommunicator_basic_tcp,
480 workdir: meson.current_build_dir(),
481 suite: ['transport', 'communicator'], is_parallel: false)
482test('test_communicator_basic-udp', testcommunicator_basic_udp,
483 workdir: meson.current_build_dir(),
484 suite: ['transport', 'communicator'], is_parallel: false)
485if quic_dep.found() and get_option('experimental')
486 test('test_communicator_basic-quic', testcommunicator_basic_quic,
487 workdir: meson.current_build_dir(),
488 suite: ['transport', 'communicator'], is_parallel: false)
489endif
490test('test_communicator_rekey-tcp', testcommunicator_rekey_tcp,
491 workdir: meson.current_build_dir(),
492 suite: ['transport', 'communicator'], is_parallel: false)
493test('test_communicator_rekey-udp', testcommunicator_rekey_udp,
494 workdir: meson.current_build_dir(),
495 suite: ['transport', 'communicator'], is_parallel: false)
496test('test_communicator_backchannel-udp', testcommunicator_backchannel_udp,
497 workdir: meson.current_build_dir(),
498 suite: ['transport', 'communicator'], is_parallel: false)
499test('test_communicator_bidirect-tcp', testcommunicator_bidirect_tcp,
500 workdir: meson.current_build_dir(),
501 suite: ['transport', 'communicator'], is_parallel: false)
diff --git a/src/service/transport/template_cfg_peer1.conf b/src/service/transport/template_cfg_peer1.conf
new file mode 100644
index 000000000..5ba198450
--- /dev/null
+++ b/src/service/transport/template_cfg_peer1.conf
@@ -0,0 +1,50 @@
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/service/transport/template_cfg_peer2.conf b/src/service/transport/template_cfg_peer2.conf
new file mode 100644
index 000000000..6ac610fec
--- /dev/null
+++ b/src/service/transport/template_cfg_peer2.conf
@@ -0,0 +1,58 @@
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/service/transport/template_tng_cfg_peer1.conf b/src/service/transport/template_tng_cfg_peer1.conf
new file mode 100644
index 000000000..b6198d72c
--- /dev/null
+++ b/src/service/transport/template_tng_cfg_peer1.conf
@@ -0,0 +1,34 @@
1@INLINE@ test_tng_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[arm]
12PORT = 12005
13UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-arm.sock
14
15[statistics]
16PORT = 12004
17UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-statistics.sock
18
19[resolver]
20PORT = 12003
21UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-resolver.sock
22
23[peerinfo]
24PORT = 12002
25UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-peerinfo.sock
26USE_INCLUDED_HELLOS = NO
27
28[transport]
29#PREFIX = valgrind --leak-check=full
30PORT = 12001
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-p1-service-transport.sock
32
33[hostlist]
34SERVERS = dummy
diff --git a/src/service/transport/test_communicator_basic.c b/src/service/transport/test_communicator_basic.c
new file mode 100644
index 000000000..78ac26b25
--- /dev/null
+++ b/src/service/transport/test_communicator_basic.c
@@ -0,0 +1,1266 @@
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_signatures.h"
31#include "gnunet_testing_lib.h"
32#include "transport.h"
33#include "gnunet_statistics_service.h"
34
35#include <inttypes.h>
36
37
38#define LOG(kind, ...) GNUNET_log_from (kind, \
39 "test_transport_communicator", \
40 __VA_ARGS__)
41
42#define NUM_PEERS 2
43
44static struct GNUNET_SCHEDULER_Task *to_task[NUM_PEERS];
45
46static int queue_est = GNUNET_NO;
47
48static struct GNUNET_PeerIdentity peer_id[NUM_PEERS];
49
50static char *communicator_binary;
51
52static struct
53GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_hs[NUM_PEERS];
54
55static struct GNUNET_CONFIGURATION_Handle *cfg_peers[NUM_PEERS];
56
57static struct GNUNET_STATISTICS_Handle *stats[NUM_PEERS];
58
59static char *cfg_peers_name[NUM_PEERS];
60
61static int finished[NUM_PEERS];
62
63static int ret;
64
65static int bidirect = GNUNET_NO;
66
67static size_t long_message_size;
68
69static struct GNUNET_TIME_Absolute start_short[NUM_PEERS];
70
71static struct GNUNET_TIME_Absolute start_long[NUM_PEERS];
72
73static struct GNUNET_TIME_Absolute timeout[NUM_PEERS];
74
75// static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *my_tc;
76
77static char *communicator_name;
78
79static char *test_name;
80
81static struct GNUNET_STATISTICS_GetHandle *box_stats[NUM_PEERS];
82
83static struct GNUNET_STATISTICS_GetHandle *rekey_stats[NUM_PEERS];
84
85#define TEST_SECTION "test-setup"
86
87#define SHORT_MESSAGE_SIZE 128
88
89#define LONG_MESSAGE_SIZE 32000 /* FIXME */
90
91#define ALLOWED_PACKET_LOSS 91
92
93#define BURST_PACKETS 5000
94
95#define TOTAL_ITERATIONS 1
96
97#define PEER_A 0
98
99#define PEER_B 1
100
101static unsigned int iterations_left[NUM_PEERS];
102
103#define TIMEOUT_MULTIPLIER 5
104
105#define DEFAULT_DELAY \
106 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,200)
107
108#define SHORT_BURST_WINDOW \
109 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,2)
110
111#define LONG_BURST_WINDOW \
112 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS,2)
113
114enum TestPhase
115{
116 TP_INIT,
117 TP_BURST_SHORT,
118 TP_BURST_LONG,
119 TP_SIZE_CHECK
120};
121
122static unsigned int phase_short[NUM_PEERS];
123
124static unsigned int phase_long[NUM_PEERS];
125
126static unsigned int phase_size[NUM_PEERS];
127
128static long long unsigned int allowed_packet_loss_short;
129
130static long long unsigned int allowed_packet_loss_long;
131
132static long long unsigned int burst_packets_short;
133
134static long long unsigned int burst_packets_long;
135
136static long long unsigned int delay_long_value;
137
138static long long unsigned int delay_short_value;
139
140static struct GNUNET_TIME_Relative delay_short;
141
142static struct GNUNET_TIME_Relative delay_long;
143
144static size_t num_sent_short[NUM_PEERS];
145
146static size_t num_sent_long[NUM_PEERS];
147
148static size_t num_sent_size[NUM_PEERS];
149
150static uint32_t ack[NUM_PEERS];
151
152static enum TestPhase phase[NUM_PEERS];
153
154static size_t num_received_short[NUM_PEERS];
155
156static size_t num_received_long[NUM_PEERS];
157
158static size_t num_received_size[NUM_PEERS];
159
160static uint64_t avg_latency[NUM_PEERS];
161
162static void
163communicator_available_cb (
164 void *cls,
165 struct
166 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
167 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc,
168 char *address_prefix)
169{
170 LOG (GNUNET_ERROR_TYPE_INFO,
171 "Communicator available. (cc: %u, prefix: %s)\n",
172 cc,
173 address_prefix);
174}
175
176
177static void
178open_queue (void *cls)
179{
180 const char *address = cls;
181
182 if (NULL != tc_hs[PEER_A]->c_mq)
183 {
184 queue_est = GNUNET_YES;
185 GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (tc_hs[PEER_A],
186 &peer_id[PEER_B]
187 ,
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
286
287static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
288get_tc_h (unsigned int peer_nr)
289{
290 LOG (GNUNET_ERROR_TYPE_DEBUG,
291 "Got peer %u\n",
292 peer_nr);
293
294 LOG (GNUNET_ERROR_TYPE_DEBUG,
295 "Handle %p peer 0\n",
296 tc_hs[0]);
297
298 LOG (GNUNET_ERROR_TYPE_DEBUG,
299 "Handle %p peer 1\n",
300 tc_hs[1]);
301
302 LOG (GNUNET_ERROR_TYPE_DEBUG,
303 "Handle %p get\n",
304 tc_hs[peer_nr]);
305
306 return tc_hs[peer_nr];
307}
308
309
310static unsigned int
311get_peer_nr_from_tc (struct
312 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
313{
314 if (tc_h == get_tc_h (0))
315 return PEER_A;
316 else
317 return PEER_B;
318}
319
320
321static unsigned int
322get_peer_nr (void *cls, unsigned int get_the_other_one)
323{
324 if (0 == strcmp ((char*) cls, cfg_peers_name[0]))
325 return get_the_other_one ? PEER_B : PEER_A;
326 else
327 return get_the_other_one ? PEER_A : PEER_B;
328}
329
330
331static void
332process_statistics_box_done (void *cls, int success)
333{
334 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
335 unsigned int peer_nr;
336
337 peer_nr = get_peer_nr_from_tc (tc_h);
338
339 if (NULL != box_stats[peer_nr])
340 box_stats[peer_nr] = NULL;
341 if (NULL == rekey_stats[peer_nr])
342 {
343 LOG (GNUNET_ERROR_TYPE_DEBUG,
344 "Finished\n");
345 GNUNET_SCHEDULER_shutdown ();
346 }
347}
348
349
350static void
351process_statistics_rekey_done (void *cls, int success)
352{
353 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
354 unsigned int peer_nr;
355
356 peer_nr = get_peer_nr_from_tc (tc_h);
357
358 if (NULL != rekey_stats[peer_nr])
359 rekey_stats[peer_nr] = NULL;
360 if (NULL == box_stats[peer_nr])
361 {
362 LOG (GNUNET_ERROR_TYPE_DEBUG,
363 "Finished\n");
364 GNUNET_SCHEDULER_shutdown ();
365 }
366}
367
368
369static int
370process_statistics (void *cls,
371 const char *subsystem,
372 const char *name,
373 uint64_t value,
374 int is_persistent)
375{
376 LOG (GNUNET_ERROR_TYPE_DEBUG,
377 "Statistic: Name %s and value %" PRIu64 "\n",
378 name,
379 value);
380 if ((0 == strcmp ("rekey", test_name)) && (0 == strcmp (
381 "# rekeying successful",
382 name)))
383 {
384 if (0 == value)
385 {
386 ret = 2;
387 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
388 "No successful rekeying!\n");
389 GNUNET_SCHEDULER_shutdown ();
390 }
391 LOG (GNUNET_ERROR_TYPE_MESSAGE,
392 "Successful rekeys: %llu\n",
393 (unsigned long long) value);
394 }
395 if ((0 == strcmp ("backchannel", test_name)) &&
396 (0 == strcmp (
397 "# messages decrypted with BOX",
398 name))
399 && (9000 > value))
400 {
401 ret = 2;
402 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
403 "Not enough BOX messages! (want: %u, have %llu)\n",
404 9000, (unsigned long long) value);
405 GNUNET_SCHEDULER_shutdown ();
406 }
407 if ((0 == strcmp ("rekey", test_name)) &&
408 (0 == strcmp (
409 "# messages decrypted with BOX",
410 name))
411 && (6000 > value))
412 {
413 if (6000 > value)
414 {
415 ret = 2;
416 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
417 "Not enough BOX messages! (want: %u, have %llu)\n",
418 6000, (unsigned long long) value);
419 GNUNET_SCHEDULER_shutdown ();
420 }
421 LOG (GNUNET_ERROR_TYPE_MESSAGE,
422 "Successful messages in BOX: %llu\n",
423 (unsigned long long) value);
424 }
425 return GNUNET_OK;
426}
427
428
429static void
430short_test (void *cls);
431
432static void
433short_test_cb (void *cls)
434{
435 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
436 unsigned int peer_nr;
437 char *payload;
438
439 peer_nr = get_peer_nr_from_tc (tc_h);
440
441 LOG (GNUNET_ERROR_TYPE_DEBUG,
442 "short_test_cb %u/%u for peer %u and handle %p\n",
443 (unsigned int) num_sent_short[peer_nr],
444 (unsigned int) num_received_short[peer_nr],
445 peer_nr,
446 tc_h);
447 payload = make_payload (SHORT_MESSAGE_SIZE);
448 num_sent_short[peer_nr]++;
449 if (burst_packets_short == num_sent_short[peer_nr])
450 tc_h->cont = NULL;
451 else
452 tc_h->cont = short_test;
453 tc_h->cont_cls = cls;
454 GNUNET_TRANSPORT_TESTING_transport_communicator_send (tc_h,
455 NULL,
456 cls,
457 payload,
458 SHORT_MESSAGE_SIZE);
459 GNUNET_free (payload);
460 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
461 GNUNET_TIME_relative_multiply (
462 GNUNET_TIME_UNIT_SECONDS,
463 TIMEOUT_MULTIPLIER));
464}
465
466
467static void
468short_test (void *cls)
469{
470 GNUNET_SCHEDULER_add_delayed (delay_short,
471 &short_test_cb,
472 cls);
473}
474
475
476static void
477size_test (void *cls)
478{
479 unsigned int peer_nr;
480 char *payload;
481 size_t max_size = 64000;
482 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
483
484 peer_nr = get_peer_nr_from_tc (tc_h);
485 LOG (GNUNET_ERROR_TYPE_DEBUG,
486 "size_test_cb %u\n",
487 (unsigned int) num_sent_size[peer_nr]);
488 GNUNET_assert (TP_SIZE_CHECK == phase[peer_nr]);
489 if (LONG_MESSAGE_SIZE != long_message_size)
490 max_size = long_message_size;
491 if (ack[peer_nr] + 10 > max_size)
492 return; /* Leave some room for our protocol, so not 2^16 exactly */
493 ack[peer_nr] += 10;
494 payload = make_payload (ack[peer_nr]);
495 num_sent_size[peer_nr]++;
496 if (ack[peer_nr] >= max_size)
497 tc_h->cont = NULL;
498 else
499 tc_h->cont = size_test;
500 tc_h->cont_cls = cls;
501 GNUNET_TRANSPORT_TESTING_transport_communicator_send (tc_h,
502 NULL,
503 cls,
504 payload,
505 ack[peer_nr]);
506 GNUNET_free (payload);
507 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
508 GNUNET_TIME_relative_multiply (
509 GNUNET_TIME_UNIT_SECONDS,
510 TIMEOUT_MULTIPLIER));
511}
512
513
514static void
515long_test (void *cls);
516
517static void
518long_test_cb (void *cls)
519{
520 unsigned int peer_nr;
521 char *payload;
522 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
523
524 peer_nr = get_peer_nr_from_tc (tc_h);
525
526 LOG (GNUNET_ERROR_TYPE_DEBUG,
527 "long_test_cb %u/%u\n",
528 (unsigned int) num_sent_long[peer_nr],
529 (unsigned int) num_received_long[peer_nr]);
530 payload = make_payload (long_message_size);
531 num_sent_long[peer_nr]++;
532 if (burst_packets_long == num_sent_long[peer_nr])
533 tc_h->cont = NULL;
534 else
535 tc_h->cont = long_test;
536 tc_h->cont_cls = cls;
537 GNUNET_TRANSPORT_TESTING_transport_communicator_send (tc_h,
538 NULL,
539 cls,
540 payload,
541 long_message_size);
542 GNUNET_free (payload);
543 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
544 GNUNET_TIME_relative_multiply (
545 GNUNET_TIME_UNIT_SECONDS,
546 TIMEOUT_MULTIPLIER));
547}
548
549
550static void
551long_test (void *cls)
552{
553 GNUNET_SCHEDULER_add_delayed (delay_long,
554 &long_test_cb,
555 cls);
556}
557
558
559static void
560choose_phase (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
561{
562 unsigned int peer_nr;
563
564 peer_nr = get_peer_nr_from_tc (tc_h);
565
566 if (GNUNET_YES == phase_short[peer_nr])
567 {
568 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
569 "Choose phase short with peer %u and Handle %p\n",
570 peer_nr,
571 tc_h);
572 phase[peer_nr] = TP_BURST_SHORT;
573 start_short[peer_nr] = GNUNET_TIME_absolute_get ();
574 short_test (tc_h);
575 }
576 else if (GNUNET_YES == phase_long[peer_nr])
577 {
578 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
579 "Choose phase long with peer %u\n",
580 peer_nr);
581 phase[peer_nr] = TP_BURST_LONG;
582 start_long[peer_nr] = GNUNET_TIME_absolute_get ();
583 long_test (tc_h);
584 }
585 else if (GNUNET_YES == phase_size[peer_nr])
586 {
587 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
588 "Choose phase size\n");
589 phase[peer_nr] = TP_SIZE_CHECK;
590 size_test (tc_h);
591 }
592 else
593 {
594 if ((0 == strcmp ("udp", communicator_name)) && ((0 == strcmp ("rekey",
595 test_name))
596 || (0 == strcmp (
597 "backchannel",
598 test_name))) )
599 {
600 LOG (GNUNET_ERROR_TYPE_DEBUG, "Getting statistics UDP...\n");
601 if (NULL != box_stats[peer_nr])
602 GNUNET_STATISTICS_get_cancel (box_stats[peer_nr]);
603 box_stats[peer_nr] = GNUNET_STATISTICS_get (stats[1],
604 "communicator-udp",
605 "# messages decrypted with BOX",
606 process_statistics_box_done,
607 &process_statistics,
608 tc_h);
609 if (NULL != rekey_stats[peer_nr])
610 GNUNET_STATISTICS_get_cancel (rekey_stats[peer_nr]);
611 rekey_stats[peer_nr] = GNUNET_STATISTICS_get (stats[1],
612 "communicator-udp",
613 "# rekeying successful",
614 process_statistics_rekey_done,
615 &process_statistics,
616 tc_h);
617 }
618 else if ((0 == strcmp ("tcp", communicator_name)) && (0 == strcmp ("rekey",
619 test_name)))
620 {
621 LOG (GNUNET_ERROR_TYPE_DEBUG, "Getting statistics... TCP\n");
622 if (NULL != box_stats[peer_nr])
623 GNUNET_STATISTICS_get_cancel (box_stats[peer_nr]);
624 box_stats[peer_nr] = GNUNET_STATISTICS_get (stats[1],
625 "communicator-tcp",
626 //"# messages decrypted with BOX",
627 NULL,
628 process_statistics_box_done,
629 &process_statistics,
630 tc_h);
631 if (NULL != rekey_stats[peer_nr])
632 GNUNET_STATISTICS_get_cancel (rekey_stats[peer_nr]);
633 rekey_stats[peer_nr] = GNUNET_STATISTICS_get (stats[1],
634 "communicator-tcp",
635 "# rekeying successful",
636 process_statistics_rekey_done,
637 &process_statistics,
638 tc_h);
639 }
640 else
641 {
642 if ((GNUNET_NO == bidirect) || (((PEER_A == peer_nr) &&
643 finished[PEER_B]) || ((PEER_B ==
644 peer_nr) &&
645 finished
646 [PEER_A])))
647 {
648 LOG (GNUNET_ERROR_TYPE_DEBUG,
649 "Finished\n");
650 GNUNET_SCHEDULER_shutdown ();
651 }
652 finished[peer_nr] = GNUNET_YES;
653 }
654 }
655}
656
657
658static void
659finish_phase_long (unsigned int peer_nr)
660{
661 static struct GNUNET_TIME_Relative duration;
662
663 duration = GNUNET_TIME_absolute_get_duration (start_long[peer_nr]);
664 LOG (GNUNET_ERROR_TYPE_MESSAGE,
665 "Long size packet test for peer %u done.\n",
666 peer_nr);
667 char *goodput = GNUNET_STRINGS_byte_size_fancy (
668 (long_message_size * num_received_long[peer_nr] * 1000 * 1000)
669 / duration.
670 rel_value_us);
671
672 LOG (GNUNET_ERROR_TYPE_MESSAGE,
673 "%lu/%lu packets in %llu us (%s/s) -- avg latency: %llu us\n",
674 (unsigned long) num_received_long[peer_nr],
675 (unsigned long) num_sent_long[peer_nr],
676 (unsigned long long) duration.rel_value_us,
677 goodput,
678 (unsigned long long) avg_latency[peer_nr]);
679 GNUNET_free (goodput);
680 ack[peer_nr] = 0;
681 // phase = TP_SIZE_CHECK;
682 // num_received = 0;
683 // num_sent_long = 0;
684 avg_latency[peer_nr] = 0;
685 // size_test (NULL);
686 phase_long[peer_nr] = GNUNET_NO;
687 choose_phase (get_tc_h (peer_nr));
688}
689
690
691static void
692finish_phase_short (unsigned int peer_nr)
693{
694 static struct GNUNET_TIME_Relative duration;
695
696 duration = GNUNET_TIME_absolute_get_duration (start_short[peer_nr]);
697 LOG (GNUNET_ERROR_TYPE_MESSAGE,
698 "Short size packet test for peer %u done.\n",
699 peer_nr);
700 char *goodput = GNUNET_STRINGS_byte_size_fancy (
701 (SHORT_MESSAGE_SIZE * num_received_short[peer_nr] * 1000 * 1000)
702 / duration.rel_value_us);
703 LOG (GNUNET_ERROR_TYPE_MESSAGE,
704 "%lu/%lu packets in %llu us (%s/s) -- avg latency: %llu us\n",
705 (unsigned long) num_received_short[peer_nr],
706 (unsigned long) num_sent_short[peer_nr],
707 (unsigned long long) duration.rel_value_us,
708 goodput,
709 (unsigned long long) avg_latency[peer_nr]);
710 GNUNET_free (goodput);
711 // start_long = GNUNET_TIME_absolute_get ();
712 // phase = TP_BURST_LONG;
713 // num_sent_short = 0;
714 avg_latency[peer_nr] = 0;
715 // num_received = 0;
716 phase_short[peer_nr] = GNUNET_NO;
717 choose_phase (get_tc_h (peer_nr));
718 // long_test (NULL);
719}
720
721
722static void
723latency_timeout (void *cls)
724{
725
726 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
727 unsigned int peer_nr;
728 size_t num_sent = 0;
729 size_t num_received = 0;
730
731 peer_nr = get_peer_nr_from_tc (tc_h);
732 to_task[peer_nr] = NULL;
733
734 switch (phase[peer_nr])
735 {
736 case TP_INIT:
737 GNUNET_assert (0);
738 break;
739 case TP_BURST_SHORT:
740 num_sent = num_sent_short[peer_nr];
741 num_received = num_received_short[peer_nr];
742 if ((num_sent_short[peer_nr] == burst_packets_short) &&
743 (num_received_short[peer_nr] >
744 burst_packets_short
745 / 100
746 *
747 allowed_packet_loss_short) )
748 {
749 finish_phase_short (peer_nr);
750 to_task[peer_nr] = GNUNET_SCHEDULER_add_at (timeout[peer_nr],
751 &latency_timeout,
752 cls);
753 return;
754 }
755 break;
756 case TP_BURST_LONG:
757 num_sent = num_sent_long[peer_nr];
758 num_received = num_received_long[peer_nr];
759 if ((num_sent_long[peer_nr] == burst_packets_long) &&
760 (num_received_long[peer_nr] >
761 burst_packets_long
762 / 100
763 *
764 allowed_packet_loss_long) )
765 {
766 finish_phase_long (peer_nr);
767 to_task[peer_nr] = GNUNET_SCHEDULER_add_at (timeout[peer_nr],
768 &latency_timeout,
769 cls);
770 return;
771 }
772 break;
773 case TP_SIZE_CHECK:
774 num_sent = num_sent_size[peer_nr];
775 num_received = num_received_size[peer_nr];
776 break;
777 }
778 if (GNUNET_TIME_absolute_get_remaining (timeout[peer_nr]).rel_value_us > 0)
779 {
780 to_task[peer_nr] = GNUNET_SCHEDULER_add_at (timeout[peer_nr],
781 &latency_timeout,
782 cls);
783 return;
784 }
785 LOG (GNUNET_ERROR_TYPE_ERROR,
786 "Latency too high. Test failed. (Phase: %d. Sent: %lu, Received: %lu)\n",
787 phase[peer_nr], num_sent, num_received);
788 ret = 2;
789 GNUNET_SCHEDULER_shutdown ();
790}
791
792
793/**
794 * @brief Handle opening of queue
795 *
796 * Issues sending of test data
797 *
798 * Implements #GNUNET_TRANSPORT_TESTING_AddQueueCallback
799 *
800 * @param cls Closure
801 * @param tc_h Communicator handle
802 * @param tc_queue Handle to newly opened queue
803 */
804static void
805add_queue_cb (void *cls,
806 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
807 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *
808 tc_queue,
809 size_t mtu)
810{
811
812 unsigned int peer_nr;
813
814 peer_nr = get_peer_nr (cls, GNUNET_NO);
815 LOG (GNUNET_ERROR_TYPE_DEBUG,
816 "Handle %p add %u %u\n",
817 tc_h,
818 peer_nr,
819 get_peer_nr_from_tc (tc_h));
820 if ((GNUNET_NO == bidirect) && (0 != strcmp ((char*) cls, cfg_peers_name[0])))
821 {
822 LOG (GNUNET_ERROR_TYPE_DEBUG,
823 "Queue available at receiving peer\n");
824 return; // TODO?
825 }
826 else if (TP_INIT != phase[peer_nr])
827 return;
828 LOG (GNUNET_ERROR_TYPE_DEBUG,
829 "Queue established, starting test...\n");
830 if (UINT16_MAX != mtu) /* Message header overhead */
831 long_message_size = mtu - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
832 - sizeof(struct GNUNET_MessageHeader);
833 else
834 long_message_size = LONG_MESSAGE_SIZE;
835 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
836 GNUNET_TIME_relative_multiply (
837 GNUNET_TIME_UNIT_SECONDS,
838 TIMEOUT_MULTIPLIER));
839 GNUNET_assert (NULL == to_task[peer_nr]);
840 to_task[peer_nr] = GNUNET_SCHEDULER_add_delayed (
841 GNUNET_TIME_relative_multiply (
842 GNUNET_TIME_UNIT_SECONDS,
843 TIMEOUT_MULTIPLIER),
844 &latency_timeout,
845 tc_h);
846 choose_phase (tc_h);
847}
848
849
850static void
851update_avg_latency (const char *payload, unsigned int peer_nr)
852{
853 struct GNUNET_TIME_AbsoluteNBO *ts_n;
854 struct GNUNET_TIME_Absolute ts;
855 struct GNUNET_TIME_Relative latency;
856 size_t num_received = 0;
857
858 ts_n = (struct GNUNET_TIME_AbsoluteNBO *) payload;
859 ts = GNUNET_TIME_absolute_ntoh (*ts_n);
860 latency = GNUNET_TIME_absolute_get_duration (ts);
861
862 switch (phase[peer_nr])
863 {
864 case TP_INIT:
865 GNUNET_assert (0);
866 break;
867 case TP_BURST_SHORT:
868 num_received = num_received_short[peer_nr];
869 break;
870 case TP_BURST_LONG:
871 num_received = num_received_long[peer_nr];
872 break;
873 case TP_SIZE_CHECK:
874 num_received = num_received_size[peer_nr];
875 break;
876 }
877 if (1 >= num_received)
878 avg_latency[peer_nr] = latency.rel_value_us;
879 else
880 avg_latency[peer_nr] = ((avg_latency[peer_nr] * (num_received - 1))
881 + latency.rel_value_us)
882 / num_received;
883 LOG (GNUNET_ERROR_TYPE_DEBUG,
884 "Latency of received packet by peer %u: %s with avg latency %" PRIu64
885 "\n",
886 peer_nr,
887 GNUNET_STRINGS_relative_time_to_string (latency,
888 GNUNET_YES),
889 avg_latency[peer_nr]);
890}
891
892
893static void
894load_phase_config ()
895{
896
897 phase_short[0] = GNUNET_CONFIGURATION_get_value_yesno (cfg_peers[0],
898 TEST_SECTION,
899 "PHASE_SHORT");
900 if (GNUNET_SYSERR == phase_short[0])
901 phase_short[0] = GNUNET_YES;
902
903 phase_short[1] = phase_short[0];
904
905 phase_long[0] = GNUNET_CONFIGURATION_get_value_yesno (cfg_peers[0],
906 TEST_SECTION,
907 "PHASE_LONG");
908
909 if (GNUNET_SYSERR == phase_long[0])
910 phase_long[0] = GNUNET_YES;
911
912 phase_long[1] = phase_long[0];
913
914 phase_size[0] = GNUNET_CONFIGURATION_get_value_yesno (cfg_peers[0],
915 TEST_SECTION,
916 "PHASE_SIZE");
917
918 if (GNUNET_SYSERR == phase_size[0])
919 phase_size[0] = GNUNET_YES;
920
921 phase_size[1] = phase_size[0];
922}
923
924
925/**
926 * @brief Handle an incoming message
927 *
928 * Implements #GNUNET_TRANSPORT_TESTING_IncomingMessageCallback
929
930 * @param cls Closure
931 * @param tc_h Handle to the receiving communicator
932 * @param msg Received message
933 */
934static void
935incoming_message_cb (
936 void *cls,
937 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
938 const char *payload,
939 size_t payload_len)
940{
941 unsigned int peer_nr;
942
943
944 peer_nr = get_peer_nr (cls, GNUNET_YES);
945
946 if ((GNUNET_NO == bidirect) && (0 != strcmp ((char*) cls,
947 cfg_peers_name[NUM_PEERS - 1])))
948 {
949 LOG (GNUNET_ERROR_TYPE_WARNING,
950 "unexpected receiver...\n");
951 return;
952 }
953 /* Reset timeout */
954 timeout[peer_nr] = GNUNET_TIME_relative_to_absolute (
955 GNUNET_TIME_relative_multiply (
956 GNUNET_TIME_UNIT_SECONDS,
957 TIMEOUT_MULTIPLIER));
958 switch (phase[peer_nr])
959 {
960 case TP_INIT:
961 GNUNET_break (0);
962 break;
963 case TP_BURST_SHORT:
964 {
965 GNUNET_assert (SHORT_MESSAGE_SIZE == payload_len);
966 num_received_short[peer_nr]++;
967
968 update_avg_latency (payload, peer_nr);
969 if ((num_sent_short[peer_nr] == burst_packets_short) &&
970 (num_received_short[peer_nr] ==
971 burst_packets_short))
972 {
973 finish_phase_short (peer_nr);
974 }
975 break;
976 }
977 case TP_BURST_LONG:
978 {
979 if (long_message_size != payload_len)
980 {
981 LOG (GNUNET_ERROR_TYPE_WARNING,
982 "Ignoring packet with wrong length (have: %lu, want: %lu)\n",
983 payload_len, long_message_size);
984 return; // Ignore
985 }
986 num_received_long[peer_nr]++;
987
988 update_avg_latency (payload, peer_nr);
989 if ((num_sent_long[peer_nr] == burst_packets_long) &&
990 (num_received_long[peer_nr] >
991 burst_packets_long))
992 {
993 finish_phase_long (peer_nr);
994 }
995 break;
996 }
997 case TP_SIZE_CHECK:
998 {
999 size_t max_size = 64000;
1000
1001 GNUNET_assert (TP_SIZE_CHECK == phase[peer_nr]);
1002 if (LONG_MESSAGE_SIZE != long_message_size)
1003 max_size = long_message_size;
1004 num_received_size[peer_nr]++;
1005 update_avg_latency (payload, peer_nr);
1006 if ((GNUNET_YES == phase_size[peer_nr]) && (num_received_size[peer_nr] >=
1007 (max_size) / 10) )
1008 {
1009 LOG (GNUNET_ERROR_TYPE_MESSAGE,
1010 "Size packet test for peer %u done.\n",
1011 peer_nr);
1012 LOG (GNUNET_ERROR_TYPE_MESSAGE,
1013 "%lu/%lu packets -- avg latency: %llu us\n",
1014 (unsigned long) num_received_size[peer_nr],
1015 (unsigned long) num_sent_size[peer_nr],
1016 (unsigned long long) avg_latency[peer_nr]);
1017 iterations_left[peer_nr]--;
1018 phase_size[peer_nr] = GNUNET_NO;
1019 if (0 != iterations_left[peer_nr])
1020 {
1021 // start_short = GNUNET_TIME_absolute_get ();
1022 // phase = TP_BURST_SHORT;
1023 num_received_size[peer_nr] = 0;
1024 num_sent_size[peer_nr] = 0;
1025 avg_latency[peer_nr] = 0;
1026 num_sent_short[peer_nr] = 0;
1027 num_sent_long[peer_nr] = 0;
1028 num_received_short[peer_nr] = 0;
1029 num_received_long[peer_nr] = 0;
1030 // short_test (NULL);
1031 if (((PEER_A == peer_nr) && finished[PEER_B]) || ((PEER_B ==
1032 peer_nr) &&
1033 finished[PEER_A]))
1034 {
1035 load_phase_config ();
1036 }
1037 }
1038 choose_phase (get_tc_h (peer_nr));
1039 }
1040 break;
1041 }
1042 }
1043}
1044
1045
1046static void
1047do_shutdown (void *cls)
1048{
1049 LOG (GNUNET_ERROR_TYPE_DEBUG,
1050 "shutting down test.\n");
1051
1052 for (unsigned int i = 0; i < NUM_PEERS; i++)
1053 {
1054 if (NULL != box_stats[i])
1055 {
1056 GNUNET_STATISTICS_get_cancel (box_stats[i]);
1057 box_stats[i] = NULL;
1058 }
1059 if (NULL != rekey_stats[i])
1060 {
1061 GNUNET_STATISTICS_get_cancel (rekey_stats[i]);
1062 rekey_stats[i] = NULL;
1063 }
1064 if (NULL != to_task[i])
1065 {
1066 GNUNET_SCHEDULER_cancel (to_task[i]);
1067 to_task[i] = NULL;
1068 }
1069 GNUNET_STATISTICS_destroy (stats[i], GNUNET_YES);
1070 GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (tc_hs[i]);
1071 }
1072}
1073
1074
1075/**
1076 * @brief Main function called by the scheduler
1077 *
1078 * @param cls Closure - Handle to confiation
1079 */
1080static void
1081run (void *cls)
1082{
1083 ret = 0;
1084 // num_received = 0;
1085 // num_sent = 0;
1086 for (unsigned int i = 0; i < NUM_PEERS; i++)
1087 {
1088 tc_hs[i] = GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
1089 "transport",
1090 communicator_binary,
1091 cfg_peers_name[i],
1092 &peer_id[i],
1093 &communicator_available_cb,
1094 &add_address_cb,
1095 &queue_create_reply_cb,
1096 &add_queue_cb,
1097 &incoming_message_cb,
1098 &handle_backchannel_cb,
1099 cfg_peers_name[i]); /* cls */
1100
1101 if ((0 == strcmp ("udp", communicator_name)) && ((0 == strcmp ("rekey",
1102 test_name))
1103 ||
1104 (0 == strcmp (
1105 "backchannel",
1106 test_name))) )
1107 {
1108 stats[i] = GNUNET_STATISTICS_create ("communicator-udp",
1109 cfg_peers[i]);
1110 }
1111 else if ((0 == strcmp ("tcp", communicator_name)) && (0 == strcmp ("rekey",
1112 test_name)))
1113 {
1114 stats[i] = GNUNET_STATISTICS_create ("communicator-tcp",
1115 cfg_peers[i]);
1116 }
1117 else if ((0 == strcmp ("bidirect", test_name)))
1118 {
1119 bidirect = GNUNET_YES;
1120 }
1121 }
1122 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
1123 NULL);
1124}
1125
1126
1127int
1128main (int argc,
1129 char *const *argv)
1130{
1131 struct GNUNET_CRYPTO_EddsaPrivateKey *private_key;
1132 char *test_mode;
1133 char *cfg_peer;
1134
1135 iterations_left[0] = TOTAL_ITERATIONS;
1136 iterations_left[1] = TOTAL_ITERATIONS;
1137 phase[0] = TP_INIT;
1138 phase[1] = TP_INIT;
1139 ret = 1;
1140 test_name = GNUNET_STRINGS_get_suffix_from_binary_name (argv[0]);
1141 communicator_name = strchr (test_name, '-');
1142 communicator_name[0] = '\0';
1143 communicator_name++;
1144 test_mode = test_name;
1145
1146 GNUNET_asprintf (&communicator_binary,
1147 "gnunet-communicator-%s",
1148 communicator_name);
1149
1150 if (GNUNET_OK !=
1151 GNUNET_log_setup ("test_communicator_basic",
1152 "DEBUG",
1153 NULL))
1154 {
1155 fprintf (stderr, "Unable to setup log\n");
1156 GNUNET_break (0);
1157 return 2;
1158 }
1159 for (unsigned int i = 0; i < NUM_PEERS; i++)
1160 {
1161 GNUNET_asprintf ((&cfg_peer),
1162 "test_communicator_%s_%s_peer%u.conf",
1163 communicator_name, test_mode, i + 1);
1164 cfg_peers_name[i] = cfg_peer;
1165 cfg_peers[i] = GNUNET_CONFIGURATION_create ();
1166 if (GNUNET_YES ==
1167 GNUNET_DISK_file_test (cfg_peers_name[i]))
1168 {
1169 if (GNUNET_SYSERR ==
1170 GNUNET_CONFIGURATION_load (cfg_peers[i],
1171 cfg_peers_name[i]))
1172 {
1173 fprintf (stderr,
1174 "Malformed configuration file `%s', exiting ...\n",
1175 cfg_peers_name[i]);
1176 return 1;
1177 }
1178 }
1179 else
1180 {
1181 if (GNUNET_SYSERR ==
1182 GNUNET_CONFIGURATION_load (cfg_peers[i],
1183 NULL))
1184 {
1185 fprintf (stderr,
1186 "Configuration file %s does not exist, exiting ...\n",
1187 cfg_peers_name[i]);
1188 return 1;
1189 }
1190 }
1191 private_key =
1192 GNUNET_CRYPTO_eddsa_key_create_from_configuration (cfg_peers[i]);
1193 if (NULL == private_key)
1194 {
1195 LOG (GNUNET_ERROR_TYPE_ERROR,
1196 "Unable to get peer ID\n");
1197 return 1;
1198 }
1199 GNUNET_CRYPTO_eddsa_key_get_public (private_key,
1200 &peer_id[i].public_key);
1201 GNUNET_free (private_key);
1202 LOG (GNUNET_ERROR_TYPE_INFO,
1203 "Identity of peer %u is %s\n",
1204 i,
1205 GNUNET_i2s_full (&peer_id[i]));
1206 }
1207 if (GNUNET_OK !=
1208 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1209 TEST_SECTION,
1210 "ALLOWED_PACKET_LOSS_SHORT",
1211 &allowed_packet_loss_short))
1212 allowed_packet_loss_short = ALLOWED_PACKET_LOSS;
1213 if (GNUNET_OK !=
1214 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1215 TEST_SECTION,
1216 "ALLOWED_PACKET_LOSS_LONG",
1217 &allowed_packet_loss_long))
1218 allowed_packet_loss_long = ALLOWED_PACKET_LOSS;
1219 if (GNUNET_OK !=
1220 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1221 TEST_SECTION,
1222 "BURST_PACKETS_SHORT",
1223 &burst_packets_short))
1224 burst_packets_short = BURST_PACKETS;
1225 if (GNUNET_OK !=
1226 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1227 TEST_SECTION,
1228 "BURST_PACKETS_LONG",
1229 &burst_packets_long))
1230 burst_packets_long = BURST_PACKETS;
1231 if (GNUNET_OK !=
1232 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1233 TEST_SECTION,
1234 "DELAY_SHORT",
1235 &delay_short_value))
1236 delay_short = DEFAULT_DELAY;
1237 else
1238 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,
1239 delay_short_value);
1240 if (GNUNET_OK !=
1241 GNUNET_CONFIGURATION_get_value_number (cfg_peers[0],
1242 TEST_SECTION,
1243 "DELAY_SHORT",
1244 &delay_long_value))
1245 delay_long = DEFAULT_DELAY;
1246 else
1247 GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS,
1248 delay_long_value);
1249 load_phase_config ();
1250 LOG (GNUNET_ERROR_TYPE_MESSAGE, "Starting test...\n");
1251 LOG (GNUNET_ERROR_TYPE_DEBUG,
1252 "argv[0]: %s\n",
1253 argv[0]);
1254 LOG (GNUNET_ERROR_TYPE_DEBUG,
1255 "test_name: %s\n",
1256 test_name);
1257 LOG (GNUNET_ERROR_TYPE_DEBUG,
1258 "communicator_name: %s\n",
1259 communicator_name);
1260 LOG (GNUNET_ERROR_TYPE_DEBUG,
1261 "communicator_binary: %s\n",
1262 communicator_binary);
1263 GNUNET_SCHEDULER_run (&run,
1264 NULL);
1265 return ret;
1266}
diff --git a/src/service/transport/test_communicator_quic_basic_peer1.conf b/src/service/transport/test_communicator_quic_basic_peer1.conf
new file mode 100644
index 000000000..d43752ecc
--- /dev/null
+++ b/src/service/transport/test_communicator_quic_basic_peer1.conf
@@ -0,0 +1,45 @@
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-quic]
16PORT = 52402
17
18[transport]
19#PORT = 60000
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_1.sock
21
22[nat]
23UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/nat.sock
24ENABLE_IPSCAN = YES
25
26[peerstore]
27UNIXPATH = $GNUNET_TMP/test-communicator-unix-1/peerstore.sock
28
29[statistics]
30PORT = 22461
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_1.sock
32
33[resolver]
34PORT = 62089
35UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_1.sock
36
37[communicator-udp]
38# PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/vg_com1
39BINDTO = 60002
40DISABLE_V6 = YES
41MAX_QUEUE_LENGTH=5000
42
43[communicator-quic]
44BINDTO = 60002
45DISABLE_V6 = YES
diff --git a/src/service/transport/test_communicator_quic_basic_peer2.conf b/src/service/transport/test_communicator_quic_basic_peer2.conf
new file mode 100644
index 000000000..4fabc8a86
--- /dev/null
+++ b/src/service/transport/test_communicator_quic_basic_peer2.conf
@@ -0,0 +1,45 @@
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[transport-tcp]
10PORT = 52400
11
12[transport-udp]
13PORT = 52402
14
15[transport-quic]
16PORT = 52403
17
18[transport]
19#PORT = 60001
20UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport_test_2.sock
21
22[nat]
23UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/nat.sock
24
25
26[peerstore]
27UNIXPATH = $GNUNET_TMP/test-communicator-unix-2/peerstore.sock
28
29[statistics]
30PORT = 22462
31UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-statistics_test_2.sock
32
33[resolver]
34PORT = 62090
35UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-resolver_test_2.sock
36
37[communicator-udp]
38# PREFIX = valgrind --leak-check=full --track-origins=yes --log-file=/tmp/vg_com2
39BINDTO = 60003
40DISABLE_V6 = YES
41MAX_QUEUE_LENGTH=5000
42
43[communicator-quic]
44BINDTO = 60003
45DISABLE_V6 = YES \ No newline at end of file
diff --git a/src/service/transport/test_communicator_tcp_basic_peer1.conf b/src/service/transport/test_communicator_tcp_basic_peer1.conf
new file mode 100644
index 000000000..dbc227ac6
--- /dev/null
+++ b/src/service/transport/test_communicator_tcp_basic_peer1.conf
@@ -0,0 +1,48 @@
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/service/transport/test_communicator_tcp_basic_peer2.conf b/src/service/transport/test_communicator_tcp_basic_peer2.conf
new file mode 100644
index 000000000..b73157f0d
--- /dev/null
+++ b/src/service/transport/test_communicator_tcp_basic_peer2.conf
@@ -0,0 +1,44 @@
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/service/transport/test_communicator_tcp_bidirect_peer1.conf b/src/service/transport/test_communicator_tcp_bidirect_peer1.conf
new file mode 100644
index 000000000..dbc227ac6
--- /dev/null
+++ b/src/service/transport/test_communicator_tcp_bidirect_peer1.conf
@@ -0,0 +1,48 @@
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/service/transport/test_communicator_tcp_bidirect_peer2.conf b/src/service/transport/test_communicator_tcp_bidirect_peer2.conf
new file mode 100644
index 000000000..b73157f0d
--- /dev/null
+++ b/src/service/transport/test_communicator_tcp_bidirect_peer2.conf
@@ -0,0 +1,44 @@
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/service/transport/test_communicator_tcp_rekey_peer1.conf b/src/service/transport/test_communicator_tcp_rekey_peer1.conf
new file mode 100644
index 000000000..82fbf353a
--- /dev/null
+++ b/src/service/transport/test_communicator_tcp_rekey_peer1.conf
@@ -0,0 +1,45 @@
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/service/transport/test_communicator_tcp_rekey_peer2.conf b/src/service/transport/test_communicator_tcp_rekey_peer2.conf
new file mode 100644
index 000000000..086a996ae
--- /dev/null
+++ b/src/service/transport/test_communicator_tcp_rekey_peer2.conf
@@ -0,0 +1,45 @@
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/service/transport/test_communicator_udp_backchannel_peer1.conf b/src/service/transport/test_communicator_udp_backchannel_peer1.conf
new file mode 100644
index 000000000..65f33bd6b
--- /dev/null
+++ b/src/service/transport/test_communicator_udp_backchannel_peer1.conf
@@ -0,0 +1,48 @@
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 --log-file=/tmp/vg_comm1
43BINDTO = 60002
44DISABLE_V6 = YES
45MAX_QUEUE_LENGTH=5000
46
47[communicator-test]
48BACKCHANNEL_ENABLED = YES
diff --git a/src/service/transport/test_communicator_udp_backchannel_peer2.conf b/src/service/transport/test_communicator_udp_backchannel_peer2.conf
new file mode 100644
index 000000000..9875af724
--- /dev/null
+++ b/src/service/transport/test_communicator_udp_backchannel_peer2.conf
@@ -0,0 +1,48 @@
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 --log-file=/tmp/vg_comm2
43BINDTO = 60003
44DISABLE_V6 = YES
45MAX_QUEUE_LENGTH=5000
46
47[communicator-test]
48BACKCHANNEL_ENABLED = YES
diff --git a/src/service/transport/test_communicator_udp_basic_peer1.conf b/src/service/transport/test_communicator_udp_basic_peer1.conf
new file mode 100644
index 000000000..83c599ae5
--- /dev/null
+++ b/src/service/transport/test_communicator_udp_basic_peer1.conf
@@ -0,0 +1,40 @@
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 --log-file=/tmp/vg_com1
36#PREFIX = valgrind --tool=callgrind
37BINDTO = 60002
38DISABLE_V6 = YES
39MAX_QUEUE_LENGTH=5000
40
diff --git a/src/service/transport/test_communicator_udp_basic_peer2.conf b/src/service/transport/test_communicator_udp_basic_peer2.conf
new file mode 100644
index 000000000..781bfa7da
--- /dev/null
+++ b/src/service/transport/test_communicator_udp_basic_peer2.conf
@@ -0,0 +1,39 @@
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 --log-file=/tmp/vg_com2
37BINDTO = 60003
38DISABLE_V6 = YES
39MAX_QUEUE_LENGTH=5000
diff --git a/src/service/transport/test_communicator_udp_rekey_peer1.conf b/src/service/transport/test_communicator_udp_rekey_peer1.conf
new file mode 100644
index 000000000..305dd3b84
--- /dev/null
+++ b/src/service/transport/test_communicator_udp_rekey_peer1.conf
@@ -0,0 +1,53 @@
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
45#PREFIX = valgrind --tool=callgrind
46BINDTO = 60002
47DISABLE_V6 = YES
48MAX_QUEUE_LENGTH=5000
49REKEY_INTERVAL = 100ms
50REKEY_MAX_BYTES=500KiB
51
52[communicator-test]
53BACKCHANNEL_ENABLED = YES
diff --git a/src/service/transport/test_communicator_udp_rekey_peer2.conf b/src/service/transport/test_communicator_udp_rekey_peer2.conf
new file mode 100644
index 000000000..9bce572aa
--- /dev/null
+++ b/src/service/transport/test_communicator_udp_rekey_peer2.conf
@@ -0,0 +1,52 @@
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_INTERVAL = 100ms
49REKEY_MAX_BYTES=500KiB
50
51[communicator-test]
52BACKCHANNEL_ENABLED = YES
diff --git a/src/service/transport/test_communicator_unix_basic_peer1.conf b/src/service/transport/test_communicator_unix_basic_peer1.conf
new file mode 100644
index 000000000..13ba2d16b
--- /dev/null
+++ b/src/service/transport/test_communicator_unix_basic_peer1.conf
@@ -0,0 +1,43 @@
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/service/transport/test_communicator_unix_basic_peer2.conf b/src/service/transport/test_communicator_unix_basic_peer2.conf
new file mode 100644
index 000000000..727e844a7
--- /dev/null
+++ b/src/service/transport/test_communicator_unix_basic_peer2.conf
@@ -0,0 +1,43 @@
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/service/transport/test_delay b/src/service/transport/test_delay
new file mode 100755
index 000000000..5f82b65fb
--- /dev/null
+++ b/src/service/transport/test_delay
@@ -0,0 +1,19 @@
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/service/transport/test_plugin_hostkey b/src/service/transport/test_plugin_hostkey
new file mode 100644
index 000000000..e7b1ad012
--- /dev/null
+++ b/src/service/transport/test_plugin_hostkey
Binary files differ
diff --git a/src/service/transport/test_plugin_hostkey.ecc b/src/service/transport/test_plugin_hostkey.ecc
new file mode 100644
index 000000000..18641b798
--- /dev/null
+++ b/src/service/transport/test_plugin_hostkey.ecc
@@ -0,0 +1 @@
‚”ˆÖ’ÛËy¢/HÒc ȃ§¿±;¼»f?¶@…~áJ \ No newline at end of file
diff --git a/src/service/transport/test_tng_defaults.conf b/src/service/transport/test_tng_defaults.conf
new file mode 100644
index 000000000..81dbb5bd7
--- /dev/null
+++ b/src/service/transport/test_tng_defaults.conf
@@ -0,0 +1,14 @@
1@INLINE@ ../../../contrib/conf/gnunet/no_forcestart.conf
2
3[PATHS]
4GNUNET_TEST_HOME = $GNUNET_TMP/test-tng/
5
6[transport]
7# PREFIX = valgrind
8
9[nat]
10DISABLEV6 = NO
11RETURN_LOCAL_ADDRESSES = YES
12BINDTO = 127.0.0.1
13INTERNAL_ADDRESS = 127.0.0.1
14EXTERNAL_ADDRESS = 127.0.0.1
diff --git a/src/service/transport/test_transport_address_switch.c b/src/service/transport/test_transport_address_switch.c
new file mode 100644
index 000000000..ce5117bd1
--- /dev/null
+++ b/src/service/transport/test_transport_address_switch.c
@@ -0,0 +1,433 @@
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/service/transport/test_transport_address_switch_tcp_peer1.conf b/src/service/transport/test_transport_address_switch_tcp_peer1.conf
new file mode 100644
index 000000000..cfcbfe41c
--- /dev/null
+++ b/src/service/transport/test_transport_address_switch_tcp_peer1.conf
@@ -0,0 +1,48 @@
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/service/transport/test_transport_address_switch_tcp_peer2.conf b/src/service/transport/test_transport_address_switch_tcp_peer2.conf
new file mode 100644
index 000000000..bda2354b6
--- /dev/null
+++ b/src/service/transport/test_transport_address_switch_tcp_peer2.conf
@@ -0,0 +1,48 @@
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/service/transport/test_transport_address_switch_udp_peer1.conf b/src/service/transport/test_transport_address_switch_udp_peer1.conf
new file mode 100644
index 000000000..bdc3a2253
--- /dev/null
+++ b/src/service/transport/test_transport_address_switch_udp_peer1.conf
@@ -0,0 +1,48 @@
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/service/transport/test_transport_address_switch_udp_peer2.conf b/src/service/transport/test_transport_address_switch_udp_peer2.conf
new file mode 100644
index 000000000..ae6397db4
--- /dev/null
+++ b/src/service/transport/test_transport_address_switch_udp_peer2.conf
@@ -0,0 +1,48 @@
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/service/transport/test_transport_api.c b/src/service/transport/test_transport_api.c
new file mode 100644
index 000000000..5f5e03a9e
--- /dev/null
+++ b/src/service/transport/test_transport_api.c
@@ -0,0 +1,126 @@
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/service/transport/test_transport_api2.c b/src/service/transport/test_transport_api2.c
new file mode 100644
index 000000000..4d423f7c2
--- /dev/null
+++ b/src/service/transport/test_transport_api2.c
@@ -0,0 +1,126 @@
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/service/transport/test_transport_api2_tcp_node1.conf b/src/service/transport/test_transport_api2_tcp_node1.conf
new file mode 100644
index 000000000..463ec61d8
--- /dev/null
+++ b/src/service/transport/test_transport_api2_tcp_node1.conf
@@ -0,0 +1,35 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6BINARY = gnunet-service-transport
7PLUGINS = tcp
8#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_peer1-%p
9UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p1.sock
10
11[PEER]
12PRIVATE_KEY = $GNUNET_RUNTIME_DIR/private.key
13
14[communicator-tcp]
15BINARY = gnunet-communicator-tcp
16BINDTO = 192.168.15.1:60002
17DISABLE_V6 = YES
18IMMEDIATE_START = YES
19UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p1.sock
20#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_ctpeer1-%p
21#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
22
23[communicator-udp]
24#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_cupeer1-%p
25BINARY = gnunet-communicator-udp
26BINDTO = 192.168.15.1:60002
27DISABLE_V6 = YES
28IMMEDIATE_START = YES
29UNIXPATH = $GNUNET_RUNTIME_DIR/udp-comm-p1.sock
30
31[peerstore]
32IMMEDIATE_START = YES
33
34#[transport]
35#PREFIX = valgrind
diff --git a/src/service/transport/test_transport_api2_tcp_node2.conf b/src/service/transport/test_transport_api2_tcp_node2.conf
new file mode 100644
index 000000000..b7f92869e
--- /dev/null
+++ b/src/service/transport/test_transport_api2_tcp_node2.conf
@@ -0,0 +1,22 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6BINARY = gnunet-service-transport
7#PREFIX = valgrind --log-file=$GNUNET_TEST_HOME/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=$GNUNET_TEST_HOME/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/service/transport/test_transport_api2_tcp_peer1.conf b/src/service/transport/test_transport_api2_tcp_peer1.conf
new file mode 100644
index 000000000..54ec9fd9f
--- /dev/null
+++ b/src/service/transport/test_transport_api2_tcp_peer1.conf
@@ -0,0 +1,23 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6BINARY = gnunet-service-transport
7PLUGINS = tcp
8#PREFIX = valgrind --log-file=$GNUNET_TEST_HOME/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=$GNUNET_TEST_HOME/vg_cpeer1-%p
18
19[peerstore]
20IMMEDIATE_START = YES
21
22#[transport]
23#PREFIX = valgrind
diff --git a/src/service/transport/test_transport_api2_tcp_peer2.conf b/src/service/transport/test_transport_api2_tcp_peer2.conf
new file mode 100644
index 000000000..7ae5ac697
--- /dev/null
+++ b/src/service/transport/test_transport_api2_tcp_peer2.conf
@@ -0,0 +1,22 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p2/
4
5[transport]
6BINARY = gnunet-service-transport
7#PREFIX = valgrind --log-file=$GNUNET_TEST_HOME/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=$GNUNET_TEST_HOME/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/service/transport/test_transport_api2_tng_node.conf b/src/service/transport/test_transport_api2_tng_node.conf
new file mode 100644
index 000000000..c50ccf662
--- /dev/null
+++ b/src/service/transport/test_transport_api2_tng_node.conf
@@ -0,0 +1,40 @@
1@INLINE@ template_tng_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-tcp-p1/
4
5[transport]
6BINARY = gnunet-service-transport
7#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_peer1-%p
8UNIXPATH = $GNUNET_RUNTIME_DIR/tng-p1.sock
9
10[PEER]
11PRIVATE_KEY = $GNUNET_RUNTIME_DIR/private.key
12
13[communicator-tcp]
14BINARY = gnunet-communicator-tcp
15BINDTO = 192.168.15.1:60002
16DISABLE_V6 = YES
17IMMEDIATE_START = YES
18UNIXPATH = $GNUNET_RUNTIME_DIR/tcp-comm-p1.sock
19#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_ctpeer1-%p
20#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
21
22[communicator-udp]
23#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_cupeer1-%p
24BINARY = gnunet-communicator-udp
25BINDTO = 192.168.15.1:60002
26DISABLE_V6 = YES
27IMMEDIATE_START = YES
28UNIXPATH = $GNUNET_RUNTIME_DIR/udp-comm-p1.sock
29
30[peerstore]
31IMMEDIATE_START = YES
32
33[topology]
34IMMEDIATE_START = YES
35
36[dht]
37IMMEDIATE_START = YES
38
39[fs]
40IMMEDIATE_START = YES
diff --git a/src/service/transport/test_transport_api_data.conf b/src/service/transport/test_transport_api_data.conf
new file mode 100644
index 000000000..c06235a0a
--- /dev/null
+++ b/src/service/transport/test_transport_api_data.conf
@@ -0,0 +1,9 @@
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/service/transport/test_transport_api_monitor_peers.c b/src/service/transport/test_transport_api_monitor_peers.c
new file mode 100644
index 000000000..c09e3782d
--- /dev/null
+++ b/src/service/transport/test_transport_api_monitor_peers.c
@@ -0,0 +1,226 @@
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/service/transport/test_transport_api_monitor_peers_peer1.conf b/src/service/transport/test_transport_api_monitor_peers_peer1.conf
new file mode 100644
index 000000000..bc9eee19b
--- /dev/null
+++ b/src/service/transport/test_transport_api_monitor_peers_peer1.conf
@@ -0,0 +1,4 @@
1@INLINE@ template_cfg_peer1.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-monitoring-p1/
4
diff --git a/src/service/transport/test_transport_api_monitor_peers_peer2.conf b/src/service/transport/test_transport_api_monitor_peers_peer2.conf
new file mode 100644
index 000000000..5225a5a87
--- /dev/null
+++ b/src/service/transport/test_transport_api_monitor_peers_peer2.conf
@@ -0,0 +1,5 @@
1@INLINE@ template_cfg_peer2.conf
2[PATHS]
3GNUNET_TEST_HOME = $GNUNET_TMP/test-transport/api-monitoring-p2/
4
5
diff --git a/src/service/transport/test_transport_api_monitor_validation_peer1.conf b/src/service/transport/test_transport_api_monitor_validation_peer1.conf
new file mode 100644
index 000000000..02f7bc2f0
--- /dev/null
+++ b/src/service/transport/test_transport_api_monitor_validation_peer1.conf
@@ -0,0 +1,6 @@
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/service/transport/test_transport_api_monitor_validation_peer2.conf b/src/service/transport/test_transport_api_monitor_validation_peer2.conf
new file mode 100644
index 000000000..d4e0874f0
--- /dev/null
+++ b/src/service/transport/test_transport_api_monitor_validation_peer2.conf
@@ -0,0 +1,7 @@
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/service/transport/test_transport_api_multi_peer1.conf b/src/service/transport/test_transport_api_multi_peer1.conf
new file mode 100644
index 000000000..b7cb98777
--- /dev/null
+++ b/src/service/transport/test_transport_api_multi_peer1.conf
@@ -0,0 +1,7 @@
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/service/transport/test_transport_api_multi_peer2.conf b/src/service/transport/test_transport_api_multi_peer2.conf
new file mode 100644
index 000000000..f69e0abd9
--- /dev/null
+++ b/src/service/transport/test_transport_api_multi_peer2.conf
@@ -0,0 +1,9 @@
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/service/transport/test_transport_api_tcp_nat_peer1.conf b/src/service/transport/test_transport_api_tcp_nat_peer1.conf
new file mode 100644
index 000000000..fb2fcecc6
--- /dev/null
+++ b/src/service/transport/test_transport_api_tcp_nat_peer1.conf
@@ -0,0 +1,34 @@
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/service/transport/test_transport_api_tcp_nat_peer2.conf b/src/service/transport/test_transport_api_tcp_nat_peer2.conf
new file mode 100644
index 000000000..1faefc195
--- /dev/null
+++ b/src/service/transport/test_transport_api_tcp_nat_peer2.conf
@@ -0,0 +1,32 @@
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/service/transport/test_transport_api_tcp_peer1.conf b/src/service/transport/test_transport_api_tcp_peer1.conf
new file mode 100644
index 000000000..eabd6b701
--- /dev/null
+++ b/src/service/transport/test_transport_api_tcp_peer1.conf
@@ -0,0 +1,9 @@
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/service/transport/test_transport_api_tcp_peer2.conf b/src/service/transport/test_transport_api_tcp_peer2.conf
new file mode 100644
index 000000000..58ce0777f
--- /dev/null
+++ b/src/service/transport/test_transport_api_tcp_peer2.conf
@@ -0,0 +1,9 @@
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/service/transport/test_transport_api_udp_nat_peer1.conf b/src/service/transport/test_transport_api_udp_nat_peer1.conf
new file mode 100644
index 000000000..7bbcaa628
--- /dev/null
+++ b/src/service/transport/test_transport_api_udp_nat_peer1.conf
@@ -0,0 +1,34 @@
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/service/transport/test_transport_api_udp_nat_peer2.conf b/src/service/transport/test_transport_api_udp_nat_peer2.conf
new file mode 100644
index 000000000..8bdb8c293
--- /dev/null
+++ b/src/service/transport/test_transport_api_udp_nat_peer2.conf
@@ -0,0 +1,32 @@
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/service/transport/test_transport_api_udp_peer1.conf b/src/service/transport/test_transport_api_udp_peer1.conf
new file mode 100644
index 000000000..4684b77f2
--- /dev/null
+++ b/src/service/transport/test_transport_api_udp_peer1.conf
@@ -0,0 +1,17 @@
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/service/transport/test_transport_api_udp_peer2.conf b/src/service/transport/test_transport_api_udp_peer2.conf
new file mode 100644
index 000000000..96706ce49
--- /dev/null
+++ b/src/service/transport/test_transport_api_udp_peer2.conf
@@ -0,0 +1,15 @@
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/service/transport/test_transport_api_unix_peer1.conf b/src/service/transport/test_transport_api_unix_peer1.conf
new file mode 100644
index 000000000..005558bcc
--- /dev/null
+++ b/src/service/transport/test_transport_api_unix_peer1.conf
@@ -0,0 +1,10 @@
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/service/transport/test_transport_api_unix_peer2.conf b/src/service/transport/test_transport_api_unix_peer2.conf
new file mode 100644
index 000000000..840ed81c7
--- /dev/null
+++ b/src/service/transport/test_transport_api_unix_peer2.conf
@@ -0,0 +1,7 @@
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/service/transport/test_transport_defaults.conf b/src/service/transport/test_transport_defaults.conf
new file mode 100644
index 000000000..03e7addec
--- /dev/null
+++ b/src/service/transport/test_transport_defaults.conf
@@ -0,0 +1,20 @@
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/service/transport/test_transport_distance_vector_circle_topo.conf b/src/service/transport/test_transport_distance_vector_circle_topo.conf
new file mode 100644
index 000000000..e8d694c3a
--- /dev/null
+++ b/src/service/transport/test_transport_distance_vector_circle_topo.conf
@@ -0,0 +1,11 @@
1M:1
2N:3
3X:0
4B:0
5T:libgnunet_test_transport_plugin_cmd_simple_send_dv
6R:1|{tcp_port:0}|{udp_port:1}
7R:2|{tcp_port:0}|{udp_port:1}
8R:3|{tcp_port:0}|{udp_port:1}
9P:1:1|{connect:{P:2:1:udp}}
10P:2:1|{connect:{P:3:1:udp}}
11P:3:1|{connect:{P:1:1:udp}}
diff --git a/src/service/transport/test_transport_distance_vector_inverse_topo.conf b/src/service/transport/test_transport_distance_vector_inverse_topo.conf
new file mode 100644
index 000000000..e062b3e2e
--- /dev/null
+++ b/src/service/transport/test_transport_distance_vector_inverse_topo.conf
@@ -0,0 +1,13 @@
1M:1
2N:4
3X:0
4AC:1
5T:libgnunet_test_transport_plugin_cmd_simple_send_dv
6R:1|{tcp_port:1}|{udp_port:0}
7R:2|{tcp_port:1}|{udp_port:0}
8R:3|{tcp_port:1}|{udp_port:0}
9R:4|{tcp_port:1}|{udp_port:0}
10P:1:1|{connect:{P:2:1:tcp}}|{AC:2}
11P:2:1|{connect:{P:3:1:tcp}}|{AC:2}
12P:3:1|{connect:{P:4:1:tcp}}|{AC:2}
13P:4:1|{AC:3} \ No newline at end of file
diff --git a/src/service/transport/test_transport_distance_vector_topo.conf b/src/service/transport/test_transport_distance_vector_topo.conf
new file mode 100644
index 000000000..ead3e0a0a
--- /dev/null
+++ b/src/service/transport/test_transport_distance_vector_topo.conf
@@ -0,0 +1,8 @@
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/service/transport/test_transport_just_run_topo.conf b/src/service/transport/test_transport_just_run_topo.conf
new file mode 100644
index 000000000..d27a2fc77
--- /dev/null
+++ b/src/service/transport/test_transport_just_run_topo.conf
@@ -0,0 +1,6 @@
1M:2
2N:1
3X:0
4T:libgnunet_test_transport_plugin_cmd_just_run
5P:1:1|{connect:{P:1:2:tcp}|{P:1:2:udp}}
6P:1:2|{connect:{P:1:1:tcp}|{P:1:1:udp}} \ No newline at end of file
diff --git a/src/service/transport/test_transport_nat_icmp_tcp.sh b/src/service/transport/test_transport_nat_icmp_tcp.sh
new file mode 100755
index 000000000..41cdde487
--- /dev/null
+++ b/src/service/transport/test_transport_nat_icmp_tcp.sh
@@ -0,0 +1,12 @@
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_nat_icmp_tcp_topo.conf"
12#sudo valgrind --vgdb=yes --leak-check=full --track-origins=yes --trace-children=yes --trace-children-skip=/usr/bin/awk,/usr/bin/cut,/usr/bin/seq,/sbin/ip/sed/bash ./test_transport_start_with_config test_transport_nat_upnp_topo.conf
diff --git a/src/service/transport/test_transport_nat_icmp_tcp_topo.conf b/src/service/transport/test_transport_nat_icmp_tcp_topo.conf
new file mode 100644
index 000000000..37738c80f
--- /dev/null
+++ b/src/service/transport/test_transport_nat_icmp_tcp_topo.conf
@@ -0,0 +1,7 @@
1M:1
2N:1
3X:1
4T:libgnunet_test_transport_plugin_cmd_nat_upnp
5K:1|{connect:{P:1:1:tcp_natted}}
6R:1|{tcp_port:0}|{udp_port:0}
7P:1:1 \ No newline at end of file
diff --git a/src/service/transport/test_transport_nat_upnp.sh b/src/service/transport/test_transport_nat_upnp.sh
new file mode 100755
index 000000000..df43ef320
--- /dev/null
+++ b/src/service/transport/test_transport_nat_upnp.sh
@@ -0,0 +1,12 @@
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_nat_upnp_topo.conf"
12#sudo valgrind --vgdb=yes --leak-check=full --track-origins=yes --trace-children=yes --trace-children-skip=/usr/bin/awk,/usr/bin/cut,/usr/bin/seq,/sbin/ip/sed/bash ./test_transport_start_with_config test_transport_nat_upnp_topo.conf
diff --git a/src/service/transport/test_transport_nat_upnp_topo.conf b/src/service/transport/test_transport_nat_upnp_topo.conf
new file mode 100644
index 000000000..e02633d4b
--- /dev/null
+++ b/src/service/transport/test_transport_nat_upnp_topo.conf
@@ -0,0 +1,7 @@
1M:1
2N:1
3X:1
4T:libgnunet_test_transport_plugin_cmd_nat_upnp
5K:1|{connect:{P:1:1:tcp}}
6R:1|{tcp_port:0}|{udp_port:0}|{script:upnp.sh}
7P:1:1|{connect:{K:1:udp}} \ No newline at end of file
diff --git a/src/service/transport/test_transport_plugin_cmd_just_run.c b/src/service/transport/test_transport_plugin_cmd_just_run.c
new file mode 100644
index 000000000..df7484884
--- /dev/null
+++ b/src/service/transport/test_transport_plugin_cmd_just_run.c
@@ -0,0 +1,494 @@
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_barrier.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#include "gnunet_testing_barrier.h"
34#include "gnunet_core_service.h"
35
36/**
37 * Generic logging shortcut
38 */
39#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
40
41#define BASE_DIR "testdir"
42
43#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
44
45#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
46
47#define MAX_RECEIVED 1000
48
49#define MESSAGE_SIZE 65000
50
51static struct GNUNET_TESTING_Command block_script;
52
53static struct GNUNET_TESTING_Command connect_peers;
54
55static struct GNUNET_TESTING_Command local_prepared;
56
57static struct GNUNET_TESTING_Command start_peer;
58
59static struct GNUNET_TESTING_Interpreter *is;
60
61static struct GNUNET_CONTAINER_MultiPeerMap *senders;
62
63struct Sender
64{
65 /**
66 * Number of received messages from sender.
67 */
68 unsigned long long num_received;
69
70 /**
71 * Sample mean time the message traveled.
72 */
73 struct GNUNET_TIME_Relative mean_time;
74
75 /**
76 * Time the first message was send.
77 */
78 struct GNUNET_TIME_Absolute time_first;
79};
80
81/**
82 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
83 * received.
84 *
85 */
86static int
87check_test (void *cls,
88 const struct
89 GNUNET_TRANSPORT_TESTING_PerformanceTestMessage *message)
90{
91 return GNUNET_OK;
92}
93
94
95struct GNUNET_TESTING_BarrierList*
96get_waiting_for_barriers ()
97{
98 struct GNUNET_TESTING_BarrierList*barriers;
99 struct GNUNET_TESTING_BarrierListEntry *ble;
100
101 barriers = GNUNET_new (struct GNUNET_TESTING_BarrierList);
102 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
103 ble->barrier_name = "ready-to-connect";
104 ble->expected_reaches = 1;
105 GNUNET_CONTAINER_DLL_insert (barriers->head,
106 barriers->tail,
107 ble);
108
109 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
110 ble->barrier_name = "test-case-finished";
111 ble->expected_reaches = 1;
112 GNUNET_CONTAINER_DLL_insert (barriers->head,
113 barriers->tail,
114 ble);
115 return barriers;
116}
117
118
119/**
120 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
121 *
122 */
123static void
124all_peers_started ()
125{
126}
127
128
129/**
130 * Function called with the final result of the test.
131 *
132 * @param cls the `struct MainParams`
133 * @param rv #GNUNET_OK if the test passed
134 */
135static void
136handle_result (void *cls,
137 enum GNUNET_GenericReturnValue rv)
138{
139 struct TestState *ts = cls;
140
141 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
142 "Local test exits with status %d\n",
143 rv);
144
145 ts->finished_cb (rv);
146 GNUNET_free (ts->testdir);
147 GNUNET_free (ts->cfgname);
148 GNUNET_TESTING_free_topology (ts->topology);
149 GNUNET_free (ts);
150}
151
152
153/**
154 * Callback from start peer cmd for signaling a peer got connected.
155 *
156 *
157static void *
158notify_connect (struct GNUNET_TESTING_Interpreter *is,
159 const struct GNUNET_PeerIdentity *peer)
160{
161 const struct ConnectPeersState *cps;
162 const struct GNUNET_TESTING_Command *cmd;
163
164 cmd = GNUNET_TESTING_interpreter_lookup_command (is,
165 "connect-peers");
166 GNUNET_TRANSPORT_get_trait_connect_peer_state (cmd,
167 &cps);
168 void *ret = NULL;
169
170 cps->notify_connect (is,
171 peer);
172 return ret;
173 }*/
174
175
176/**
177 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
178 */
179static void
180all_local_tests_prepared ()
181{
182 const struct GNUNET_TESTING_LocalPreparedState *lfs;
183
184 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
185 &lfs);
186 GNUNET_assert (NULL != &lfs->ac);
187 if (NULL == lfs->ac.cont)
188 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
189 else
190 GNUNET_TESTING_async_finish ((struct
191 GNUNET_TESTING_AsyncContext *) &lfs->ac);
192}
193
194
195static void
196child_completed_callback (void *cls,
197 enum GNUNET_OS_ProcessStatusType type,
198 long unsigned int exit_code)
199{
200
201}
202
203
204/**
205 * Function called to check a message being
206 * received.
207 *
208 */
209static int
210check_encrypted (void *cls, struct GNUNET_MessageHeader *header)
211{
212 return GNUNET_OK;
213}
214
215
216static void
217core_receive_continue (struct GNUNET_PeerIdentity *peer)
218{
219 const struct GNUNET_TESTING_StartPeerState *sps;
220
221 GNUNET_TRANSPORT_get_trait_state (&start_peer,
222 &sps);
223
224 LOG (GNUNET_ERROR_TYPE_DEBUG,
225 "Executing core receive continue\n");
226
227 GNUNET_TRANSPORT_core_receive_continue (sps->th, peer);
228}
229
230
231/*static void
232handle_core (void *cls, struct GNUNET_MessageHeader *header)
233{
234 struct GNUNET_PeerIdentity *peer = cls;
235
236 core_receive_continue (peer);
237 }*/
238
239
240/**
241 * Function called to handle a message being received.
242 *
243 */
244static void
245handle_encrypted (void *cls, struct GNUNET_MessageHeader *header)
246{
247 struct GNUNET_PeerIdentity *peer = cls;
248
249 core_receive_continue (peer);
250}
251
252
253static void
254handle_ephemeral_key (void *cls, struct GNUNET_MessageHeader *header)
255{
256 struct GNUNET_PeerIdentity *peer = cls;
257
258 core_receive_continue (peer);
259}
260
261
262static void
263handle_ping (void *cls, struct GNUNET_MessageHeader *header)
264{
265 struct GNUNET_PeerIdentity *peer = cls;
266
267 core_receive_continue (peer);
268}
269
270
271static void
272handle_pong (void *cls, struct GNUNET_MessageHeader *header)
273{
274 struct GNUNET_PeerIdentity *peer = cls;
275
276 core_receive_continue (peer);
277}
278
279/**
280 * Function to start a local test case.
281 *
282 * @param write_message Callback to send a message to the master loop.
283 * @param router_ip Global address of the network namespace.
284 * @param node_ip The IP address of the node.
285 * @param m The number of the node in a network namespace.
286 * @param n The number of the network namespace.
287 * @param local_m The number of nodes in a network namespace.
288 * @param topology_data A file name for the file containing the topology configuration, or a string containing
289 * the topology configuration.
290 * @param read_file If read_file is GNUNET_YES this string is the filename for the topology configuration,
291 * if read_file is GNUNET_NO the string contains the topology configuration.
292 * @param finish_cb Callback function which writes a message from the helper process running on a netjail
293 * node to the master process * signaling that the test case running on the netjail node finished.
294 * @return Returns the struct GNUNET_TESTING_Interpreter of the command loop running on this netjail node.
295 */
296static struct GNUNET_TESTING_Interpreter *
297start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
298 const char *router_ip,
299 const char *node_ip,
300 const char *m,
301 const char *n,
302 const char *local_m,
303 const char *topology_data,
304 unsigned int *read_file,
305 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
306{
307
308 unsigned int n_int;
309 unsigned int m_int;
310 unsigned int local_m_int;
311 unsigned int num;
312 struct TestState *ts = GNUNET_new (struct TestState);
313 struct GNUNET_TESTING_NetjailTopology *topology;
314 unsigned int sscanf_ret = 0;
315 char **argv = NULL;
316 int argc = 0;
317
318 ts->finished_cb = finished_cb;
319 LOG (GNUNET_ERROR_TYPE_ERROR,
320 "n %s m %s\n",
321 n,
322 m);
323
324 if (GNUNET_YES == *read_file)
325 {
326 LOG (GNUNET_ERROR_TYPE_DEBUG,
327 "read from file\n");
328 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
329 }
330 else
331 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
332
333 ts->topology = topology;
334
335 errno = 0;
336 sscanf_ret = sscanf (m, "%u", &m_int);
337 if (errno != 0)
338 {
339 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
340 }
341 GNUNET_assert (0 < sscanf_ret);
342 errno = 0;
343 sscanf_ret = sscanf (n, "%u", &n_int);
344 if (errno != 0)
345 {
346 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
347 }
348 GNUNET_assert (0 < sscanf_ret);
349 errno = 0;
350 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
351 if (errno != 0)
352 {
353 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
354 }
355 GNUNET_assert (0 < sscanf_ret);
356
357 if (0 == n_int)
358 num = m_int;
359 else
360 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
361
362 block_script = GNUNET_TESTING_cmd_block_until_external_trigger (
363 "block-script");
364 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
365 "start-peer",
366 "system-create",
367 num,
368 topology,
369 0,
370 GNUNET_NO);
371 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
372 "local-test-prepared",
373 write_message);
374
375
376 GNUNET_asprintf (&ts->cfgname,
377 "test_transport_api2_tcp_node1.conf");
378
379 LOG (GNUNET_ERROR_TYPE_DEBUG,
380 "plugin cfgname: %s\n",
381 ts->cfgname);
382
383 LOG (GNUNET_ERROR_TYPE_DEBUG,
384 "node ip: %s\n",
385 node_ip);
386
387 GNUNET_asprintf (&ts->testdir,
388 "%s%s%s",
389 BASE_DIR,
390 m,
391 n);
392
393 /*struct GNUNET_MQ_MessageHandler handlers[] = {
394 GNUNET_MQ_hd_fixed_size (ephemeral_key,
395 GNUNET_MESSAGE_TYPE_CORE_EPHEMERAL_KEY,
396 struct EphemeralKeyMessage,
397 NULL),
398 GNUNET_MQ_hd_fixed_size (ping,
399 GNUNET_MESSAGE_TYPE_CORE_PING,
400 struct PingMessage,
401 NULL),
402 GNUNET_MQ_hd_fixed_size (pong,
403 GNUNET_MESSAGE_TYPE_CORE_PONG,
404 struct PongMessage,
405 NULL),
406 GNUNET_MQ_handler_end ()
407 };*/
408
409 start_peer = GNUNET_TESTING_cmd_start_peer ("start-peer",
410 "system-create",
411 num,
412 node_ip,
413 ts->cfgname,
414 GNUNET_NO);
415
416 struct GNUNET_TESTING_Command commands[] = {
417 GNUNET_TESTING_cmd_system_create ("system-create",
418 ts->testdir),
419 start_peer,
420 GNUNET_TESTING_cmd_barrier_reached ("ready-to-connect-reached",
421 "ready-to-connect",
422 GNUNET_NO,
423 num,
424 GNUNET_NO,
425 write_message),
426 connect_peers,
427 GNUNET_TESTING_cmd_exec_bash_script ("script",
428 "block.sh",
429 argv,
430 argc,
431 &child_completed_callback),
432 block_script,
433 GNUNET_TESTING_cmd_barrier_reached ("test-case-finished-reached",
434 "test-case-finished",
435 GNUNET_NO,
436 num,
437 GNUNET_NO,
438 write_message),
439 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
440 "start-peer"),
441 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
442 "system-create"),
443 GNUNET_TESTING_cmd_end ()
444 };
445
446 ts->write_message = write_message;
447
448 is = GNUNET_TESTING_run (commands,
449 TIMEOUT,
450 &handle_result,
451 ts);
452 return is;
453}
454
455
456/**
457 * Entry point for the plugin.
458 *
459 * @param cls NULL
460 * @return the exported block API
461 */
462void *
463libgnunet_test_transport_plugin_cmd_just_run_init (void *cls)
464{
465 struct GNUNET_TESTING_PluginFunctions *api;
466
467 GNUNET_log_setup ("simple-send",
468 "DEBUG",
469 NULL);
470
471 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
472 api->start_testcase = &start_testcase;
473 api->get_waiting_for_barriers = get_waiting_for_barriers;
474 return api;
475}
476
477
478/**
479 * Exit point from the plugin.
480 *
481 * @param cls the return value from #libgnunet_test_transport_plugin_just_run_init
482 * @return NULL
483 */
484void *
485libgnunet_test_transport_plugin_cmd_just_run_done (void *cls)
486{
487 struct GNUNET_TESTING_PluginFunctions *api = cls;
488
489 GNUNET_free (api);
490 return NULL;
491}
492
493
494/* end of plugin_cmd_simple_send.c */
diff --git a/src/service/transport/test_transport_plugin_cmd_nat_upnp.c b/src/service/transport/test_transport_plugin_cmd_nat_upnp.c
new file mode 100644
index 000000000..01e3e8b72
--- /dev/null
+++ b/src/service/transport/test_transport_plugin_cmd_nat_upnp.c
@@ -0,0 +1,368 @@
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_barrier.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#include "gnunet_testing_barrier.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40#define BASE_DIR "testdir"
41
42#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
43
44#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
45
46static struct GNUNET_TESTING_Command block_send;
47
48static struct GNUNET_TESTING_Command block_receive;
49
50static struct GNUNET_TESTING_Command connect_peers;
51
52static struct GNUNET_TESTING_Command local_prepared;
53
54static struct GNUNET_TESTING_Interpreter *is;
55
56/**
57 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
58 * received.
59 *
60 */
61static int
62check_test (void *cls,
63 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
64{
65 return GNUNET_OK;
66}
67
68
69/**
70 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
71 * being received.
72 *
73 */
74static void
75handle_test (void *cls,
76 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
77{
78 struct GNUNET_TESTING_AsyncContext *ac;
79
80 GNUNET_TESTING_get_trait_async_context (&block_receive,
81 &ac);
82 GNUNET_assert (NULL != ac);
83 if (NULL == ac->cont)
84 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
85 else
86 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
87}
88
89
90struct GNUNET_TESTING_BarrierList*
91get_waiting_for_barriers ()
92{
93 struct GNUNET_TESTING_BarrierList*barriers;
94 struct GNUNET_TESTING_BarrierListEntry *ble;
95
96 barriers = GNUNET_new (struct GNUNET_TESTING_BarrierList);
97 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
98 ble->barrier_name = "ready-to-connect";
99 ble->expected_reaches = 1;
100 GNUNET_CONTAINER_DLL_insert (barriers->head,
101 barriers->tail,
102 ble);
103
104 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
105 ble->barrier_name = "test-case-finished";
106 ble->expected_reaches = 1;
107 GNUNET_CONTAINER_DLL_insert (barriers->head,
108 barriers->tail,
109 ble);
110 return barriers;
111}
112
113
114/**
115 * Function called with the final result of the test.
116 *
117 * @param cls the `struct MainParams`
118 * @param rv #GNUNET_OK if the test passed
119 */
120static void
121handle_result (void *cls,
122 enum GNUNET_GenericReturnValue rv)
123{
124 struct TestState *ts = cls;
125
126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
127 "Local test exits with status %d\n",
128 rv);
129
130 ts->finished_cb (rv);
131 GNUNET_free (ts->testdir);
132 GNUNET_free (ts->cfgname);
133 GNUNET_TESTING_free_topology (ts->topology);
134 GNUNET_free (ts);
135}
136
137
138/**
139 * Callback from start peer cmd for signaling a peer got connected.
140 *
141 */
142static void *
143notify_connect (struct GNUNET_TESTING_Interpreter *is,
144 const struct GNUNET_PeerIdentity *peer)
145{
146 const struct ConnectPeersState *cps;
147 const struct GNUNET_TESTING_Command *cmd;
148
149 cmd = GNUNET_TESTING_interpreter_lookup_command (is,
150 "connect-peers");
151 GNUNET_TRANSPORT_TESTING_get_trait_connect_peer_state (cmd,
152 &cps);
153 void *ret = NULL;
154
155 cps->notify_connect (is,
156 peer);
157 return ret;
158}
159
160
161/**
162 * Function to start a local test case.
163 *
164 * @param write_message Callback to send a message to the master loop.
165 * @param router_ip Global address of the network namespace.
166 * @param node_ip The IP address of the node.
167 * @param m The number of the node in a network namespace.
168 * @param n The number of the network namespace.
169 * @param local_m The number of nodes in a network namespace.
170 * @param topology_data A file name for the file containing the topology configuration, or a string containing
171 * the topology configuration.
172 * @param read_file If read_file is GNUNET_YES this string is the filename for the topology configuration,
173 * if read_file is GNUNET_NO the string contains the topology configuration.
174 * @param finish_cb Callback function which writes a message from the helper process running on a netjail
175 * node to the master process * signaling that the test case running on the netjail node finished.
176 * @return Returns the struct GNUNET_TESTING_Interpreter of the command loop running on this netjail node.
177 */
178static struct GNUNET_TESTING_Interpreter *
179start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
180 const char *router_ip,
181 const char *node_ip,
182 const char *m,
183 const char *n,
184 const char *local_m,
185 const char *topology_data,
186 unsigned int *read_file,
187 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
188{
189
190 unsigned int n_int;
191 unsigned int m_int;
192 unsigned int local_m_int;
193 unsigned int num;
194 struct TestState *ts = GNUNET_new (struct TestState);
195 struct GNUNET_TESTING_NetjailTopology *topology;
196 unsigned int sscanf_ret = 0;
197
198 ts->finished_cb = finished_cb;
199 LOG (GNUNET_ERROR_TYPE_ERROR,
200 "n %s m %s\n",
201 n,
202 m);
203
204 if (GNUNET_YES == *read_file)
205 {
206 LOG (GNUNET_ERROR_TYPE_DEBUG,
207 "read from file\n");
208 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
209 }
210 else
211 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
212
213 ts->topology = topology;
214
215 errno = 0;
216 sscanf_ret = sscanf (m, "%u", &m_int);
217 if (errno != 0)
218 {
219 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
220 }
221 GNUNET_assert (0 < sscanf_ret);
222 errno = 0;
223 sscanf_ret = sscanf (n, "%u", &n_int);
224 if (errno != 0)
225 {
226 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
227 }
228 GNUNET_assert (0 < sscanf_ret);
229 errno = 0;
230 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
231 if (errno != 0)
232 {
233 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
234 }
235 GNUNET_assert (0 < sscanf_ret);
236
237 if (0 == n_int)
238 num = m_int;
239 else
240 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
241
242 block_send = GNUNET_TESTING_cmd_block_until_external_trigger (
243 "block");
244 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
245 "block-receive");
246 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
247 "start-peer",
248 "system-create",
249 num,
250 topology,
251 0,
252 GNUNET_YES);
253 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
254 "local-test-prepared",
255 write_message);
256
257
258 GNUNET_asprintf (&ts->cfgname,
259 "test_transport_api2_tcp_node1.conf");
260
261 LOG (GNUNET_ERROR_TYPE_DEBUG,
262 "plugin cfgname: %s\n",
263 ts->cfgname);
264
265 LOG (GNUNET_ERROR_TYPE_DEBUG,
266 "node ip: %s\n",
267 node_ip);
268
269 GNUNET_asprintf (&ts->testdir,
270 "%s%s%s",
271 BASE_DIR,
272 m,
273 n);
274
275 struct GNUNET_MQ_MessageHandler handlers[] = {
276 GNUNET_MQ_hd_var_size (test,
277 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
278 struct GNUNET_TRANSPORT_TESTING_TestMessage,
279 ts),
280 GNUNET_MQ_handler_end ()
281 };
282
283 struct GNUNET_TESTING_Command commands[] = {
284 GNUNET_TESTING_cmd_system_create ("system-create",
285 ts->testdir),
286 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
287 "system-create",
288 num,
289 node_ip,
290 handlers,
291 ts->cfgname,
292 notify_connect,
293 GNUNET_NO),
294 GNUNET_TESTING_cmd_barrier_reached ("ready-to-connect-reached",
295 "ready-to-connect",
296 GNUNET_NO,
297 num,
298 GNUNET_NO,
299 write_message),
300 connect_peers,
301 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
302 "start-peer",
303 "system-create",
304 num,
305 topology),
306 block_receive,
307 GNUNET_TESTING_cmd_barrier_reached ("test-case-finished-reached",
308 "test-case-finished",
309 GNUNET_NO,
310 num,
311 GNUNET_NO,
312 write_message),
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 is = GNUNET_TESTING_run (commands,
323 TIMEOUT,
324 &handle_result,
325 ts);
326 return is;
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_nat_upnp_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->get_waiting_for_barriers = get_waiting_for_barriers;
348 return api;
349}
350
351
352/**
353 * Exit point from the plugin.
354 *
355 * @param cls the return value from #libgnunet_test_transport_plugin_nat_upnp_init
356 * @return NULL
357 */
358void *
359libgnunet_test_transport_plugin_cmd_nat_upnp_done (void *cls)
360{
361 struct GNUNET_TESTING_PluginFunctions *api = cls;
362
363 GNUNET_free (api);
364 return NULL;
365}
366
367
368/* end of plugin_cmd_simple_send.c */
diff --git a/src/service/transport/test_transport_plugin_cmd_simple_send.c b/src/service/transport/test_transport_plugin_cmd_simple_send.c
new file mode 100644
index 000000000..efef49826
--- /dev/null
+++ b/src/service/transport/test_transport_plugin_cmd_simple_send.c
@@ -0,0 +1,377 @@
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_barrier.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#include "gnunet_testing_barrier.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40#define BASE_DIR "testdir"
41
42#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
43
44#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
45
46static struct GNUNET_TESTING_Command block_send;
47
48static struct GNUNET_TESTING_Command block_receive;
49
50static struct GNUNET_TESTING_Command connect_peers;
51
52static struct GNUNET_TESTING_Command local_prepared;
53
54static struct GNUNET_TESTING_Interpreter *is;
55
56/**
57 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
58 * received.
59 *
60 */
61static int
62check_test (void *cls,
63 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
64{
65 return GNUNET_OK;
66}
67
68
69/**
70 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
71 * being received.
72 *
73 */
74static void
75handle_test (void *cls,
76 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
77{
78 struct GNUNET_TESTING_AsyncContext *ac;
79
80 GNUNET_TESTING_get_trait_async_context (&block_receive,
81 &ac);
82 GNUNET_assert (NULL != ac);
83 if (NULL == ac->cont)
84 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
85 else
86 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
87}
88
89
90struct GNUNET_TESTING_BarrierList *
91get_waiting_for_barriers ()
92{
93 // No Barrier
94 return GNUNET_new (struct GNUNET_TESTING_BarrierList);
95}
96
97
98/**
99 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
100 *
101 */
102static void
103all_peers_started ()
104{
105 struct GNUNET_TESTING_AsyncContext *ac;
106
107 GNUNET_TESTING_get_trait_async_context (&block_send,
108 &ac);
109 GNUNET_assert (NULL != ac);
110 if (NULL == ac->cont)
111 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
112 else
113 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
114}
115
116
117/**
118 * Function called with the final result of the test.
119 *
120 * @param cls the `struct MainParams`
121 * @param rv #GNUNET_OK if the test passed
122 */
123static void
124handle_result (void *cls,
125 enum GNUNET_GenericReturnValue rv)
126{
127 struct TestState *ts = cls;
128
129 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
130 "Local test exits with status %d\n",
131 rv);
132
133 ts->finished_cb (rv);
134 GNUNET_free (ts->testdir);
135 GNUNET_free (ts->cfgname);
136 GNUNET_TESTING_free_topology (ts->topology);
137 GNUNET_free (ts);
138}
139
140
141/**
142 * Callback from start peer cmd for signaling a peer got connected.
143 *
144 */
145static void *
146notify_connect (struct GNUNET_TESTING_Interpreter *is,
147 const struct GNUNET_PeerIdentity *peer)
148{
149 const struct ConnectPeersState *cps;
150 const struct GNUNET_TESTING_Command *cmd;
151
152 cmd = GNUNET_TESTING_interpreter_lookup_command (is,
153 "connect-peers");
154 GNUNET_TRANSPORT_TESTING_get_trait_connect_peer_state (cmd,
155 &cps);
156 void *ret = NULL;
157
158 cps->notify_connect (is,
159 peer);
160 return ret;
161}
162
163
164/**
165 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
166 */
167static void
168all_local_tests_prepared ()
169{
170 const struct GNUNET_TESTING_LocalPreparedState *lfs;
171
172 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
173 &lfs);
174 GNUNET_assert (NULL != &lfs->ac);
175 if (NULL == lfs->ac.cont)
176 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
177 else
178 GNUNET_TESTING_async_finish ((struct
179 GNUNET_TESTING_AsyncContext *) &lfs->ac);
180}
181
182
183/**
184 * Function to start a local test case.
185 *
186 * @param write_message Callback to send a message to the master loop.
187 * @param router_ip Global address of the network namespace.
188 * @param node_ip The IP address of the node.
189 * @param m The number of the node in a network namespace.
190 * @param n The number of the network namespace.
191 * @param local_m The number of nodes in a network namespace.
192 */
193static struct GNUNET_TESTING_Interpreter *
194start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
195 const char *router_ip,
196 const char *node_ip,
197 const char *m,
198 const char *n,
199 const char *local_m,
200 const char *topology_data,
201 unsigned int *read_file,
202 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
203{
204
205 unsigned int n_int;
206 unsigned int m_int;
207 unsigned int local_m_int;
208 unsigned int num;
209 struct TestState *ts = GNUNET_new (struct TestState);
210 struct GNUNET_TESTING_NetjailTopology *topology;
211 unsigned int sscanf_ret = 0;
212
213 ts->finished_cb = finished_cb;
214 LOG (GNUNET_ERROR_TYPE_ERROR,
215 "n %s m %s\n",
216 n,
217 m);
218
219 if (GNUNET_YES == *read_file)
220 {
221 LOG (GNUNET_ERROR_TYPE_DEBUG,
222 "read from file\n");
223 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
224 }
225 else
226 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
227
228 ts->topology = topology;
229
230 errno = 0;
231 sscanf_ret = sscanf (m, "%u", &m_int);
232 if (errno != 0)
233 {
234 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
235 }
236 GNUNET_assert (0 < sscanf_ret);
237 errno = 0;
238 sscanf_ret = sscanf (n, "%u", &n_int);
239 if (errno != 0)
240 {
241 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
242 }
243 GNUNET_assert (0 < sscanf_ret);
244 errno = 0;
245 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
246 if (errno != 0)
247 {
248 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
249 }
250 GNUNET_assert (0 < sscanf_ret);
251
252 if (0 == n_int)
253 num = m_int;
254 else
255 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
256
257 block_send = GNUNET_TESTING_cmd_block_until_external_trigger (
258 "block");
259 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
260 "block-receive");
261 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
262 "start-peer",
263 "system-create",
264 num,
265 topology,
266 0,
267 GNUNET_YES);
268 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
269 "local-test-prepared",
270 write_message);
271
272
273 GNUNET_asprintf (&ts->cfgname,
274 "test_transport_api2_tcp_node1.conf");
275
276 LOG (GNUNET_ERROR_TYPE_DEBUG,
277 "plugin cfgname: %s\n",
278 ts->cfgname);
279
280 LOG (GNUNET_ERROR_TYPE_DEBUG,
281 "node ip: %s\n",
282 node_ip);
283
284 GNUNET_asprintf (&ts->testdir,
285 "%s%s%s",
286 BASE_DIR,
287 m,
288 n);
289
290 struct GNUNET_MQ_MessageHandler handlers[] = {
291 GNUNET_MQ_hd_var_size (test,
292 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
293 struct GNUNET_TRANSPORT_TESTING_TestMessage,
294 ts),
295 GNUNET_MQ_handler_end ()
296 };
297
298 struct GNUNET_TESTING_Command commands[] = {
299 GNUNET_TESTING_cmd_system_create ("system-create",
300 ts->testdir),
301 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
302 "system-create",
303 num,
304 node_ip,
305 handlers,
306 ts->cfgname,
307 notify_connect,
308 GNUNET_NO),
309 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
310 write_message),
311 block_send,
312 connect_peers,
313 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
314 "start-peer",
315 "system-create",
316 num,
317 topology),
318 block_receive,
319 local_prepared,
320 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
321 "start-peer"),
322 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
323 "system-create"),
324 GNUNET_TESTING_cmd_end ()
325 };
326
327 ts->write_message = write_message;
328
329 is = GNUNET_TESTING_run (commands,
330 TIMEOUT,
331 &handle_result,
332 ts);
333 return is;
334}
335
336
337/**
338 * Entry point for the plugin.
339 *
340 * @param cls NULL
341 * @return the exported block API
342 */
343void *
344libgnunet_test_transport_plugin_cmd_simple_send_init (void *cls)
345{
346 struct GNUNET_TESTING_PluginFunctions *api;
347
348 GNUNET_log_setup ("simple-send",
349 "DEBUG",
350 NULL);
351
352 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
353 api->start_testcase = &start_testcase;
354 api->all_peers_started = &all_peers_started;
355 api->all_local_tests_prepared = all_local_tests_prepared;
356 api->get_waiting_for_barriers = get_waiting_for_barriers;
357 return api;
358}
359
360
361/**
362 * Exit point from the plugin.
363 *
364 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
365 * @return NULL
366 */
367void *
368libgnunet_test_transport_plugin_cmd_simple_send_done (void *cls)
369{
370 struct GNUNET_TESTING_PluginFunctions *api = cls;
371
372 GNUNET_free (api);
373 return NULL;
374}
375
376
377/* end of plugin_cmd_simple_send.c */
diff --git a/src/service/transport/test_transport_plugin_cmd_simple_send_broadcast.c b/src/service/transport/test_transport_plugin_cmd_simple_send_broadcast.c
new file mode 100644
index 000000000..62f7d820f
--- /dev/null
+++ b/src/service/transport/test_transport_plugin_cmd_simple_send_broadcast.c
@@ -0,0 +1,399 @@
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_barrier.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#include "gnunet_testing_barrier.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40#define BASE_DIR "testdir"
41
42#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
43
44#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
45
46static struct GNUNET_TESTING_Command block_send;
47
48static struct GNUNET_TESTING_Command block_receive;
49
50static struct GNUNET_TESTING_Command connect_peers;
51
52static struct GNUNET_TESTING_Command local_prepared;
53
54static struct GNUNET_TESTING_Interpreter *is;
55
56/**
57 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
58 * received.
59 *
60 */
61static int
62check_test (void *cls,
63 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
64{
65 return GNUNET_OK;
66}
67
68
69/**
70 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
71 * being received.
72 *
73 */
74static void
75handle_test (void *cls,
76 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
77{
78 struct GNUNET_TESTING_AsyncContext *ac;
79
80 GNUNET_TESTING_get_trait_async_context (&block_receive,
81 &ac);
82 GNUNET_assert (NULL != ac);
83 if ((GNUNET_NO == ac->finished) && (NULL == ac->cont))
84 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
85 else if (GNUNET_NO == ac->finished)
86 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
87}
88
89
90struct GNUNET_TESTING_BarrierList *
91get_waiting_for_barriers ()
92{
93 // No Barrier
94 return GNUNET_new (struct GNUNET_TESTING_BarrierList);
95}
96
97
98/**
99 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
100 *
101 */
102static void
103all_peers_started ()
104{
105 struct GNUNET_TESTING_AsyncContext *ac;
106
107 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
108 "Received message\n");
109 GNUNET_TESTING_get_trait_async_context (&block_send,
110 &ac);
111 GNUNET_assert (NULL != ac);
112 if (NULL == ac->cont)
113 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
114 else
115 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
116}
117
118
119/**
120 * Function called with the final result of the test.
121 *
122 * @param cls the `struct MainParams`
123 * @param rv #GNUNET_OK if the test passed
124 */
125static void
126handle_result (void *cls,
127 enum GNUNET_GenericReturnValue rv)
128{
129 struct TestState *ts = cls;
130
131 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
132 "Local test exits with status %d\n",
133 rv);
134 ts->finished_cb (rv);
135 GNUNET_free (ts->testdir);
136 GNUNET_free (ts->cfgname);
137 GNUNET_TESTING_free_topology (ts->topology);
138 GNUNET_free (ts);
139}
140
141
142/**
143 * Callback from start peer cmd for signaling a peer got connected.
144 *
145 */
146static void *
147notify_connect (struct GNUNET_TESTING_Interpreter *is,
148 const struct GNUNET_PeerIdentity *peer)
149{
150 struct GNUNET_TESTING_AsyncContext *ac;
151 void *ret = NULL;
152 const struct GNUNET_TESTING_Command *cmd;
153 struct GNUNET_TESTING_BlockState *bs;
154
155 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
156 "notify_connect\n");
157 GNUNET_TESTING_get_trait_async_context (&connect_peers,
158 &ac);
159 if (NULL != ac->is)
160 {
161 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
162 "notify_connect running\n");
163 GNUNET_assert (NULL != ac);
164 if (NULL == ac->cont)
165 GNUNET_TESTING_async_fail (ac);
166 else
167 GNUNET_TESTING_async_finish (ac);
168 }
169 else
170 {
171 cmd = GNUNET_TESTING_interpreter_lookup_future_command (is,
172 "connect-peers");
173 LOG (GNUNET_ERROR_TYPE_DEBUG,
174 "block state %s\n",
175 cmd->label.value);
176 GNUNET_TESTING_get_trait_block_state (
177 cmd,
178 &bs);
179
180 LOG (GNUNET_ERROR_TYPE_DEBUG,
181 "block state %u\n",
182 bs->asynchronous_finish);
183 bs->asynchronous_finish = GNUNET_YES;
184 LOG (GNUNET_ERROR_TYPE_DEBUG,
185 "block state %u\n",
186 bs->asynchronous_finish);
187 }
188
189 return ret;
190}
191
192
193/**
194 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
195 */
196static void
197all_local_tests_prepared ()
198{
199 const struct GNUNET_TESTING_LocalPreparedState *lfs;
200
201 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
202 &lfs);
203 GNUNET_assert (NULL != &lfs->ac);
204 if (NULL == lfs->ac.cont)
205 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
206 else
207 GNUNET_TESTING_async_finish ((struct
208 GNUNET_TESTING_AsyncContext *) &lfs->ac);
209}
210
211
212/**
213 * Function to start a local test case.
214 *
215 * @param write_message Callback to send a message to the master loop.
216 * @param router_ip Global address of the network namespace.
217 * @param node_ip The IP address of the node.
218 * @param m The number of the node in a network namespace.
219 * @param n The number of the network namespace.
220 * @param local_m The number of nodes in a network namespace.
221 */
222static struct GNUNET_TESTING_Interpreter *
223start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
224 const char *router_ip,
225 const char *node_ip,
226 const char *m,
227 const char *n,
228 const char *local_m,
229 const char *topology_data,
230 unsigned int *read_file,
231 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
232{
233 unsigned int n_int;
234 unsigned int m_int;
235 unsigned int local_m_int;
236 unsigned int num;
237 struct TestState *ts = GNUNET_new (struct TestState);
238 struct GNUNET_TESTING_NetjailTopology *topology;
239 unsigned int sscanf_ret = 0;
240
241 ts->finished_cb = finished_cb;
242 LOG (GNUNET_ERROR_TYPE_ERROR,
243 "n %s m %s\n",
244 n,
245 m);
246
247 if (GNUNET_YES == *read_file)
248 {
249 LOG (GNUNET_ERROR_TYPE_DEBUG,
250 "read from file\n");
251 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
252 }
253 else
254 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
255
256 ts->topology = topology;
257
258 errno = 0;
259 sscanf_ret = sscanf (m, "%u", &m_int);
260 if (errno != 0)
261 {
262 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
263 }
264 GNUNET_assert (0 < sscanf_ret);
265 errno = 0;
266 sscanf_ret = sscanf (n, "%u", &n_int);
267 if (errno != 0)
268 {
269 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
270 }
271 GNUNET_assert (0 < sscanf_ret);
272 errno = 0;
273 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
274 if (errno != 0)
275 {
276 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
277 }
278 GNUNET_assert (0 < sscanf_ret);
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 is = GNUNET_TESTING_run (commands,
352 TIMEOUT,
353 &handle_result,
354 ts);
355 return is;
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 api->get_waiting_for_barriers = get_waiting_for_barriers;
379 return api;
380}
381
382
383/**
384 * Exit point from the plugin.
385 *
386 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
387 * @return NULL
388 */
389void *
390libgnunet_test_transport_plugin_cmd_simple_send_broadcast_done (void *cls)
391{
392 struct GNUNET_TESTING_PluginFunctions *api = cls;
393
394 GNUNET_free (api);
395 return NULL;
396}
397
398
399/* end of plugin_cmd_simple_send_broadcast.c */
diff --git a/src/service/transport/test_transport_plugin_cmd_simple_send_dv.c b/src/service/transport/test_transport_plugin_cmd_simple_send_dv.c
new file mode 100644
index 000000000..b92736eaa
--- /dev/null
+++ b/src/service/transport/test_transport_plugin_cmd_simple_send_dv.c
@@ -0,0 +1,433 @@
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_barrier.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#include "gnunet_testing_barrier.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40#define BASE_DIR "testdir"
41
42#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
43
44#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
45
46/**
47 * The number of messages received.
48 */
49static unsigned int number_received;
50
51static struct GNUNET_TESTING_Command block_send;
52
53static struct GNUNET_TESTING_Command block_receive;
54
55static struct GNUNET_TESTING_Command connect_peers;
56
57static struct GNUNET_TESTING_Command local_prepared;
58
59static struct GNUNET_TESTING_Command start_peer;
60
61static struct GNUNET_TESTING_Interpreter *is;
62
63/**
64 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
65 * received.
66 *
67 */
68static int
69check_test (void *cls,
70 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
71{
72 GNUNET_assert (NULL != cls);
73 return GNUNET_OK;
74}
75
76
77/**
78 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
79 * being received.
80 *
81 */
82static void
83handle_test (void *cls,
84 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
85{
86 struct GNUNET_PeerIdentity *peer = cls;
87 struct GNUNET_TESTING_AsyncContext *ac_block;
88 const struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
89 unsigned int connected;
90 struct GNUNET_TESTING_BlockState *bs;
91 struct GNUNET_TRANSPORT_CoreHandle *ch;
92 const struct GNUNET_TESTING_StartPeerState *sps;
93
94 GNUNET_TRANSPORT_TESTING_get_trait_state (&start_peer,
95 &sps);
96 ch = sps->th;
97 GNUNET_TRANSPORT_TESTING_get_trait_connected_peers_map (&start_peer,
98 &connected_peers_map);
99
100 if (NULL != connected_peers_map)
101 {
102 connected = GNUNET_CONTAINER_multishortmap_size (
103 connected_peers_map);
104
105 number_received++;
106 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
107 "Received %u test message(s) from %s, %u connected peer(s)\n",
108 number_received,
109 GNUNET_i2s (peer),
110 connected);
111
112 GNUNET_TESTING_get_trait_async_context (&block_receive,
113 &ac_block);
114
115 if (connected == number_received)
116 {
117 if (NULL != ac_block->is)
118 {
119 GNUNET_assert (NULL != ac_block);
120 if (NULL == ac_block->cont)
121 GNUNET_TESTING_async_fail ((struct
122 GNUNET_TESTING_AsyncContext *) ac_block);
123 else
124 GNUNET_TESTING_async_finish ((struct
125 GNUNET_TESTING_AsyncContext *) ac_block);
126 }
127 else
128 {
129 GNUNET_TESTING_get_trait_block_state (
130 &block_receive,
131 &bs);
132 bs->asynchronous_finish = GNUNET_YES;
133 }
134
135 }
136 }
137 GNUNET_TRANSPORT_core_receive_continue (ch, peer);
138}
139
140
141struct GNUNET_TESTING_BarrierList *
142get_waiting_for_barriers ()
143{
144 // No Barrier
145 return GNUNET_new (struct GNUNET_TESTING_BarrierList);
146}
147
148
149/**
150 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
151 *
152 */
153static void
154all_peers_started ()
155{
156 struct GNUNET_TESTING_AsyncContext *ac;
157
158 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
159 "Received message\n");
160 GNUNET_TESTING_get_trait_async_context (&block_send,
161 &ac);
162 GNUNET_assert (NULL != ac);
163 if (NULL == ac->cont)
164 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
165 else
166 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
167}
168
169
170/**
171 * Function called with the final result of the test.
172 *
173 * @param cls the `struct MainParams`
174 * @param rv #GNUNET_OK if the test passed
175 */
176static void
177handle_result (void *cls,
178 enum GNUNET_GenericReturnValue rv)
179{
180 struct TestState *ts = cls;
181
182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
183 "Local test exits with status %d\n",
184 rv);
185 ts->finished_cb (rv);
186 GNUNET_free (ts->testdir);
187 GNUNET_free (ts->cfgname);
188 GNUNET_TESTING_free_topology (ts->topology);
189 GNUNET_free (ts);
190}
191
192
193/**
194 * Callback from start peer cmd for signaling a peer got connected.
195 *
196 */
197static void *
198notify_connect (struct GNUNET_TESTING_Interpreter *is,
199 const struct GNUNET_PeerIdentity *peer)
200{
201 const struct ConnectPeersState *cps;
202 const struct GNUNET_TESTING_Command *cmd;
203
204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
205 "notify_connect peer %s\n",
206 GNUNET_i2s (peer));
207 // FIXME: modifying future is a bit unclean, not easy to follow logic;
208 // might be better to when reaching the future command to look into
209 // the past...
210 cmd = GNUNET_TESTING_interpreter_lookup_command_all (is,
211 "connect-peers");
212 // FIXME: check return value!
213 GNUNET_TRANSPORT_TESTING_get_trait_connect_peer_state (cmd,
214 &cps);
215 cps->notify_connect (is,
216 peer);
217 return NULL;
218}
219
220
221/**
222 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
223 */
224static void
225all_local_tests_prepared ()
226{
227 const struct GNUNET_TESTING_LocalPreparedState *lfs;
228
229 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
230 &lfs);
231 GNUNET_assert (NULL != &lfs->ac);
232 if (NULL == lfs->ac.cont)
233 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
234 else
235 GNUNET_TESTING_async_finish ((struct
236 GNUNET_TESTING_AsyncContext *) &lfs->ac);
237}
238
239
240/**
241 * Function to start a local test case.
242 *
243 * @param write_message Callback to send a message to the master loop.
244 * @param router_ip Global address of the network namespace.
245 * @param node_ip The IP address of the node.
246 * @param m The number of the node in a network namespace.
247 * @param n The number of the network namespace.
248 * @param local_m The number of nodes in a network namespace.
249 */
250static struct GNUNET_TESTING_Interpreter *
251start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
252 const char *router_ip,
253 const char *node_ip,
254 const char *m,
255 const char *n,
256 const char *local_m,
257 const char *topology_data,
258 unsigned int *read_file,
259 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
260{
261 unsigned int n_int;
262 unsigned int m_int;
263 unsigned int local_m_int;
264 unsigned int num;
265 struct TestState *ts = GNUNET_new (struct TestState);
266 struct GNUNET_TESTING_NetjailTopology *topology;
267 struct GNUNET_MQ_MessageHandler handlers[] = {
268 GNUNET_MQ_hd_var_size (test,
269 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
270 struct GNUNET_TRANSPORT_TESTING_TestMessage,
271 ts),
272 GNUNET_MQ_handler_end ()
273 };
274 unsigned int sscanf_ret = 0;
275
276 ts->finished_cb = finished_cb;
277 LOG (GNUNET_ERROR_TYPE_ERROR,
278 "n %s m %s\n",
279 n,
280 m);
281
282 if (GNUNET_YES == *read_file)
283 {
284 LOG (GNUNET_ERROR_TYPE_DEBUG,
285 "read from file\n");
286 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
287 }
288 else
289 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
290
291 ts->topology = topology;
292
293 errno = 0;
294 sscanf_ret = sscanf (m, "%u", &m_int);
295 if (errno != 0)
296 {
297 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
298 }
299 GNUNET_assert (0 < sscanf_ret);
300 errno = 0;
301 sscanf_ret = sscanf (n, "%u", &n_int);
302 if (errno != 0)
303 {
304 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
305 }
306 GNUNET_assert (0 < sscanf_ret);
307 errno = 0;
308 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
309 if (errno != 0)
310 {
311 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
312 }
313 GNUNET_assert (0 < sscanf_ret);
314
315 if (0 == n_int)
316 num = m_int;
317 else
318 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
319
320 block_send = GNUNET_TESTING_cmd_block_until_external_trigger ("block");
321 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
322 "block-receive");
323 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers (
324 "connect-peers",
325 "start-peer",
326 "system-create",
327 num,
328 topology,
329 topology->additional_connects,
330 GNUNET_YES);
331 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
332 "local-test-prepared",
333 write_message);
334
335
336 GNUNET_asprintf (&ts->cfgname,
337 "test_transport_api2_tcp_node1.conf");
338
339 LOG (GNUNET_ERROR_TYPE_DEBUG,
340 "plugin cfgname: %s\n",
341 ts->cfgname);
342
343 LOG (GNUNET_ERROR_TYPE_DEBUG,
344 "node ip: %s\n",
345 node_ip);
346
347 GNUNET_asprintf (&ts->testdir,
348 "%s%s%s",
349 BASE_DIR,
350 m,
351 n);
352
353 start_peer = GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
354 "system-create",
355 num,
356 node_ip,
357 handlers,
358 ts->cfgname,
359 notify_connect,
360 GNUNET_NO);
361 struct GNUNET_TESTING_Command commands[] = {
362 GNUNET_TESTING_cmd_system_create ("system-create",
363 ts->testdir),
364 start_peer,
365 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
366 write_message),
367 block_send,
368 connect_peers,
369 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
370 "start-peer",
371 "system-create",
372 num,
373 topology),
374 block_receive,
375 local_prepared,
376 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
377 "start-peer"),
378 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
379 "system-create"),
380 GNUNET_TESTING_cmd_end ()
381 };
382
383 ts->write_message = write_message;
384
385 is = GNUNET_TESTING_run (commands,
386 TIMEOUT,
387 &handle_result,
388 ts);
389 return is;
390}
391
392
393/**
394 * Entry point for the plugin.
395 *
396 * @param cls NULL
397 * @return the exported block API
398 */
399void *
400libgnunet_test_transport_plugin_cmd_simple_send_dv_init (void *cls)
401{
402 struct GNUNET_TESTING_PluginFunctions *api;
403
404 GNUNET_log_setup ("simple-send",
405 "DEBUG",
406 NULL);
407
408 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
409 api->start_testcase = &start_testcase;
410 api->all_peers_started = &all_peers_started;
411 api->all_local_tests_prepared = all_local_tests_prepared;
412 api->get_waiting_for_barriers = get_waiting_for_barriers;
413 return api;
414}
415
416
417/**
418 * Exit point from the plugin.
419 *
420 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
421 * @return NULL
422 */
423void *
424libgnunet_test_transport_plugin_cmd_simple_send_dv_done (void *cls)
425{
426 struct GNUNET_TESTING_PluginFunctions *api = cls;
427
428 GNUNET_free (api);
429 return NULL;
430}
431
432
433/* end of plugin_cmd_simple_send_broadcast.c */
diff --git a/src/service/transport/test_transport_plugin_cmd_simple_send_performance.c b/src/service/transport/test_transport_plugin_cmd_simple_send_performance.c
new file mode 100644
index 000000000..33deb3323
--- /dev/null
+++ b/src/service/transport/test_transport_plugin_cmd_simple_send_performance.c
@@ -0,0 +1,480 @@
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_barrier.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#include "gnunet_testing_barrier.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
39
40#define BASE_DIR "testdir"
41
42#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
43
44#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
45
46#define MAX_RECEIVED 1000
47
48#define MESSAGE_SIZE 65000
49
50static struct GNUNET_TESTING_Command block_send;
51
52static struct GNUNET_TESTING_Command block_receive;
53
54static struct GNUNET_TESTING_Command connect_peers;
55
56static struct GNUNET_TESTING_Command local_prepared;
57
58static struct GNUNET_TESTING_Command start_peer;
59
60static struct GNUNET_TESTING_Interpreter *is;
61
62static struct GNUNET_CONTAINER_MultiPeerMap *senders;
63
64struct Sender
65{
66 /**
67 * Number of received messages from sender.
68 */
69 unsigned long long num_received;
70
71 /**
72 * Sample mean time the message traveled.
73 */
74 struct GNUNET_TIME_Relative mean_time;
75
76 /**
77 * Time the first message was send.
78 */
79 struct GNUNET_TIME_Absolute time_first;
80};
81
82/**
83 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
84 * received.
85 *
86 */
87static int
88check_test (void *cls,
89 const struct
90 GNUNET_TRANSPORT_TESTING_PerformanceTestMessage *message)
91{
92 return GNUNET_OK;
93}
94
95
96/**
97 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
98 * being received.
99 *
100 */
101static void
102handle_test (void *cls,
103 const struct
104 GNUNET_TRANSPORT_TESTING_PerformanceTestMessage *message)
105{
106 struct GNUNET_PeerIdentity *peer = cls;
107 struct GNUNET_TESTING_AsyncContext *ac;
108 struct Sender *sender;
109 struct GNUNET_TIME_Absolute time_send;
110 struct GNUNET_TIME_Absolute now;
111 struct GNUNET_TIME_Relative time_traveled;
112 uint32_t num;
113 struct GNUNET_TRANSPORT_CoreHandle *ch;
114 const struct GNUNET_TESTING_StartPeerState *sps;
115
116
117 GNUNET_TRANSPORT_TESTING_get_trait_state (&start_peer,
118 &sps);
119 ch = sps->th;
120 num = ntohl (message->num);
121 GNUNET_TESTING_get_trait_async_context (&block_receive,
122 &ac);
123 GNUNET_assert (NULL != ac);
124
125 sender = GNUNET_CONTAINER_multipeermap_get (senders, peer);
126
127 now = GNUNET_TIME_absolute_get ();
128 time_send = GNUNET_TIME_absolute_ntoh (message->time_send);
129
130 time_traveled = GNUNET_TIME_absolute_get_difference (time_send, now);
131
132 if (NULL == sender)
133 {
134 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
135 "time traveled init %s\n",
136 GNUNET_i2s (peer));
137 sender = GNUNET_new (struct Sender);
138 sender->time_first = time_send;
139 sender->mean_time = GNUNET_TIME_UNIT_ZERO;
140 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (senders,
141 peer, sender,
142 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
143 }
144
145 if (GNUNET_TIME_UNIT_ZERO.rel_value_us == sender->mean_time.rel_value_us)
146 {
147 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
148 "time traveld mean zero\n");
149 sender->mean_time = time_traveled;
150 }
151 else
152 {
153 double factor = (double) sender->num_received
154 / ((double) sender->num_received + 1.0);
155 struct GNUNET_TIME_Relative s1;
156 struct GNUNET_TIME_Relative s2;
157
158 s1 = GNUNET_TIME_relative_multiply (sender->mean_time,
159 factor);
160 s2 = GNUNET_TIME_relative_divide (time_traveled,
161 sender->num_received + 1);
162 sender->mean_time = GNUNET_TIME_relative_add (s1, s2);
163 }
164
165 sender->num_received++;
166
167 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
168 "time traveled: %llu\n",
169 (unsigned long long) time_traveled.rel_value_us);
170 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
171 "mean time traveled: %s %llu messages received with message number %u\n",
172 GNUNET_STRINGS_relative_time_to_string (sender->mean_time,
173 false),
174 sender->num_received,
175 num);
176 if (floor (MAX_RECEIVED * (1 - 1.0 / 200)) < sender->num_received && NULL ==
177 ac->cont)
178 {
179 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
180 "time traveled failed\n");
181 // GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
182 }
183 else if (floor (MAX_RECEIVED * (1 - 1.0 / 200)) < sender->num_received &&
184 GNUNET_NO == ac->finished)
185 {
186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
187 "time traveled finish\n");
188 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
189 }
190 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
191 "time traveled end\n");
192 GNUNET_TRANSPORT_core_receive_continue (ch, peer);
193}
194
195
196struct GNUNET_TESTING_BarrierList*
197get_waiting_for_barriers ()
198{
199 struct GNUNET_TESTING_BarrierList*barriers;
200 struct GNUNET_TESTING_BarrierListEntry *ble;
201
202 barriers = GNUNET_new (struct GNUNET_TESTING_BarrierList);
203 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
204 ble->barrier_name = "ready-to-connect";
205 ble->expected_reaches = 1;
206 GNUNET_CONTAINER_DLL_insert (barriers->head,
207 barriers->tail,
208 ble);
209
210 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
211 ble->barrier_name = "test-case-finished";
212 ble->expected_reaches = 1;
213 GNUNET_CONTAINER_DLL_insert (barriers->head,
214 barriers->tail,
215 ble);
216 return barriers;
217}
218
219
220/**
221 * Function called with the final result of the test.
222 *
223 * @param cls the `struct MainParams`
224 * @param rv #GNUNET_OK if the test passed
225 */
226static void
227handle_result (void *cls,
228 enum GNUNET_GenericReturnValue rv)
229{
230 struct TestState *ts = cls;
231
232 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
233 "Local test exits with status %d\n",
234 rv);
235
236 ts->finished_cb (rv);
237 GNUNET_free (ts->testdir);
238 GNUNET_free (ts->cfgname);
239 GNUNET_TESTING_free_topology (ts->topology);
240 GNUNET_free (ts);
241}
242
243
244/**
245 * Callback from start peer cmd for signaling a peer got connected.
246 *
247 */
248static void *
249notify_connect (struct GNUNET_TESTING_Interpreter *is,
250 const struct GNUNET_PeerIdentity *peer)
251{
252 const struct ConnectPeersState *cps;
253 const struct GNUNET_TESTING_Command *cmd;
254
255 cmd = GNUNET_TESTING_interpreter_lookup_command (is,
256 "connect-peers");
257 GNUNET_TRANSPORT_TESTING_get_trait_connect_peer_state (cmd,
258 &cps);
259 void *ret = NULL;
260
261 cps->notify_connect (is,
262 peer);
263 return ret;
264}
265
266
267/**
268 * Function to start a local test case.
269 *
270 * @param write_message Callback to send a message to the master loop.
271 * @param router_ip Global address of the network namespace.
272 * @param node_ip The IP address of the node.
273 * @param m The number of the node in a network namespace.
274 * @param n The number of the network namespace.
275 * @param local_m The number of nodes in a network namespace.
276 * @param topology_data A file name for the file containing the topology configuration, or a string containing
277 * the topology configuration.
278 * @param read_file If read_file is GNUNET_YES this string is the filename for the topology configuration,
279 * if read_file is GNUNET_NO the string contains the topology configuration.
280 * @param finish_cb Callback function which writes a message from the helper process running on a netjail
281 * node to the master process * signaling that the test case running on the netjail node finished.
282 * @return Returns the struct GNUNET_TESTING_Interpreter of the command loop running on this netjail node.
283 */
284static struct GNUNET_TESTING_Interpreter *
285start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
286 const char *router_ip,
287 const char *node_ip,
288 const char *m,
289 const char *n,
290 const char *local_m,
291 const char *topology_data,
292 unsigned int *read_file,
293 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
294{
295
296 unsigned int n_int;
297 unsigned int m_int;
298 unsigned int local_m_int;
299 unsigned int num;
300 struct TestState *ts = GNUNET_new (struct TestState);
301 struct GNUNET_TESTING_NetjailTopology *topology;
302 unsigned int sscanf_ret = 0;
303
304 senders = GNUNET_CONTAINER_multipeermap_create (1, GNUNET_NO);
305 ts->finished_cb = finished_cb;
306 LOG (GNUNET_ERROR_TYPE_ERROR,
307 "n %s m %s\n",
308 n,
309 m);
310
311 if (GNUNET_YES == *read_file)
312 {
313 LOG (GNUNET_ERROR_TYPE_DEBUG,
314 "read from file\n");
315 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
316 }
317 else
318 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
319
320 ts->topology = topology;
321
322 errno = 0;
323 sscanf_ret = sscanf (m, "%u", &m_int);
324 if (errno != 0)
325 {
326 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
327 }
328 GNUNET_assert (0 < sscanf_ret);
329 errno = 0;
330 sscanf_ret = sscanf (n, "%u", &n_int);
331 if (errno != 0)
332 {
333 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
334 }
335 GNUNET_assert (0 < sscanf_ret);
336 errno = 0;
337 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
338 if (errno != 0)
339 {
340 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
341 }
342 GNUNET_assert (0 < sscanf_ret);
343
344 if (0 == n_int)
345 num = m_int;
346 else
347 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
348
349 block_send = GNUNET_TESTING_cmd_block_until_external_trigger (
350 "block");
351 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
352 "block-receive");
353 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
354 "start-peer",
355 "system-create",
356 num,
357 topology,
358 0,
359 GNUNET_YES);
360 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
361 "local-test-prepared",
362 write_message);
363
364
365 GNUNET_asprintf (&ts->cfgname,
366 "test_transport_api2_tcp_node1.conf");
367
368 LOG (GNUNET_ERROR_TYPE_DEBUG,
369 "plugin cfgname: %s\n",
370 ts->cfgname);
371
372 LOG (GNUNET_ERROR_TYPE_DEBUG,
373 "node ip: %s\n",
374 node_ip);
375
376 GNUNET_asprintf (&ts->testdir,
377 "%s%s%s",
378 BASE_DIR,
379 m,
380 n);
381
382 struct GNUNET_MQ_MessageHandler handlers[] = {
383 GNUNET_MQ_hd_var_size (test,
384 GNUNET_TRANSPORT_TESTING_SIMPLE_PERFORMANCE_MTYPE,
385 struct
386 GNUNET_TRANSPORT_TESTING_PerformanceTestMessage,
387 ts),
388 GNUNET_MQ_handler_end ()
389 };
390
391 start_peer = GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
392 "system-create",
393 num,
394 node_ip,
395 handlers,
396 ts->cfgname,
397 notify_connect,
398 GNUNET_NO);
399
400 struct GNUNET_TESTING_Command commands[] = {
401 GNUNET_TESTING_cmd_system_create ("system-create",
402 ts->testdir),
403 start_peer,
404 GNUNET_TESTING_cmd_barrier_reached ("ready-to-connect-reached",
405 "ready-to-connect",
406 GNUNET_NO,
407 num,
408 GNUNET_NO,
409 write_message),
410 connect_peers,
411 GNUNET_TRANSPORT_cmd_send_simple_performance ("send-simple",
412 "start-peer",
413 "system-create",
414 num,
415 MESSAGE_SIZE,
416 MAX_RECEIVED,
417 topology),
418 block_receive,
419 GNUNET_TESTING_cmd_barrier_reached ("test-case-finished-reached",
420 "test-case-finished",
421 GNUNET_NO,
422 num,
423 GNUNET_NO,
424 write_message),
425 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
426 "start-peer"),
427 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
428 "system-create"),
429 GNUNET_TESTING_cmd_end ()
430 };
431
432 ts->write_message = write_message;
433
434 is = GNUNET_TESTING_run (commands,
435 TIMEOUT,
436 &handle_result,
437 ts);
438 return is;
439}
440
441
442/**
443 * Entry point for the plugin.
444 *
445 * @param cls NULL
446 * @return the exported block API
447 */
448void *
449libgnunet_test_transport_plugin_cmd_simple_send_performance_init (void *cls)
450{
451 struct GNUNET_TESTING_PluginFunctions *api;
452
453 GNUNET_log_setup ("simple-send",
454 "DEBUG",
455 NULL);
456
457 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
458 api->start_testcase = &start_testcase;
459 api->get_waiting_for_barriers = get_waiting_for_barriers;
460 return api;
461}
462
463
464/**
465 * Exit point from the plugin.
466 *
467 * @param cls the return value from #libgnunet_test_transport_plugin_simple_send_performance_init
468 * @return NULL
469 */
470void *
471libgnunet_test_transport_plugin_cmd_simple_send_performance_done (void *cls)
472{
473 struct GNUNET_TESTING_PluginFunctions *api = cls;
474
475 GNUNET_free (api);
476 return NULL;
477}
478
479
480/* end of plugin_cmd_simple_send.c */
diff --git a/src/service/transport/test_transport_plugin_cmd_udp_backchannel.c b/src/service/transport/test_transport_plugin_cmd_udp_backchannel.c
new file mode 100644
index 000000000..75fb85e66
--- /dev/null
+++ b/src/service/transport/test_transport_plugin_cmd_udp_backchannel.c
@@ -0,0 +1,371 @@
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_barrier.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#include "gnunet_testing_barrier.h"
34
35/**
36 * Generic logging shortcut
37 */
38#define LOG(kind, ...) GNUNET_log_from (kind, "udp-backchannel", __VA_ARGS__)
39
40#define BASE_DIR "testdir"
41
42#define TOPOLOGY_CONFIG "test_transport_udp_backchannel_topo.conf"
43
44#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
45
46static struct GNUNET_TESTING_Command block_send;
47
48static struct GNUNET_TESTING_Command connect_peers;
49
50static struct GNUNET_TESTING_Command local_prepared;
51
52static struct GNUNET_TESTING_Interpreter *is;
53
54
55/**
56 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
57 * received.
58 *
59 */
60static int
61check_test (void *cls,
62 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
63{
64 return GNUNET_OK;
65}
66
67
68/**
69 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
70 * being received.
71 *
72 */
73static void
74handle_test (void *cls,
75 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
76{
77 // struct GNUNET_TESTING_AsyncContext *ac;
78
79 /*GNUNET_TESTING_get_trait_async_context (&block_receive,
80 &ac);
81 if ((NULL == ac) || (NULL == ac->cont))
82 GNUNET_TESTING_async_fail (ac);
83 else
84 GNUNET_TESTING_async_finish (ac);*/
85}
86
87
88struct GNUNET_TESTING_BarrierList *
89get_waiting_for_barriers ()
90{
91 // No Barrier
92 return GNUNET_new (struct GNUNET_TESTING_BarrierList);
93}
94
95
96/**
97 * Callback to set the flag indicating all peers started. Will be called via the plugin api.
98 *
99 */
100static void
101all_peers_started ()
102{
103 struct GNUNET_TESTING_AsyncContext *ac;
104
105 GNUNET_TESTING_get_trait_async_context (&block_send,
106 &ac);
107 GNUNET_assert (NULL != ac);
108 if ((NULL == ac->cont))
109 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
110 else
111 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
112}
113
114
115/**
116* Function called with the final result of the test.
117*
118* @param cls the `struct MainParams`
119* @param rv #GNUNET_OK if the test passed
120*/
121static void
122handle_result (void *cls,
123 enum GNUNET_GenericReturnValue rv)
124{
125 struct TestState *ts = cls;
126
127 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
128 "Local test exits with status %d\n",
129 rv);
130
131 ts->finished_cb (rv);
132 GNUNET_free (ts->testdir);
133 GNUNET_free (ts->cfgname);
134 GNUNET_TESTING_free_topology (ts->topology);
135 GNUNET_free (ts);
136}
137
138
139/**
140 * Callback from start peer cmd for signaling a peer got connected.
141 *
142 */
143static void *
144notify_connect (struct GNUNET_TESTING_Interpreter *is,
145 const struct GNUNET_PeerIdentity *peer)
146{
147 const struct ConnectPeersState *cps;
148
149 GNUNET_TRANSPORT_TESTING_get_trait_connect_peer_state (&connect_peers,
150 &cps);
151 void *ret = NULL;
152
153 cps->notify_connect (is,
154 peer);
155 return ret;
156}
157
158
159/**
160 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
161 */
162static void
163all_local_tests_prepared ()
164{
165 const struct GNUNET_TESTING_LocalPreparedState *lfs;
166
167 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
168 &lfs);
169 GNUNET_assert (NULL != &lfs->ac);
170 if (NULL == lfs->ac.cont)
171 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
172 else
173 GNUNET_TESTING_async_finish ((struct
174 GNUNET_TESTING_AsyncContext *) &lfs->ac);
175}
176
177
178/**
179 * Function to start a local test case.
180 *
181 * @param write_message Callback to send a message to the master loop.
182 * @param router_ip Global address of the network namespace.
183 * @param node_ip The IP address of the node.
184 * @param m The number of the node in a network namespace.
185 * @param n The number of the network namespace.
186 * @param local_m The number of nodes in a network namespace.
187 */
188static struct GNUNET_TESTING_Interpreter *
189start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
190 const char *router_ip,
191 const char *node_ip,
192 const char *m,
193 const char *n,
194 const char *local_m,
195 const char *topology_data,
196 unsigned int *read_file,
197 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
198{
199
200 unsigned int n_int;
201 unsigned int m_int;
202 unsigned int local_m_int;
203 unsigned int num;
204 struct TestState *ts = GNUNET_new (struct TestState);
205 struct GNUNET_TESTING_NetjailTopology *topology;
206 unsigned int sscanf_ret = 0;
207
208 ts->finished_cb = finished_cb;
209 LOG (GNUNET_ERROR_TYPE_ERROR,
210 "n %s m %s\n",
211 n,
212 m);
213
214 if (GNUNET_YES == *read_file)
215 {
216 LOG (GNUNET_ERROR_TYPE_DEBUG,
217 "read from file\n");
218 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
219 }
220 else
221 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
222
223 ts->topology = topology;
224
225 errno = 0;
226 sscanf_ret = sscanf (m, "%u", &m_int);
227 if (errno != 0)
228 {
229 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
230 }
231 GNUNET_assert (0 < sscanf_ret);
232 errno = 0;
233 sscanf_ret = sscanf (n, "%u", &n_int);
234 if (errno != 0)
235 {
236 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
237 }
238 GNUNET_assert (0 < sscanf_ret);
239 errno = 0;
240 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
241 if (errno != 0)
242 {
243 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
244 }
245 GNUNET_assert (0 < sscanf_ret);
246
247
248 if (0 == n_int)
249 num = m_int;
250 else
251 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
252
253 block_send = GNUNET_TESTING_cmd_block_until_external_trigger (
254 "block");
255 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
256 "start-peer",
257 "system-create",
258 num,
259 topology,
260 0,
261 GNUNET_YES);
262 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
263 "local-test-prepared",
264 write_message);
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 NULL),
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_backchannel_check ("backchannel-check",
307 "start-peer",
308 "system-create",
309 num,
310 m_int,
311 n_int,
312 topology),
313 local_prepared,
314 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
315 "start-peer"),
316 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
317 "system-create"),
318 GNUNET_TESTING_cmd_end ()
319 };
320
321 ts->write_message = write_message;
322
323 is = GNUNET_TESTING_run (commands,
324 TIMEOUT,
325 &handle_result,
326 ts);
327 return is;
328}
329
330
331/**
332 * Entry point for the plugin.
333 *
334 * @param cls NULL
335 * @return the exported block API
336 */
337void *
338libgnunet_test_transport_plugin_cmd_udp_backchannel_init (void *cls)
339{
340 struct GNUNET_TESTING_PluginFunctions *api;
341
342 GNUNET_log_setup ("udp-backchannel",
343 "DEBUG",
344 "plugin.out");
345
346 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
347 api->start_testcase = &start_testcase;
348 api->all_peers_started = &all_peers_started;
349 api->all_local_tests_prepared = all_local_tests_prepared;
350 api->get_waiting_for_barriers = get_waiting_for_barriers;
351 return api;
352}
353
354
355/**
356 * Exit point from the plugin.
357 *
358 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
359 * @return NULL
360 */
361void *
362libgnunet_test_transport_plugin_cmd_udp_backchannel_done (void *cls)
363{
364 struct GNUNET_TESTING_PluginFunctions *api = cls;
365
366 GNUNET_free (api);
367 return NULL;
368}
369
370
371/* end of plugin_cmd_simple_send.c */
diff --git a/src/service/transport/test_transport_simple_send.sh b/src/service/transport/test_transport_simple_send.sh
new file mode 100755
index 000000000..0250070be
--- /dev/null
+++ b/src/service/transport/test_transport_simple_send.sh
@@ -0,0 +1,11 @@
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/service/transport/test_transport_simple_send_broadcast.sh b/src/service/transport/test_transport_simple_send_broadcast.sh
new file mode 100755
index 000000000..a4801bf70
--- /dev/null
+++ b/src/service/transport/test_transport_simple_send_broadcast.sh
@@ -0,0 +1,11 @@
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/service/transport/test_transport_simple_send_broadcast_topo.conf b/src/service/transport/test_transport_simple_send_broadcast_topo.conf
new file mode 100644
index 000000000..aa4964f81
--- /dev/null
+++ b/src/service/transport/test_transport_simple_send_broadcast_topo.conf
@@ -0,0 +1,4 @@
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/service/transport/test_transport_simple_send_dv_circle.sh b/src/service/transport/test_transport_simple_send_dv_circle.sh
new file mode 100755
index 000000000..bd5f00abe
--- /dev/null
+++ b/src/service/transport/test_transport_simple_send_dv_circle.sh
@@ -0,0 +1,11 @@
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/service/transport/test_transport_simple_send_dv_inverse.sh b/src/service/transport/test_transport_simple_send_dv_inverse.sh
new file mode 100755
index 000000000..cf7b863a0
--- /dev/null
+++ b/src/service/transport/test_transport_simple_send_dv_inverse.sh
@@ -0,0 +1,12 @@
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
11# exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; valgrind --leak-check=full --track-origins=yes --trace-children=yes --trace-children-skip=/usr/bin/awk,/usr/bin/cut,/usr/bin/seq,/sbin/ip/sed/bash ./test_transport_start_with_config test_transport_distance_vector_inverse_topo.conf"
12exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config test_transport_distance_vector_inverse_topo.conf"
diff --git a/src/service/transport/test_transport_simple_send_performance.sh b/src/service/transport/test_transport_simple_send_performance.sh
new file mode 100755
index 000000000..12798c2f0
--- /dev/null
+++ b/src/service/transport/test_transport_simple_send_performance.sh
@@ -0,0 +1,11 @@
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_performance_topo.conf"
diff --git a/src/service/transport/test_transport_simple_send_performance_topo.conf b/src/service/transport/test_transport_simple_send_performance_topo.conf
new file mode 100644
index 000000000..9f39cd9bc
--- /dev/null
+++ b/src/service/transport/test_transport_simple_send_performance_topo.conf
@@ -0,0 +1,6 @@
1M:2
2N:1
3X:0
4T:libgnunet_test_transport_plugin_cmd_simple_send_performance
5P:1:1|{connect:{P:1:2:tcp}|{P:1:2:udp}}
6P:1:2|{connect:{P:1:1:tcp}|{P:1:1:udp}} \ No newline at end of file
diff --git a/src/service/transport/test_transport_simple_send_string.sh b/src/service/transport/test_transport_simple_send_string.sh
new file mode 100755
index 000000000..211abb494
--- /dev/null
+++ b/src/service/transport/test_transport_simple_send_string.sh
@@ -0,0 +1,21 @@
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/service/transport/test_transport_simple_send_topo.conf b/src/service/transport/test_transport_simple_send_topo.conf
new file mode 100644
index 000000000..2c16201f5
--- /dev/null
+++ b/src/service/transport/test_transport_simple_send_topo.conf
@@ -0,0 +1,6 @@
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/service/transport/test_transport_start_testcase.sh b/src/service/transport/test_transport_start_testcase.sh
new file mode 100755
index 000000000..ad9832fb8
--- /dev/null
+++ b/src/service/transport/test_transport_start_testcase.sh
@@ -0,0 +1,12 @@
1#!/bin/bash
2#read -p "Test case configuration to use:" conf
3#if ! [ -d "/run/netns" ]; then
4# echo You have to create the directory /run/netns.
5#fi
6#if [ -f /proc/sys/kernel/unprivileged_userns_clone ]; then
7# if [ "$(cat /proc/sys/kernel/unprivileged_userns_clone)" != 1 ]; then
8# 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"
9# exit 78
10# fi
11#fi
12#exec unshare -r -nmU bash -c "mount -t tmpfs --make-rshared tmpfs /run/netns; ./test_transport_start_with_config $conf"
diff --git a/src/service/transport/test_transport_start_with_config.c b/src/service/transport/test_transport_start_with_config.c
new file mode 100644
index 000000000..349cd65a5
--- /dev/null
+++ b/src/service/transport/test_transport_start_with_config.c
@@ -0,0 +1,121 @@
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 "gnunet_util_lib.h"
30
31#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
32
33
34int
35main (int argc,
36 char *const *argv)
37{
38 char *topology_data;
39 char *topology_data_script;
40 struct GNUNET_TESTING_NetjailTopology *topology;
41 unsigned int read_file = GNUNET_YES;
42 int ret;
43 char *rest = NULL;
44 char *token;
45 size_t single_line_len;
46 size_t data_len;
47
48 GNUNET_log_setup ("test-netjail",
49 "INFO",
50 NULL);
51
52 if (0 == strcmp ("-s", argv[1]))
53 {
54 data_len = strlen (argv[2]);
55 topology_data = GNUNET_malloc (data_len);
56 topology_data_script = GNUNET_malloc (data_len);
57 token = strtok_r (argv[2], "\n", &rest);
58 while (NULL != token)
59 {
60 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
61 "token1 %s\n",
62 token);
63 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
64 "token2 %s\n",
65 token);
66 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
67 "topology_data %s\n",
68 topology_data);
69 strcat (topology_data_script, token);
70 strcat (topology_data_script, " ");
71 strcat (topology_data, token);
72 strcat (topology_data, "\n");
73 token = strtok_r (NULL, "\n", &rest);
74 }
75 single_line_len = strlen (topology_data);
76 topology_data_script [single_line_len - 1] = '\0';
77 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
78 "read from string\n");
79 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
80 "topology_data %s\n",
81 topology_data);
82 read_file = GNUNET_NO;
83 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
84 }
85 else
86 {
87 topology_data = argv[1];
88 topology_data_script = argv[1];
89 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
90 }
91
92 struct GNUNET_TESTING_Command commands[] = {
93 GNUNET_TESTING_cmd_netjail_start ("netjail-start",
94 topology_data_script,
95 &read_file),
96 GNUNET_TESTING_cmd_netjail_start_cmds_helper ("netjail-start-testbed",
97 topology,
98 &read_file,
99 topology_data_script,
100 TIMEOUT),
101 GNUNET_TESTING_cmd_stop_cmds_helper ("stop-testbed",
102 "netjail-start-testbed",
103 topology),
104 GNUNET_TESTING_cmd_netjail_stop ("netjail-stop",
105 topology_data_script,
106 &read_file),
107 GNUNET_TESTING_cmd_end ()
108 };
109
110 ret = GNUNET_TESTING_main (commands,
111 TIMEOUT);
112
113 if (0 == strcmp ("-s", argv[1]))
114 {
115 GNUNET_free (topology_data_script);
116 GNUNET_free (topology_data);
117 }
118 GNUNET_TESTING_free_topology (topology);
119
120 return ret;
121}
diff --git a/src/service/transport/test_transport_test_transport_address_switch_tcp_peer1.conf b/src/service/transport/test_transport_test_transport_address_switch_tcp_peer1.conf
new file mode 100644
index 000000000..920e8d199
--- /dev/null
+++ b/src/service/transport/test_transport_test_transport_address_switch_tcp_peer1.conf
@@ -0,0 +1,29 @@
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/service/transport/test_transport_test_transport_address_switch_tcp_peer2.conf b/src/service/transport/test_transport_test_transport_address_switch_tcp_peer2.conf
new file mode 100644
index 000000000..6855cd00d
--- /dev/null
+++ b/src/service/transport/test_transport_test_transport_address_switch_tcp_peer2.conf
@@ -0,0 +1,29 @@
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/service/transport/test_transport_testing_startstop.c b/src/service/transport/test_transport_testing_startstop.c
new file mode 100644
index 000000000..4783c1813
--- /dev/null
+++ b/src/service/transport/test_transport_testing_startstop.c
@@ -0,0 +1,138 @@
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/service/transport/test_transport_udp_backchannel.sh b/src/service/transport/test_transport_udp_backchannel.sh
new file mode 100755
index 000000000..1a7c83385
--- /dev/null
+++ b/src/service/transport/test_transport_udp_backchannel.sh
@@ -0,0 +1,14 @@
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/service/transport/test_transport_udp_backchannel_topo.conf b/src/service/transport/test_transport_udp_backchannel_topo.conf
new file mode 100644
index 000000000..ad35bde0a
--- /dev/null
+++ b/src/service/transport/test_transport_udp_backchannel_topo.conf
@@ -0,0 +1,7 @@
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/service/transport/testing_api_cmd_start_peer.c b/src/service/transport/testing_api_cmd_start_peer.c
new file mode 100644
index 000000000..5cf5ee22d
--- /dev/null
+++ b/src/service/transport/testing_api_cmd_start_peer.c
@@ -0,0 +1,296 @@
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 "transport-testing-cmds.h"
29#include "gnunet_testing_ng_lib.h"
30#include "gnunet_transport_testing_ng_lib.h"
31
32
33/**
34 * Generic logging shortcut
35 */
36#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
37
38
39/**
40 * The run method of this cmd will start all services of a peer to test the transport service.
41 *
42 */
43static void
44start_peer_run (void *cls,
45 struct GNUNET_TESTING_Interpreter *is)
46{
47 struct GNUNET_TESTING_StartPeerState *sps = cls;
48 char *emsg = NULL;
49 struct GNUNET_PeerIdentity dummy;
50 const struct GNUNET_TESTING_Command *system_cmd;
51 const struct GNUNET_TESTING_System *tl_system;
52 char *home;
53 char *transport_unix_path;
54 char *tcp_communicator_unix_path;
55 char *udp_communicator_unix_path;
56 char *bindto;
57 char *bindto_udp;
58
59 if (GNUNET_NO == GNUNET_DISK_file_test (sps->cfgname))
60 {
61 LOG (GNUNET_ERROR_TYPE_ERROR,
62 "File not found: `%s'\n",
63 sps->cfgname);
64 GNUNET_TESTING_interpreter_fail (is);
65 return;
66 }
67
68
69 sps->cfg = GNUNET_CONFIGURATION_create ();
70 GNUNET_assert (GNUNET_OK ==
71 GNUNET_CONFIGURATION_load (sps->cfg, sps->cfgname));
72
73 GNUNET_asprintf (&home,
74 "$GNUNET_TMP/test-transport/api-tcp-p%u",
75 sps->no);
76
77 GNUNET_asprintf (&transport_unix_path,
78 "$GNUNET_RUNTIME_DIR/tng-p%u.sock",
79 sps->no);
80
81 GNUNET_asprintf (&tcp_communicator_unix_path,
82 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
83 sps->no);
84
85 GNUNET_asprintf (&udp_communicator_unix_path,
86 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
87 sps->no);
88
89 GNUNET_asprintf (&bindto,
90 "%s:60002",
91 sps->node_ip);
92
93 GNUNET_asprintf (&bindto_udp,
94 "2086");
95
96 LOG (GNUNET_ERROR_TYPE_DEBUG,
97 "node_ip %s\n",
98 bindto);
99
100 LOG (GNUNET_ERROR_TYPE_DEBUG,
101 "bind_udp %s\n",
102 GNUNET_YES == sps->broadcast ?
103 bindto_udp : bindto);
104
105 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "PATHS", "GNUNET_TEST_HOME",
106 home);
107 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "transport", "UNIXPATH",
108 transport_unix_path);
109 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
110 "BINDTO",
111 bindto);
112 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-udp",
113 "BINDTO",
114 GNUNET_YES == sps->broadcast ?
115 bindto_udp : bindto);
116 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
117 "UNIXPATH",
118 tcp_communicator_unix_path);
119 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-udp",
120 "UNIXPATH",
121 udp_communicator_unix_path);
122
123
124 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
125 sps->system_label);
126 GNUNET_TESTING_get_trait_test_system (system_cmd,
127 &tl_system);
128
129 sps->tl_system = tl_system;
130
131 LOG (GNUNET_ERROR_TYPE_DEBUG,
132 "Creating testing library with key number %u\n",
133 sps->no);
134
135 if (GNUNET_SYSERR ==
136 GNUNET_TESTING_configuration_create ((struct
137 GNUNET_TESTING_System *) tl_system,
138 sps->cfg))
139 {
140 LOG (GNUNET_ERROR_TYPE_DEBUG,
141 "Testing library failed to create unique configuration based on `%s'\n",
142 sps->cfgname);
143 GNUNET_CONFIGURATION_destroy (sps->cfg);
144 GNUNET_TESTING_interpreter_fail (is);
145 return;
146 }
147
148 sps->peer = GNUNET_TESTING_peer_configure ((struct
149 GNUNET_TESTING_System *) sps->
150 tl_system,
151 sps->cfg,
152 sps->no,
153 NULL,
154 &emsg);
155 if (NULL == sps->peer)
156 {
157 LOG (GNUNET_ERROR_TYPE_ERROR,
158 "Testing library failed to create unique configuration based on `%s': `%s' with key number %u\n",
159 sps->cfgname,
160 emsg,
161 sps->no);
162 GNUNET_free (emsg);
163 GNUNET_TESTING_interpreter_fail (is);
164 return;
165 }
166
167 if (GNUNET_OK != GNUNET_TESTING_peer_start (sps->peer))
168 {
169 LOG (GNUNET_ERROR_TYPE_ERROR,
170 "Testing library failed to create unique configuration based on `%s'\n",
171 sps->cfgname);
172 GNUNET_free (emsg);
173 GNUNET_TESTING_interpreter_fail (is);
174 return;
175 }
176
177 memset (&dummy,
178 '\0',
179 sizeof(dummy));
180
181 GNUNET_TESTING_peer_get_identity (sps->peer,
182 &sps->id);
183
184 if (0 == memcmp (&dummy,
185 &sps->id,
186 sizeof(struct GNUNET_PeerIdentity)))
187 {
188 LOG (GNUNET_ERROR_TYPE_ERROR,
189 "Testing library failed to obtain peer identity for peer %u\n",
190 sps->no);
191 GNUNET_free (emsg);
192 GNUNET_TESTING_interpreter_fail (is);
193 return;
194 }
195 LOG (GNUNET_ERROR_TYPE_DEBUG,
196 "Peer %u configured with identity `%s'\n",
197 sps->no,
198 GNUNET_i2s_full (&sps->id));
199
200 GNUNET_free (home);
201 GNUNET_free (transport_unix_path);
202 GNUNET_free (tcp_communicator_unix_path);
203 GNUNET_free (udp_communicator_unix_path);
204 GNUNET_free (bindto);
205 GNUNET_free (bindto_udp);
206}
207
208
209/**
210 * The cleanup function of this cmd frees resources the cmd allocated.
211 *
212 */
213static void
214start_peer_cleanup (void *cls)
215{
216 struct GNUNET_TESTING_StartPeerState *sps = cls;
217
218 // TODO Investigate why this caused problems during shutdown.
219 /*if (NULL != sps->cfg)
220 {
221 GNUNET_CONFIGURATION_destroy (sps->cfg);
222 sps->cfg = NULL;
223 }*/
224 GNUNET_free (sps->cfgname);
225 GNUNET_free (sps->node_ip);
226 GNUNET_free (sps->system_label);
227 GNUNET_free (sps->hello);
228 GNUNET_free (sps->connected_peers_map);
229 GNUNET_free (sps);
230}
231
232
233/**
234 * This function prepares an array with traits.
235 *
236 */
237static int
238start_peer_traits (void *cls,
239 const void **ret,
240 const char *trait,
241 unsigned int index)
242{
243 struct GNUNET_TESTING_StartPeerState *sps = cls;
244 struct GNUNET_TRANSPORT_ApplicationHandle *ah = sps->ah;
245 struct GNUNET_PeerIdentity *id = &sps->id;
246 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
247 sps->connected_peers_map;
248 char *hello = sps->hello;
249 size_t hello_size = sps->hello_size;
250 struct GNUNET_TESTING_Trait traits[] = {
251 GNUNET_TRANSPORT_TESTING_make_trait_application_handle ((const void *) ah),
252 GNUNET_TRANSPORT_TESTING_make_trait_peer_id ((const void *) id),
253 GNUNET_TRANSPORT_TESTING_make_trait_connected_peers_map ((const
254 void *)
255 connected_peers_map),
256 GNUNET_TRANSPORT_TESTING_make_trait_hello ((const void *) hello),
257 GNUNET_TRANSPORT_TESTING_make_trait_hello_size ((const void *) hello_size),
258 GNUNET_TRANSPORT_TESTING_make_trait_state ((const void *) sps),
259 GNUNET_TRANSPORT_TESTING_make_trait_broadcast ((const void *) &sps->
260 broadcast),
261 GNUNET_TESTING_trait_end ()
262 };
263
264 return GNUNET_TESTING_get_trait (traits,
265 ret,
266 trait,
267 index);
268}
269
270
271struct GNUNET_TESTING_Command
272GNUNET_TESTING_cmd_start_peer (const char *label,
273 const char *system_label,
274 uint32_t no,
275 const char *node_ip,
276 const char *cfgname,
277 unsigned int broadcast)
278{
279 struct GNUNET_TESTING_StartPeerState *sps;
280 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
281 GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO);
282
283 sps = GNUNET_new (struct GNUNET_TESTING_StartPeerState);
284 sps->no = no;
285 sps->system_label = GNUNET_strdup (system_label);
286 sps->connected_peers_map = connected_peers_map;
287 sps->cfgname = GNUNET_strdup (cfgname);
288 sps->node_ip = GNUNET_strdup (node_ip);
289 sps->broadcast = broadcast;
290
291 return GNUNET_TESTING_command_new (sps,
292 label,
293 &start_peer_run,
294 &start_peer_cleanup,
295 &start_peer_traits);
296}
diff --git a/src/service/transport/testing_api_cmd_stop_peer.c b/src/service/transport/testing_api_cmd_stop_peer.c
new file mode 100644
index 000000000..4ce54585d
--- /dev/null
+++ b/src/service/transport/testing_api_cmd_stop_peer.c
@@ -0,0 +1,129 @@
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_transport_testing_ng_lib.h"
30
31/**
32 * Generic logging shortcut
33 */
34#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
35
36
37/**
38 * Struct to hold information for callbacks.
39 *
40 */
41struct StopPeerState
42{
43 // Label of the cmd to start the peer.
44 const char *start_label;
45};
46
47
48/**
49 * The run method of this cmd will stop all services of a peer which were used to test the transport service.
50 *
51 */
52static void
53stop_peer_run (void *cls,
54 struct GNUNET_TESTING_Interpreter *is)
55{
56 struct StopPeerState *stop_ps = cls;
57 const struct GNUNET_TESTING_StartPeerState *sps;
58 const struct GNUNET_TESTING_Command *start_cmd;
59
60 start_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
61 stop_ps->start_label);
62 GNUNET_TRANSPORT_TESTING_get_trait_state (start_cmd,
63 &sps);
64
65 if (NULL != sps->peer)
66 {
67 if (GNUNET_OK !=
68 GNUNET_TESTING_peer_stop (sps->peer))
69 {
70 LOG (GNUNET_ERROR_TYPE_ERROR,
71 "Testing lib failed to stop peer %u (`%s')\n",
72 sps->no,
73 GNUNET_i2s (&sps->id));
74 }
75 GNUNET_TESTING_peer_destroy (sps->peer);
76 }
77 if (NULL != sps->rh_task)
78 GNUNET_SCHEDULER_cancel (sps->rh_task);
79}
80
81
82/**
83 * The cleanup function of this cmd frees resources the cmd allocated.
84 *
85 */
86static void
87stop_peer_cleanup (void *cls)
88{
89 struct StopPeerState *sps = cls;
90
91 GNUNET_free (sps);
92}
93
94
95/**
96 * Trait function of this cmd does nothing.
97 *
98 */
99static int
100stop_peer_traits (void *cls,
101 const void **ret,
102 const char *trait,
103 unsigned int index)
104{
105 return GNUNET_OK;
106}
107
108
109/**
110 * Create command.
111 *
112 * @param label name for command.
113 * @param start_label Label of the cmd to start the peer.
114 * @return command.
115 */
116struct GNUNET_TESTING_Command
117GNUNET_TESTING_cmd_stop_peer (const char *label,
118 const char *start_label)
119{
120 struct StopPeerState *sps;
121
122 sps = GNUNET_new (struct StopPeerState);
123 sps->start_label = start_label;
124 return GNUNET_TESTING_command_new (sps,
125 label,
126 &stop_peer_run,
127 &stop_peer_cleanup,
128 &stop_peer_traits);
129}
diff --git a/src/service/transport/transport-testing-cmds.h b/src/service/transport/transport-testing-cmds.h
new file mode 100644
index 000000000..7ebc84d11
--- /dev/null
+++ b/src/service/transport/transport-testing-cmds.h
@@ -0,0 +1,273 @@
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
30#include "gnunet_testing_ng_lib.h"
31#include "gnunet_transport_testing_ng_lib.h"
32
33
34/**
35 * Struct to store information needed in callbacks.
36 *
37 */
38// FIXME: breaks naming conventions! Needed public?
39struct ConnectPeersState
40{
41 /**
42 * Context for our asynchronous completion.
43 */
44 struct GNUNET_TESTING_AsyncContext ac;
45
46 GNUNET_TESTING_notify_connect_cb notify_connect;
47
48 /**
49 * The testing system of this node.
50 */
51 const struct GNUNET_TESTING_System *tl_system;
52
53 // Label of the cmd which started the test system.
54 const char *create_label;
55
56 /**
57 * Number globally identifying the node.
58 *
59 */
60 uint32_t num;
61
62 /**
63 * Label of the cmd to start a peer.
64 *
65 */
66 const char *start_peer_label;
67
68 /**
69 * The topology of the test setup.
70 */
71 struct GNUNET_TESTING_NetjailTopology *topology;
72
73 /**
74 * Connections to other peers.
75 */
76 struct GNUNET_TESTING_NodeConnection *node_connections_head;
77
78 struct GNUNET_TESTING_Interpreter *is;
79
80 /**
81 * Number of connections.
82 */
83 unsigned int con_num;
84
85 /**
86 * Number of additional connects this cmd will wait for not triggered by this cmd.
87 */
88 unsigned int additional_connects;
89
90 /**
91 * Number of connections we already have a notification for.
92 */
93 unsigned int con_num_notified;
94
95 /**
96 * Number of additional connects this cmd will wait for not triggered by this cmd we already have a notification for.
97 */
98 unsigned int additional_connects_notified;
99
100 /**
101 * Flag indicating, whether the command is waiting for peers to connect that are configured to connect.
102 */
103 unsigned int wait_for_connect;
104};
105
106
107
108typedef void *
109(*GNUNET_TRANSPORT_notify_connect_cb) (struct GNUNET_TESTING_Interpreter *is,
110 const struct GNUNET_PeerIdentity *peer);
111
112
113
114struct TestState
115{
116 /**
117 * Callback to write messages to the master loop.
118 *
119 */
120 GNUNET_TESTING_cmd_helper_write_cb write_message;
121
122 /**
123 * Callback to notify the helper test case has finished.
124 */
125 GNUNET_TESTING_cmd_helper_finish_cb finished_cb;
126
127 /**
128 * The name for a specific test environment directory.
129 *
130 */
131 char *testdir;
132
133 /**
134 * The name for the configuration file of the specific node.
135 *
136 */
137 char *cfgname;
138
139 /**
140 * The complete topology information.
141 */
142 struct GNUNET_TESTING_NetjailTopology *topology;
143};
144
145
146/**
147 * Create command.
148 *
149 * @param label name for command.
150 * @param system_label Label of the cmd to setup a test environment.
151 * @param no Decimal number representing the last byte of the IP address of this peer.
152 * @param node_ip The IP address of this node.
153 * @param handlers Handler for messages received by this peer.
154 * @param cfgname Configuration file name for this peer.
155 * @param notify_connect Method which will be called, when a peer connects.
156 * @param broadcast Flag indicating, if broadcast should be switched on.
157 * @return command.
158 */
159struct GNUNET_TESTING_Command
160GNUNET_TRANSPORT_cmd_start_peer (const char *label,
161 const char *system_label,
162 uint32_t no,
163 const char *node_ip,
164 struct GNUNET_MQ_MessageHandler *handlers,
165 const char *cfgname,
166 GNUNET_TRANSPORT_notify_connect_cb
167 notify_connect,
168 unsigned int broadcast);
169
170
171struct GNUNET_TESTING_Command
172GNUNET_TRANSPORT_cmd_stop_peer (const char *label,
173 const char *start_label);
174
175
176/**
177 * Create command
178 *
179 * @param label name for command
180 * @param start_peer_label Label of the cmd to start a peer.
181 * @param create_label Label of the cmd which started the test system.
182 * @param num Number globally identifying the node.
183 * @param topology The topology for the test setup.
184 * @param additional_connects Number of additional connects this cmd will wait for not triggered by this cmd.
185 * @return command.
186 */
187struct GNUNET_TESTING_Command
188GNUNET_TRANSPORT_cmd_connect_peers (
189 const char *label,
190 const char *start_peer_label,
191 const char *create_label,
192 uint32_t num,
193 struct GNUNET_TESTING_NetjailTopology *topology,
194 unsigned int additional_connects,
195 unsigned int wait_for_connect);
196
197
198/**
199 * Create command.
200 *
201 * @param label name for command.
202 * @param start_peer_label Label of the cmd to start a peer.
203 * @param create_label Label of the cmd which started the test system.
204 * @param num Number globally identifying the node.
205 * @param topology The topology for the test setup.
206 * @return command.
207 */
208struct GNUNET_TESTING_Command
209GNUNET_TRANSPORT_cmd_send_simple (const char *label,
210 const char *start_peer_label,
211 const char *create_label,
212 uint32_t num,
213 struct GNUNET_TESTING_NetjailTopology *
214 topology);
215
216/**
217 *
218 *
219 * @param label name for command.
220 * @param start_peer_label Label of the cmd to start a peer.
221 * @param create_label Label of the cmd which started the test system.
222 * @param num Number globally identifying the node.
223 * @param size The size of the test message to send.
224 * @param max_send The number of messages to send.
225 * @param topology The topology for the test setup.
226 * @return command.
227 */
228struct GNUNET_TESTING_Command
229GNUNET_TRANSPORT_cmd_send_simple_performance (const char *label,
230 const char *start_peer_label,
231 const char *create_label,
232 uint32_t num,
233 int size,
234 int max_send,
235 struct GNUNET_TESTING_NetjailTopology *
236 topology);
237
238
239/**
240 * Create command.
241 *
242 * @param label name for command.
243 * @param start_peer_label Label of the cmd to start a peer.
244 * @param create_label Label of the cmd to create the testing system.
245 * @param num Number globally identifying the node.
246 * @param node_n The number of the node in a network namespace.
247 * @param namespace_n The number of the network namespace.
248 * @param topology The topology for the test setup.
249 * @return command.
250 */
251struct GNUNET_TESTING_Command
252GNUNET_TRANSPORT_cmd_backchannel_check (const char *label,
253 const char *start_peer_label,
254 const char *create_label,
255 uint32_t num,
256 unsigned int node_n,
257 unsigned int namespace_n,
258 struct GNUNET_TESTING_NetjailTopology *
259 topology);
260
261
262
263/**
264 * Call #op on all simple traits.
265 */
266#define GNUNET_TRANSPORT_SIMPLE_TRAITS(op, prefix) \
267 op (prefix, connect_peer_state, const struct ConnectPeersState)
268
269GNUNET_TRANSPORT_SIMPLE_TRAITS (GNUNET_TESTING_MAKE_DECL_SIMPLE_TRAIT, GNUNET_TRANSPORT_TESTING)
270
271
272#endif
273/* end of transport_testing.h */
diff --git a/src/service/transport/transport-testing-communicator.c b/src/service/transport/transport-testing-communicator.c
new file mode 100644
index 000000000..9ee70fe7b
--- /dev/null
+++ b/src/service/transport/transport-testing-communicator.c
@@ -0,0 +1,1251 @@
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_signatures.h"
33#include "transport.h"
34#include "gnunet_hello_uri_lib.h"
35#include <inttypes.h>
36
37#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing2", __VA_ARGS__)
38
39struct MyClient
40{
41 struct MyClient *prev;
42 struct MyClient *next;
43 /**
44 * @brief Handle to the client
45 */
46 struct GNUNET_SERVICE_Client *client;
47
48 /**
49 * @brief Handle to the client
50 */
51 struct GNUNET_MQ_Handle *c_mq;
52
53 /**
54 * The TCH
55 */
56 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc;
57
58};
59
60/**
61 * @brief Queue of a communicator and some context
62 */
63struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue
64{
65 /**
66 * @brief Handle to the TransportCommunicator
67 */
68 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h;
69
70 /**
71 * @brief Envelope to a message that requests the opening of the queue.
72 *
73 * If the client already requests queue(s), but the communicator is not yet
74 * connected, we cannot send the request to open the queue. Save it until the
75 * communicator becomes available and send it then.
76 */
77 struct GNUNET_MQ_Envelope *open_queue_env;
78
79 /**
80 * @brief Peer ID of the peer on the other side of the queue
81 */
82 struct GNUNET_PeerIdentity peer_id;
83
84 /**
85 * @brief Queue ID
86 */
87 uint32_t qid;
88
89 /**
90 * @brief Current message id
91 */
92 uint64_t mid;
93
94 /**
95 * An `enum GNUNET_NetworkType` in NBO.
96 */
97 uint32_t nt;
98
99 /**
100 * Maximum transmission unit. UINT32_MAX for unlimited.
101 */
102 uint32_t mtu;
103
104 /**
105 * Queue length. UINT64_MAX for unlimited.
106 */
107 uint64_t q_len;
108
109 /**
110 * Queue prio
111 */
112 uint32_t priority;
113
114 /**
115 * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO.
116 */
117 uint32_t cs;
118
119 /**
120 * @brief Next element inside a DLL
121 */
122 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *next;
123
124 /**
125 * @brief Previous element inside a DLL
126 */
127 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *prev;
128};
129
130
131/**
132 * @brief Handle/Context to a single transmission
133 */
134struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorTransmission
135{
136};
137
138
139/**
140 * @brief Check whether incoming msg indicating available communicator is
141 * correct
142 *
143 * @param cls Closure
144 * @param msg Message struct
145 *
146 * @return GNUNET_YES in case message is correct
147 */
148static int
149check_communicator_available (
150 void *cls,
151 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg)
152{
153 uint16_t size;
154
155 size = ntohs (msg->header.size) - sizeof(*msg);
156 if (0 == size)
157 return GNUNET_OK; /* receive-only communicator */
158 GNUNET_MQ_check_zero_termination (msg);
159 return GNUNET_OK;
160}
161
162
163/**
164 * @brief Handle new communicator
165 *
166 * Store characteristics of communicator, call respective client callback.
167 *
168 * @param cls Closure - communicator handle
169 * @param msg Message struct
170 */
171static void
172handle_communicator_available (
173 void *cls,
174 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *msg)
175{
176 struct MyClient *client = cls;
177 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
178 client->tc;
179 uint16_t size;
180 tc_h->c_mq = client->c_mq;
181
182 size = ntohs (msg->header.size) - sizeof(*msg);
183 if (0 == size)
184 {
185 GNUNET_SERVICE_client_continue (client->client);
186 return; /* receive-only communicator */
187 }
188 tc_h->c_characteristics = ntohl (msg->cc);
189 GNUNET_free (tc_h->c_addr_prefix);
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 bc_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 msg 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 GNUNET_free (tc_h->c_address);
325 tc_h->c_address = GNUNET_strdup ((const char *) &msg[1]);
326 if (NULL != tc_h->add_address_cb)
327 {
328 LOG (GNUNET_ERROR_TYPE_DEBUG, "calling add_address_cb()\n");
329 tc_h->add_address_cb (tc_h->cb_cls,
330 tc_h,
331 tc_h->c_address,
332 GNUNET_TIME_relative_ntoh (msg->expiration),
333 msg->aid,
334 ntohl (msg->nt));
335 }
336 GNUNET_SERVICE_client_continue (client->client);
337}
338
339
340/**
341 * Incoming message. Test message is well-formed.
342 *
343 * @param cls the client
344 * @param msg the send message that was sent
345 * @return #GNUNET_OK if message is well-formed
346 */
347static int
348check_incoming_msg (void *cls,
349 const struct GNUNET_TRANSPORT_IncomingMessage *msg)
350{
351 // struct TransportClient *tc = cls;
352
353 // if (CT_COMMUNICATOR != tc->type)
354 // {
355 // GNUNET_break (0);
356 // return GNUNET_SYSERR;
357 // }
358 GNUNET_MQ_check_boxed_message (msg);
359 return GNUNET_OK;
360}
361
362
363/**
364 * @brief Receive an incoming message.
365 *
366 * Pass the message to the client.
367 *
368 * @param cls Closure - communicator handle
369 * @param inc_msg Message
370 */
371static void
372handle_incoming_msg (void *cls,
373 const struct GNUNET_TRANSPORT_IncomingMessage *inc_msg)
374{
375 struct MyClient *client = cls;
376 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
377 client->tc;
378 struct GNUNET_MessageHeader *msg;
379 msg = (struct GNUNET_MessageHeader *) &inc_msg[1];
380 size_t payload_len = ntohs (msg->size) - sizeof (struct
381 GNUNET_MessageHeader);
382 if (NULL != tc_h->incoming_msg_cb)
383 {
384 tc_h->incoming_msg_cb (tc_h->cb_cls,
385 tc_h,
386 (char*) &msg[1],
387 payload_len);
388 }
389 else
390 {
391 LOG (GNUNET_ERROR_TYPE_WARNING,
392 "Incoming message from communicator but no handler!\n");
393 }
394 if (GNUNET_YES == ntohl (inc_msg->fc_on))
395 {
396 /* send ACK when done to communicator for flow control! */
397 struct GNUNET_MQ_Envelope *env;
398 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
399
400 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
401 GNUNET_assert (NULL != env);
402 ack->reserved = htonl (0);
403 ack->fc_id = inc_msg->fc_id;
404 ack->sender = inc_msg->sender;
405 GNUNET_MQ_send (tc_h->c_mq, env);
406 }
407
408 GNUNET_SERVICE_client_continue (client->client);
409}
410
411
412/**
413 * @brief Communicator informs that it tries to establish requested queue
414 *
415 * @param cls Closure - communicator handle
416 * @param msg Message
417 */
418static void
419handle_queue_create_ok (void *cls,
420 const struct GNUNET_TRANSPORT_CreateQueueResponse *msg)
421{
422 struct MyClient *client = cls;
423 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
424 client->tc;
425
426 if (NULL != tc_h->queue_create_reply_cb)
427 {
428 tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_YES);
429 }
430 GNUNET_SERVICE_client_continue (client->client);
431}
432
433
434/**
435 * @brief Communicator informs that it won't try establishing requested queue.
436 *
437 * It will not do so probably because the address is bougus (see comment to
438 * #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL)
439 *
440 * @param cls Closure - communicator handle
441 * @param msg Message
442 */
443static void
444handle_queue_create_fail (
445 void *cls,
446 const struct GNUNET_TRANSPORT_CreateQueueResponse *msg)
447{
448 struct MyClient *client = cls;
449 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
450 client->tc;
451
452 if (NULL != tc_h->queue_create_reply_cb)
453 {
454 tc_h->queue_create_reply_cb (tc_h->cb_cls, tc_h, GNUNET_NO);
455 }
456 GNUNET_SERVICE_client_continue (client->client);
457}
458
459
460/**
461 * New queue became available. Check message.
462 *
463 * @param cls the client
464 * @param aqm the send message that was sent
465 */
466static int
467check_add_queue_message (void *cls,
468 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
469{
470 GNUNET_MQ_check_zero_termination (aqm);
471 return GNUNET_OK;
472}
473
474
475/**
476 * @brief Handle new queue
477 *
478 * Store context and call client callback.
479 *
480 * @param cls Closure - communicator handle
481 * @param msg Message struct
482 */
483static void
484handle_add_queue_message (void *cls,
485 const struct GNUNET_TRANSPORT_AddQueueMessage *msg)
486{
487 struct MyClient *client = cls;
488 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
489 client->tc;
490 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
491
492 LOG (GNUNET_ERROR_TYPE_DEBUG,
493 "Got queue with ID %u\n", msg->qid);
494 for (tc_queue = tc_h->queue_head; NULL != tc_queue; tc_queue = tc_queue->next)
495 {
496 if (tc_queue->qid == msg->qid)
497 break;
498 }
499 if (NULL == tc_queue)
500 {
501 tc_queue =
502 GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue);
503 tc_queue->tc_h = tc_h;
504 tc_queue->qid = msg->qid;
505 tc_queue->peer_id = msg->receiver;
506 GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue);
507 }
508 GNUNET_assert (tc_queue->qid == msg->qid);
509 GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver));
510 tc_queue->nt = msg->nt;
511 tc_queue->mtu = ntohl (msg->mtu);
512 tc_queue->cs = msg->cs;
513 tc_queue->priority = ntohl (msg->priority);
514 tc_queue->q_len = GNUNET_ntohll (msg->q_len);
515 if (NULL != tc_h->add_queue_cb)
516 {
517 tc_h->add_queue_cb (tc_h->cb_cls, tc_h, tc_queue, tc_queue->mtu);
518 }
519 GNUNET_SERVICE_client_continue (client->client);
520}
521
522
523/**
524 * @brief Handle new queue
525 *
526 * Store context and call client callback.
527 *
528 * @param cls Closure - communicator handle
529 * @param msg Message struct
530 */
531static void
532handle_update_queue_message (void *cls,
533 const struct
534 GNUNET_TRANSPORT_UpdateQueueMessage *msg)
535{
536 struct MyClient *client = cls;
537 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
538 client->tc;
539 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
540
541 LOG (GNUNET_ERROR_TYPE_DEBUG,
542 "Received queue update message for %u with q_len %" PRIu64 "\n",
543 msg->qid, GNUNET_ntohll (msg->q_len));
544 tc_queue = tc_h->queue_head;
545 if (NULL != tc_queue)
546 {
547 while (tc_queue->qid != msg->qid)
548 {
549 tc_queue = tc_queue->next;
550 }
551 }
552 if (NULL == tc_queue)
553 {
554 GNUNET_SERVICE_client_continue (client->client);
555 return;
556 }
557 GNUNET_assert (tc_queue->qid == msg->qid);
558 GNUNET_assert (0 == GNUNET_memcmp (&tc_queue->peer_id, &msg->receiver));
559 tc_queue->nt = msg->nt;
560 tc_queue->mtu = ntohl (msg->mtu);
561 tc_queue->cs = msg->cs;
562 tc_queue->priority = ntohl (msg->priority);
563 // Uncomment this for alternativ 1 of backchannel functionality
564 tc_queue->q_len += GNUNET_ntohll (msg->q_len);
565 // Until here for alternativ 1
566 // Uncomment this for alternativ 2 of backchannel functionality
567 // tc_queue->q_len = GNUNET_ntohll (msg->q_len);
568 // Until here for alternativ 2
569 GNUNET_SERVICE_client_continue (client->client);
570}
571
572
573/**
574 * @brief Shut down the service
575 *
576 * @param cls Closure - Handle to the service
577 */
578static void
579shutdown_service (void *cls)
580{
581 struct GNUNET_SERVICE_Handle *h = cls;
582
583 LOG (GNUNET_ERROR_TYPE_DEBUG,
584 "Shutting down service!\n");
585
586 GNUNET_SERVICE_stop (h);
587}
588
589
590/**
591 * @brief Callback called when new Client (Communicator) connects
592 *
593 * @param cls Closure - TransporCommmunicator Handle
594 * @param client Client
595 * @param mq Messagequeue
596 *
597 * @return TransportCommunicator Handle
598 */
599static void *
600connect_cb (void *cls,
601 struct GNUNET_SERVICE_Client *client,
602 struct GNUNET_MQ_Handle *mq)
603{
604 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
605 struct MyClient *new_c;
606
607 LOG (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected to %p.\n",
608 client, tc_h);
609 new_c = GNUNET_new (struct MyClient);
610 new_c->client = client;
611 new_c->c_mq = mq;
612 new_c->tc = tc_h;
613 GNUNET_CONTAINER_DLL_insert (tc_h->client_head,
614 tc_h->client_tail,
615 new_c);
616
617 if (NULL == tc_h->queue_head)
618 return new_c;
619 /* Iterate over queues. They are yet to be opened. Request opening. */
620 for (struct
621 GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_iter =
622 tc_h->queue_head;
623 NULL != tc_queue_iter;
624 tc_queue_iter = tc_queue_iter->next)
625 {
626 if (NULL == tc_queue_iter->open_queue_env)
627 continue;
628 /* Send the previously created mq envelope to request the creation of the
629 * queue. */
630 GNUNET_MQ_send (tc_h->c_mq,
631 tc_queue_iter->open_queue_env);
632 tc_queue_iter->open_queue_env = NULL;
633 }
634 return new_c;
635}
636
637
638/**
639 * @brief Callback called when Client disconnects
640 *
641 * @param cls Closure - TransportCommunicator Handle
642 * @param client Client
643 * @param internal_cls TransporCommmunicator Handle
644 */
645static void
646disconnect_cb (void *cls,
647 struct GNUNET_SERVICE_Client *client,
648 void *internal_cls)
649{
650 struct MyClient *cl = cls;
651 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h = cls;
652
653 for (cl = tc_h->client_head; NULL != cl; cl = cl->next)
654 {
655 if (cl->client != client)
656 continue;
657 GNUNET_CONTAINER_DLL_remove (tc_h->client_head,
658 tc_h->client_tail,
659 cl);
660 if (cl->c_mq == tc_h->c_mq)
661 tc_h->c_mq = NULL;
662 GNUNET_free (cl);
663 break;
664 }
665 LOG (GNUNET_ERROR_TYPE_DEBUG, "Client disconnected.\n");
666}
667
668
669/**
670 * Message was transmitted. Process the request.
671 *
672 * @param cls the client
673 * @param sma the send message that was sent
674 */
675static void
676handle_send_message_ack (void *cls,
677 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
678{
679 struct MyClient *client = cls;
680 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h =
681 client->tc;
682 static int mtr = 0;
683 mtr++;
684 if (tc_h->cont != NULL)
685 tc_h->cont (tc_h->cont_cls);
686 GNUNET_SERVICE_client_continue (client->client);
687}
688
689
690/**
691 * @brief Start the communicator part of the transport service
692 *
693 * @param communicator_available Callback to be called when a new communicator
694 * becomes available
695 * @param cfg Configuration
696 */
697static void
698transport_communicator_start (
699 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
700{
701 struct GNUNET_MQ_MessageHandler mh[] = {
702 GNUNET_MQ_hd_var_size (communicator_available,
703 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
704 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
705 tc_h),
706 GNUNET_MQ_hd_var_size (communicator_backchannel,
707 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
708 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
709 tc_h),
710 GNUNET_MQ_hd_var_size (add_address,
711 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
712 struct GNUNET_TRANSPORT_AddAddressMessage,
713 tc_h),
714 // GNUNET_MQ_hd_fixed_size (del_address,
715 // GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
716 // struct GNUNET_TRANSPORT_DelAddressMessage,
717 // NULL),
718 GNUNET_MQ_hd_var_size (incoming_msg,
719 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
720 struct GNUNET_TRANSPORT_IncomingMessage,
721 tc_h),
722 GNUNET_MQ_hd_fixed_size (queue_create_ok,
723 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
724 struct GNUNET_TRANSPORT_CreateQueueResponse,
725 tc_h),
726 GNUNET_MQ_hd_fixed_size (queue_create_fail,
727 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
728 struct GNUNET_TRANSPORT_CreateQueueResponse,
729 tc_h),
730 GNUNET_MQ_hd_var_size (add_queue_message,
731 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
732 struct GNUNET_TRANSPORT_AddQueueMessage,
733 tc_h),
734 GNUNET_MQ_hd_fixed_size (update_queue_message,
735 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE,
736 struct GNUNET_TRANSPORT_UpdateQueueMessage,
737 tc_h),
738 // GNUNET_MQ_hd_fixed_size (del_queue_message,
739 // GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
740 // struct GNUNET_TRANSPORT_DelQueueMessage,
741 // NULL),
742 GNUNET_MQ_hd_fixed_size (send_message_ack,
743 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
744 struct GNUNET_TRANSPORT_SendMessageToAck,
745 tc_h),
746 GNUNET_MQ_handler_end ()
747 };
748
749
750 tc_h->sh = GNUNET_SERVICE_start ("transport",
751 tc_h->cfg,
752 &connect_cb,
753 &disconnect_cb,
754 tc_h,
755 mh);
756 GNUNET_assert (NULL != tc_h->sh);
757}
758
759
760/**
761 * @brief Task run at shutdown to kill communicator and clean up
762 *
763 * @param cls Closure - Process of communicator
764 */
765static void
766shutdown_process (struct GNUNET_OS_Process *proc)
767{
768 if (0 != GNUNET_OS_process_kill (proc, SIGTERM))
769 {
770 LOG (GNUNET_ERROR_TYPE_WARNING,
771 "Error shutting down process with SIGERM, trying SIGKILL\n");
772 if (0 != GNUNET_OS_process_kill (proc, SIGKILL))
773 {
774 LOG (GNUNET_ERROR_TYPE_ERROR,
775 "Error shutting down process with SIGERM and SIGKILL\n");
776 }
777 }
778 GNUNET_break (GNUNET_OK == GNUNET_OS_process_wait (proc));
779 GNUNET_OS_process_destroy (proc);
780}
781
782
783/**
784 * @brief Task run at shutdown to kill the statistics process
785 *
786 * @param cls Closure - Process of communicator
787 */
788static void
789shutdown_statistics (void *cls)
790{
791 struct GNUNET_OS_Process *proc = cls;
792 shutdown_process (proc);
793}
794
795
796/**
797 * @brief Task run at shutdown to kill the peerstore process
798 *
799 * @param cls Closure - Process of communicator
800 */
801static void
802shutdown_peerstore (void *cls)
803{
804 struct GNUNET_OS_Process *proc = cls;
805 shutdown_process (proc);
806}
807
808
809/**
810 * @brief Task run at shutdown to kill a communicator process
811 *
812 * @param cls Closure - Process of communicator
813 */
814static void
815shutdown_communicator (void *cls)
816{
817 struct GNUNET_OS_Process *proc = cls;
818 shutdown_process (proc);
819}
820
821
822/**
823 * @brief Start the communicator
824 *
825 * @param cfgname Name of the communicator
826 */
827static void
828communicator_start (
829 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
830 const char *binary_name)
831{
832 char *binary;
833 char *loprefix;
834 char *section_name;
835
836 LOG (GNUNET_ERROR_TYPE_DEBUG, "communicator_start\n");
837
838 section_name = strchr (binary_name, '-');
839 section_name++;
840
841 if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_string (tc_h->cfg,
842 section_name,
843 "PREFIX",
844 &loprefix))
845 loprefix = GNUNET_strdup ("");
846
847
848 binary = GNUNET_OS_get_libexec_binary_path (binary_name);
849 tc_h->c_proc = GNUNET_OS_start_process_s (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
850 NULL,
851 loprefix,
852 binary,
853 binary_name,
854 "-c",
855 tc_h->cfg_filename,
856 NULL);
857 GNUNET_free (loprefix);
858 if (NULL == tc_h->c_proc)
859 {
860 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start communicator!");
861 return;
862 }
863 LOG (GNUNET_ERROR_TYPE_INFO, "started communicator\n");
864 GNUNET_free (binary);
865}
866
867
868/**
869 * @brief Task run at shutdown to kill communicator and clean up
870 *
871 * @param cls Closure - Process of communicator
872 */
873static void
874shutdown_nat (void *cls)
875{
876 struct GNUNET_OS_Process *proc = cls;
877 shutdown_process (proc);
878}
879
880
881/**
882 * @brief Task run at shutdown to kill the resolver process
883 *
884 * @param cls Closure - Process of communicator
885 */
886static void
887shutdown_resolver (void *cls)
888{
889 struct GNUNET_OS_Process *proc = cls;
890 shutdown_process (proc);
891}
892
893
894/**
895 * @brief Start Resolver
896 *
897 */
898static void
899resolver_start (struct
900 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
901{
902 char *binary;
903
904 LOG (GNUNET_ERROR_TYPE_DEBUG, "resolver_start\n");
905 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-resolver");
906 tc_h->resolver_proc = GNUNET_OS_start_process (
907 GNUNET_OS_INHERIT_STD_OUT_AND_ERR
908 | GNUNET_OS_USE_PIPE_CONTROL,
909 NULL,
910 NULL,
911 NULL,
912 binary,
913 "gnunet-service-resolver",
914 "-c",
915 tc_h->cfg_filename,
916 NULL);
917 if (NULL == tc_h->resolver_proc)
918 {
919 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start resolver service!");
920 return;
921 }
922 LOG (GNUNET_ERROR_TYPE_INFO, "started resolver service\n");
923 GNUNET_free (binary);
924
925}
926
927
928/**
929 * @brief Start Statistics
930 *
931 */
932static void
933statistics_start (
934 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
935{
936 char *binary;
937
938 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-statistics");
939 tc_h->stat_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
940 NULL,
941 NULL,
942 NULL,
943 binary,
944 "gnunet-service-statistics",
945 "-c",
946 tc_h->cfg_filename,
947 NULL);
948 if (NULL == tc_h->stat_proc)
949 {
950 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start Statistics!");
951 return;
952 }
953 LOG (GNUNET_ERROR_TYPE_INFO, "started Statistics\n");
954 GNUNET_free (binary);
955}
956
957
958/**
959 * @brief Start Peerstore
960 *
961 */
962static void
963peerstore_start (
964 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
965{
966 char *binary;
967
968 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-peerstore");
969 tc_h->ps_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR,
970 NULL,
971 NULL,
972 NULL,
973 binary,
974 "gnunet-service-peerstore",
975 "-c",
976 tc_h->cfg_filename,
977 NULL);
978 if (NULL == tc_h->ps_proc)
979 {
980 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start Peerstore!");
981 return;
982 }
983 LOG (GNUNET_ERROR_TYPE_INFO, "started Peerstore\n");
984 GNUNET_free (binary);
985}
986
987
988/**
989 * @brief Start NAT
990 *
991 */
992static void
993nat_start (
994 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
995{
996 char *binary;
997
998 LOG (GNUNET_ERROR_TYPE_DEBUG, "nat_start\n");
999 binary = GNUNET_OS_get_libexec_binary_path ("gnunet-service-nat");
1000 tc_h->nat_proc = GNUNET_OS_start_process (GNUNET_OS_INHERIT_STD_OUT_AND_ERR
1001 | GNUNET_OS_USE_PIPE_CONTROL,
1002 NULL,
1003 NULL,
1004 NULL,
1005 binary,
1006 "gnunet-service-nat",
1007 "-c",
1008 tc_h->cfg_filename,
1009 NULL);
1010 if (NULL == tc_h->nat_proc)
1011 {
1012 GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Failed to start NAT!");
1013 return;
1014 }
1015 LOG (GNUNET_ERROR_TYPE_INFO, "started NAT\n");
1016 GNUNET_free (binary);
1017}
1018
1019
1020/**
1021 * @brief Start communicator part of transport service and communicator
1022 *
1023 * @param service_name Name of the service
1024 * @param cfg Configuration handle
1025 * @param communicator_available_cb Callback that is called when a new
1026 * @param add_address_cb Callback that is called when a new
1027 * communicator becomes available
1028 * @param cb_cls Closure to @a communicator_available_cb and @a
1029 *
1030 * @return Handle to the communicator duo
1031 */
1032struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
1033GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
1034 const char *service_name,
1035 const char *binary_name,
1036 const char *cfg_filename,
1037 const struct GNUNET_PeerIdentity *peer_id,
1038 GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback
1039 communicator_available_cb,
1040 GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb,
1041 GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb,
1042 GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb,
1043 GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb,
1044 GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb,
1045 void *cb_cls)
1046{
1047 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h;
1048
1049 LOG (GNUNET_ERROR_TYPE_DEBUG,
1050 "Starting new transport/communicator combo with config %s\n",
1051 cfg_filename);
1052 tc_h =
1053 GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle);
1054 tc_h->cfg_filename = GNUNET_strdup (cfg_filename);
1055 tc_h->cfg = GNUNET_CONFIGURATION_create ();
1056 if ((GNUNET_SYSERR == GNUNET_CONFIGURATION_load (tc_h->cfg, cfg_filename)))
1057 {
1058 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
1059 _ ("Malformed configuration file `%s', exit ...\n"),
1060 cfg_filename);
1061 GNUNET_free (tc_h->cfg_filename);
1062 GNUNET_CONFIGURATION_destroy (tc_h->cfg);
1063 GNUNET_free (tc_h);
1064 return NULL;
1065 }
1066 tc_h->bc_enabled = GNUNET_CONFIGURATION_get_value_yesno (tc_h->cfg,
1067 "communicator-test",
1068 "BACKCHANNEL_ENABLED");
1069 tc_h->communicator_available_cb = communicator_available_cb;
1070 tc_h->add_address_cb = add_address_cb;
1071 tc_h->queue_create_reply_cb = queue_create_reply_cb;
1072 tc_h->add_queue_cb = add_queue_cb;
1073 tc_h->incoming_msg_cb = incoming_message_cb;
1074 tc_h->bc_cb = bc_cb;
1075 tc_h->peer_id = *peer_id;
1076 tc_h->cb_cls = cb_cls;
1077
1078 /* Start communicator part of service */
1079 transport_communicator_start (tc_h);
1080 /* Start NAT */
1081 nat_start (tc_h);
1082 /* Start resolver service */
1083 resolver_start (tc_h);
1084 /* Start peerstore service */
1085 peerstore_start (tc_h);
1086 /* Start statistic service */
1087 statistics_start (tc_h);
1088 /* Schedule start communicator */
1089 communicator_start (tc_h,
1090 binary_name);
1091 return tc_h;
1092}
1093
1094
1095void
1096GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (
1097 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h)
1098{
1099 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *queue;
1100 shutdown_communicator (tc_h->c_proc);
1101 shutdown_service (tc_h->sh);
1102 shutdown_nat (tc_h->nat_proc);
1103 shutdown_resolver (tc_h->resolver_proc);
1104 shutdown_peerstore (tc_h->ps_proc);
1105 shutdown_statistics (tc_h->stat_proc);
1106 GNUNET_CONFIGURATION_destroy (tc_h->cfg);
1107 while (NULL != (queue = tc_h->queue_head))
1108 {
1109 GNUNET_CONTAINER_DLL_remove (tc_h->queue_head, tc_h->queue_tail, queue);
1110 GNUNET_free (queue);
1111 }
1112 GNUNET_free (tc_h->c_address);
1113 GNUNET_free (tc_h->cfg_filename);
1114 GNUNET_free (tc_h->c_addr_prefix);
1115 GNUNET_free (tc_h);
1116}
1117
1118
1119/**
1120 * @brief Instruct communicator to open a queue
1121 *
1122 * @param tc_h Handle to communicator which shall open queue
1123 * @param peer_id Towards which peer
1124 * @param address For which address
1125 */
1126void
1127GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (
1128 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
1129 const struct GNUNET_PeerIdentity *peer_id,
1130 const char *address)
1131{
1132 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
1133 static uint32_t idgen;
1134 char *prefix;
1135 struct GNUNET_TRANSPORT_CreateQueue *msg;
1136 struct GNUNET_MQ_Envelope *env;
1137 size_t alen;
1138
1139 tc_queue =
1140 GNUNET_new (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue);
1141 tc_queue->tc_h = tc_h;
1142 prefix = GNUNET_HELLO_address_to_prefix (address);
1143 if (NULL == prefix)
1144 {
1145 GNUNET_break (0); /* We got an invalid address!? */
1146 GNUNET_free (tc_queue);
1147 return;
1148 }
1149 GNUNET_free (prefix);
1150 alen = strlen (address) + 1;
1151 env =
1152 GNUNET_MQ_msg_extra (msg, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
1153 msg->request_id = htonl (idgen++);
1154 tc_queue->qid = msg->request_id;
1155 msg->receiver = *peer_id;
1156 tc_queue->peer_id = *peer_id;
1157 memcpy (&msg[1], address, alen);
1158 if (NULL != tc_h->c_mq)
1159 {
1160 LOG (GNUNET_ERROR_TYPE_DEBUG,
1161 "Sending queue create immediately\n");
1162 GNUNET_MQ_send (tc_h->c_mq, env);
1163 }
1164 else
1165 {
1166 tc_queue->open_queue_env = env;
1167 }
1168 GNUNET_CONTAINER_DLL_insert (tc_h->queue_head, tc_h->queue_tail, tc_queue);
1169}
1170
1171
1172void
1173GNUNET_TRANSPORT_TESTING_transport_communicator_send
1174 (struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h,
1175 GNUNET_SCHEDULER_TaskCallback cont,
1176 void *cont_cls,
1177 const void *payload,
1178 size_t payload_size)
1179{
1180 struct GNUNET_MessageHeader *mh;
1181 struct GNUNET_TRANSPORT_SendMessageTo *msg;
1182 struct GNUNET_MQ_Envelope *env;
1183 size_t inbox_size;
1184 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue;
1185 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *tc_queue_tmp;
1186 static struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorQueue *last_queue;
1187 tc_queue = NULL;
1188
1189 for (tc_queue_tmp = tc_h->queue_head;
1190 NULL != tc_queue_tmp;
1191 tc_queue_tmp = tc_queue_tmp->next)
1192 {
1193 if (tc_queue_tmp->q_len <= 0)
1194 continue;
1195 if (NULL == tc_queue)
1196 {
1197 LOG (GNUNET_ERROR_TYPE_DEBUG,
1198 "Selecting queue with prio %u, len %" PRIu64 " and MTU %u\n",
1199 tc_queue_tmp->priority,
1200 tc_queue_tmp->q_len,
1201 tc_queue_tmp->mtu);
1202 tc_queue = tc_queue_tmp;
1203 continue;
1204 }
1205 if (tc_queue->priority < tc_queue_tmp->priority)
1206 {
1207 LOG (GNUNET_ERROR_TYPE_DEBUG,
1208 "Selecting queue with prio %u, len %" PRIu64 " and MTU %u\n",
1209 tc_queue_tmp->priority,
1210 tc_queue_tmp->q_len,
1211 tc_queue_tmp->mtu);
1212 tc_queue = tc_queue_tmp;
1213 }
1214 }
1215 if (last_queue != tc_queue)
1216 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1217 "Selected sending queue changed to %u with length %lu and MTU %u\n",
1218 ntohl (tc_queue->qid), (unsigned long) tc_queue->q_len, tc_queue->mtu);
1219 GNUNET_assert (NULL != tc_queue);
1220 last_queue = tc_queue;
1221 // Uncomment this for alternativ 1 of backchannel functionality
1222 if (tc_queue->q_len != GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED)
1223 tc_queue->q_len--;
1224 // Until here for alternativ 1
1225 static int msg_count = 0;
1226 msg_count++;
1227 if (msg_count % 100 == 0)
1228 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
1229 "Sending %u-th (%lu-th for queue) message on queue %u\n",
1230 msg_count, (unsigned long) tc_queue->mid, ntohl (tc_queue->qid));
1231 inbox_size = sizeof (struct GNUNET_MessageHeader) + payload_size;
1232 env = GNUNET_MQ_msg_extra (msg,
1233 inbox_size,
1234 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
1235 GNUNET_assert (NULL != env);
1236 msg->qid = tc_queue->qid;
1237 msg->mid = tc_queue->mid++;
1238 msg->receiver = tc_queue->peer_id;
1239 mh = (struct GNUNET_MessageHeader *) &msg[1];
1240 mh->size = htons (inbox_size);
1241 mh->type = GNUNET_MESSAGE_TYPE_DUMMY;
1242 memcpy (&mh[1],
1243 payload,
1244 payload_size);
1245 if (NULL != cont)
1246 GNUNET_MQ_notify_sent (env,
1247 cont,
1248 cont_cls);
1249 GNUNET_MQ_send (tc_queue->tc_h->c_mq,
1250 env);
1251}
diff --git a/src/service/transport/transport-testing-communicator.h b/src/service/transport/transport-testing-communicator.h
new file mode 100644
index 000000000..7460aab8e
--- /dev/null
+++ b/src/service/transport/transport-testing-communicator.h
@@ -0,0 +1,370 @@
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_transport_communication_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 * Callback to call when message ack received.
286 */
287 GNUNET_SCHEDULER_TaskCallback cont;
288
289 /**
290 * Closure for cont
291 */
292 void *cont_cls;
293
294 /**
295 * Backchannel supported
296 */
297 int bc_enabled;
298};
299
300/**
301 * @brief Start communicator part of transport service and communicator
302 *
303 * @param service_name Name of the service
304 * @param cfg Configuration handle
305 * @param communicator_available Callback that is called when a new
306 * communicator becomes available
307 * @param add_address_cb Callback handling new addresses
308 * @param queue_create_reply_cb Callback handling success of queue requests
309 * @param add_queue_cb Callback handling freshly created queues
310 * @param incoming_message_cb Callback handling incoming messages
311 * @param cb_cls Closure to @p communicator_available
312 *
313 * @return Handle to the communicator duo
314 */
315struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *
316GNUNET_TRANSPORT_TESTING_transport_communicator_service_start (
317 const char *service_name,
318 const char *binary_name,
319 const char *cfg_filename,
320 const struct GNUNET_PeerIdentity *peer_id,
321 GNUNET_TRANSPORT_TESTING_CommunicatorAvailableCallback
322 communicator_available_cb,
323 GNUNET_TRANSPORT_TESTING_AddAddressCallback add_address_cb,
324 GNUNET_TRANSPORT_TESTING_QueueCreateReplyCallback queue_create_reply_cb,
325 GNUNET_TRANSPORT_TESTING_AddQueueCallback add_queue_cb,
326 GNUNET_TRANSPORT_TESTING_IncomingMessageCallback incoming_message_cb,
327 GNUNET_TRANSPORT_TESTING_BackchannelCallback bc_cb,
328 void *cb_cls);
329
330
331void
332GNUNET_TRANSPORT_TESTING_transport_communicator_service_stop (
333 struct GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle *tc_h);
334
335
336/**
337 * @brief Instruct communicator to open a queue
338 *
339 * @param tc_h Handle to communicator which shall open queue
340 * @param peer_id Towards which peer
341 * @param address For which address
342 */
343void
344GNUNET_TRANSPORT_TESTING_transport_communicator_open_queue (struct
345 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
346 *tc_h,
347 const struct
348 GNUNET_PeerIdentity
349 *peer_id,
350 const char *address);
351
352
353/**
354 * @brief Instruct communicator to send data
355 *
356 * @param tc_queue The queue to use for sending
357 * @param cont function to call when done sending
358 * @param cont_cls closure for @a cont
359 * @param payload Data to send
360 * @param payload_size Size of the @a payload
361 */
362void
363GNUNET_TRANSPORT_TESTING_transport_communicator_send (struct
364 GNUNET_TRANSPORT_TESTING_TransportCommunicatorHandle
365 *tc_h,
366 GNUNET_SCHEDULER_TaskCallback
367 cont,
368 void *cont_cls,
369 const void *payload,
370 size_t payload_size);
diff --git a/src/service/transport/transport-testing-filenames2.c b/src/service/transport/transport-testing-filenames2.c
new file mode 100644
index 000000000..59fa1ebd5
--- /dev/null
+++ b/src/service/transport/transport-testing-filenames2.c
@@ -0,0 +1,203 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-filenames.c
22 * @brief convenience string manipulation functions for tests
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "transport-testing2.h"
28
29
30/**
31 * Removes all directory separators from absolute filename
32 *
33 * @param file the absolute file name, e.g. as found in argv[0]
34 * @return extracted file name, has to be freed by caller
35 */
36static char *
37extract_filename (const char *file)
38{
39 char *pch = GNUNET_strdup (file);
40 char *backup = pch;
41 char *filename = NULL;
42 char *res;
43
44 if (NULL != strstr (pch, "/"))
45 {
46 pch = strtok (pch, "/");
47 while (pch != NULL)
48 {
49 pch = strtok (NULL, "/");
50 if (pch != NULL)
51 {
52 filename = pch;
53 }
54 }
55 }
56 else
57 filename = pch;
58
59 res = GNUNET_strdup (filename);
60 GNUNET_free (backup);
61 return res;
62}
63
64
65/**
66 * Extracts the test filename from an absolute file name and removes
67 * the extension
68 *
69 * @param file absolute file name
70 * @return the result
71 */
72char *
73GNUNET_TRANSPORT_TESTING_get_test_name (const char *file)
74{
75 char *backup = extract_filename (file);
76 char *filename = backup;
77 char *dotexe;
78 char *ret;
79
80 if (NULL == filename)
81 return NULL;
82
83 /* remove "lt-" */
84 filename = strstr (filename, "test");
85 if (NULL == filename)
86 {
87 GNUNET_free (backup);
88 return NULL;
89 }
90
91 /* remove ".exe" */
92 if (NULL != (dotexe = strstr (filename, ".exe")))
93 dotexe[0] = '\0';
94 ret = GNUNET_strdup (filename);
95 GNUNET_free (backup);
96 return ret;
97}
98
99
100/**
101 * Extracts the filename from an absolute file name and removes the extension
102 *
103 * @param file absolute file name
104 * @return the result
105 */
106char *
107GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file)
108{
109 char *src = extract_filename (file);
110 char *split;
111
112 split = strstr (src, ".");
113 if (NULL != split)
114 split[0] = '\0';
115 return src;
116}
117
118
119/**
120 * Extracts the plugin name from an absolute file name and the test name
121 *
122 * @param file absolute file name
123 * @param test test name
124 * @return the result
125 */
126char *
127GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
128 const char *test)
129{
130 char *filename;
131 char *dotexe;
132 char *e = extract_filename (file);
133 char *t = extract_filename (test);
134 char *ret;
135
136 if (NULL == e)
137 goto fail;
138 /* remove "lt-" */
139 filename = strstr (e, "tes");
140 if (NULL == filename)
141 goto fail;
142 /* remove ".exe" */
143 if (NULL != (dotexe = strstr (filename, ".exe")))
144 dotexe[0] = '\0';
145
146 /* find last _ */
147 filename = strstr (filename, t);
148 if (NULL == filename)
149 goto fail;
150 /* copy plugin */
151 filename += strlen (t);
152 if ('\0' != *filename)
153 filename++;
154 ret = GNUNET_strdup (filename);
155 goto suc;
156fail:
157 ret = NULL;
158suc:
159 GNUNET_free (t);
160 GNUNET_free (e);
161 return ret;
162}
163
164
165/**
166 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
167 * if existing ".exe"-prefix and adds the peer-number
168 *
169 * @param file filename of the test, e.g. argv[0]
170 * @param count peer number
171 * @return the result
172 */
173char *
174GNUNET_TRANSPORT_TESTING_get_config_name (const char *file,
175 int count)
176{
177 char *filename = extract_filename (file);
178 char *backup = filename;
179 char *dotexe;
180 char *ret;
181
182 if (NULL == filename)
183 return NULL;
184 /* remove "lt-" */
185 filename = strstr (filename, "test");
186 if (NULL == filename)
187 goto fail;
188 /* remove ".exe" */
189 if (NULL != (dotexe = strstr (filename, ".exe")))
190 dotexe[0] = '\0';
191 GNUNET_asprintf (&ret,
192 "%s_peer%u.conf",
193 filename,
194 count);
195 GNUNET_free (backup);
196 return ret;
197fail:
198 GNUNET_free (backup);
199 return NULL;
200}
201
202
203/* end of transport-testing-filenames.c */
diff --git a/src/service/transport/transport-testing-loggers2.c b/src/service/transport/transport-testing-loggers2.c
new file mode 100644
index 000000000..e6c79b78a
--- /dev/null
+++ b/src/service/transport/transport-testing-loggers2.c
@@ -0,0 +1,81 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-loggers.c
22 * @brief convenience functions for logging common events in tests
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "transport-testing2.h"
27
28
29/**
30 * Log a connect event.
31 *
32 * @param cls NULL
33 * @param me peer that had the event
34 * @param other peer that connected.
35 */
36void
37GNUNET_TRANSPORT_TESTING_log_connect (void *cls,
38 struct
39 GNUNET_TRANSPORT_TESTING_PeerContext *me,
40 const struct GNUNET_PeerIdentity *other)
41{
42 char *ps;
43
44 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
45 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
46 "Peer %s connected to %u (%s)!\n",
47 GNUNET_i2s (other),
48 me->no,
49 ps);
50 GNUNET_free (ps);
51}
52
53
54/**
55 * Log a disconnect event.
56 *
57 * @param cls NULL
58 * @param me peer that had the event
59 * @param other peer that disconnected.
60 */
61void
62GNUNET_TRANSPORT_TESTING_log_disconnect (void *cls,
63 struct
64 GNUNET_TRANSPORT_TESTING_PeerContext *
65 me,
66 const struct
67 GNUNET_PeerIdentity *other)
68{
69 char *ps;
70
71 ps = GNUNET_strdup (GNUNET_i2s (&me->id));
72 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
73 "Peer `%s' disconnected from %u (%s)!\n",
74 GNUNET_i2s (other),
75 me->no,
76 ps);
77 GNUNET_free (ps);
78}
79
80
81/* end of transport-testing-loggers.c */
diff --git a/src/service/transport/transport-testing-main2.c b/src/service/transport/transport-testing-main2.c
new file mode 100644
index 000000000..0a1710922
--- /dev/null
+++ b/src/service/transport/transport-testing-main2.c
@@ -0,0 +1,614 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-main.c
22 * @brief convenience main function for tests
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "transport-testing2.h"
27
28
29/**
30 * Closure for #connect_cb.
31 */
32struct GNUNET_TRANSPORT_TESTING_ConnectRequestList
33{
34 /**
35 * Stored in a DLL.
36 */
37 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *next;
38
39 /**
40 * Stored in a DLL.
41 */
42 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *prev;
43
44 /**
45 * Overall context we are in.
46 */
47 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
48
49 /**
50 * Connect request this is about.
51 */
52 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
53
54 /**
55 * Peer being connected.
56 */
57 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
58
59 /**
60 * Peer being connected.
61 */
62 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
63};
64
65
66/**
67 * Shutdown function for the test. Stops all peers.
68 *
69 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
70 */
71static void
72do_shutdown (void *cls)
73{
74 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
75 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
76
77 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
78 "Testcase shutting down\n");
79 if (NULL != ccc->shutdown_task)
80 ccc->shutdown_task (ccc->shutdown_task_cls);
81 if (NULL != ccc->timeout_task)
82 {
83 GNUNET_SCHEDULER_cancel (ccc->timeout_task);
84 ccc->timeout_task = NULL;
85 }
86 if (NULL != ccc->connect_task)
87 {
88 GNUNET_SCHEDULER_cancel (ccc->connect_task);
89 ccc->connect_task = NULL;
90 }
91 while (NULL != (crl = ccc->crl_head))
92 {
93 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
94 ccc->crl_tail,
95 crl);
96 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (crl->cr);
97 GNUNET_free (crl);
98 }
99 for (unsigned int i = 0; i < ccc->num_peers; i++)
100 {
101 if (NULL != ccc->p[i])
102 {
103 GNUNET_TRANSPORT_TESTING_stop_peer (ccc->p[i]);
104 ccc->p[i] = NULL;
105 }
106 }
107}
108
109
110/**
111 * Testcase hit timeout, shut it down with error.
112 *
113 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
114 */
115static void
116do_timeout (void *cls)
117{
118 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
119
120 ccc->timeout_task = NULL;
121 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
122 "Testcase timed out\n");
123 ccc->global_ret = GNUNET_SYSERR;
124 GNUNET_SCHEDULER_shutdown ();
125}
126
127
128/**
129 * Internal data structure. Closure for
130 * #connect_cb, #disconnect_cb, #my_nc and #start_cb.
131 * Allows us to identify which peer this is about.
132 */
133struct GNUNET_TRANSPORT_TESTING_InternalPeerContext
134{
135 /**
136 * Overall context of the callback.
137 */
138 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
139
140 /**
141 * Offset of the peer this is about.
142 */
143 unsigned int off;
144};
145
146
147/**
148 * Information tracked per connected peer.
149 */
150struct ConnectPairInfo
151{
152 /**
153 * Peer this is about.
154 */
155 const struct GNUNET_PeerIdentity *sender;
156
157 /**
158 * Information about the receiving peer.
159 */
160 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi;
161};
162
163
164/**
165 * Function called when we connected two peers. Once we have gotten
166 * to the clique, launch test-specific logic.
167 *
168 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *`
169 */
170static void
171connect_cb (void *cls)
172{
173 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl = cls;
174 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = crl->ccc;
175
176 GNUNET_CONTAINER_DLL_remove (ccc->crl_head,
177 ccc->crl_tail,
178 crl);
179 {
180 char *p1_c = GNUNET_strdup (GNUNET_i2s (&crl->p1->id));
181
182 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
183 "Peers connected: %u (%s) <-> %u (%s)\n",
184 crl->p1->no,
185 p1_c,
186 crl->p2->no,
187 GNUNET_i2s (&crl->p2->id));
188 GNUNET_free (p1_c);
189 GNUNET_free (crl);
190 }
191 if (NULL == ccc->crl_head)
192 {
193 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
194 "All connections UP, launching custom test logic.\n");
195 GNUNET_SCHEDULER_add_now (ccc->connect_continuation,
196 ccc->connect_continuation_cls);
197 }
198}
199
200
201/**
202 * Find peer by peer ID.
203 *
204 * @param ccc context to search
205 * @param peer peer to look for
206 * @return NULL if @a peer was not found
207 */
208struct GNUNET_TRANSPORT_TESTING_PeerContext *
209GNUNET_TRANSPORT_TESTING_find_peer (struct
210 GNUNET_TRANSPORT_TESTING_ConnectCheckContext
211 *ccc,
212 const struct GNUNET_PeerIdentity *peer)
213{
214 for (unsigned int i = 0; i < ccc->num_peers; i++)
215 if ((NULL != ccc->p[i]) &&
216 (0 == memcmp (peer,
217 &ccc->p[i]->id,
218 sizeof(*peer))))
219 return ccc->p[i];
220 return NULL;
221}
222
223
224/**
225 * Wrapper around peers connecting. Calls client's nc function.
226 *
227 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
228 * @param peer peer we got connected to
229 * @param mq message queue for transmissions to @a peer
230 * @return closure for message handlers
231 */
232static void *
233my_nc (void *cls,
234 const struct GNUNET_PeerIdentity *peer,
235 struct GNUNET_MQ_Handle *mq)
236{
237 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
238 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
239 struct ConnectPairInfo *cpi;
240
241 if (NULL != ccc->nc)
242 ccc->nc (ccc->cls,
243 ccc->p[ipi->off],
244 peer);
245 cpi = GNUNET_new (struct ConnectPairInfo);
246 cpi->ipi = ipi;
247 cpi->sender = peer; /* valid until disconnect */
248 return cpi;
249}
250
251
252/**
253 * Wrapper around peers disconnecting. Calls client's nd function.
254 *
255 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
256 * @param peer peer we got disconnected from
257 * @param custom_cls return value from @a my_nc
258 */
259static void
260my_nd (void *cls,
261 const struct GNUNET_PeerIdentity *peer,
262 void *custom_cls)
263{
264 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
265 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
266 struct ConnectPairInfo *cpi = custom_cls;
267
268 if (NULL != ccc->nd)
269 ccc->nd (ccc->cls,
270 ccc->p[ipi->off],
271 peer);
272 GNUNET_free (cpi);
273}
274
275
276/**
277 * Wrapper around receiving data. Calls client's rec function.
278 *
279 * @param cls our `struct ConnectPairInfo *`
280 * @param message message we received
281 * @return #GNUNET_OK (all messages are fine)
282 */
283static int
284check_test (void *cls,
285 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
286{
287 return GNUNET_OK;
288}
289
290
291/**
292 * Wrapper around receiving data. Calls client's rec function.
293 *
294 * @param cls our `struct ConnectPairInfo *`
295 * @param message message we received
296 */
297static void
298handle_test (void *cls,
299 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
300{
301 struct ConnectPairInfo *cpi = cls;
302 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
303 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
304
305 if (NULL != ccc->rec)
306 ccc->rec (ccc->cls,
307 ccc->p[ipi->off],
308 cpi->sender,
309 message);
310}
311
312
313/**
314 * Wrapper around receiving data. Calls client's rec function.
315 *
316 * @param cls our `struct ConnectPairInfo *`
317 * @param message message we received
318 * @return #GNUNET_OK (all messages are fine)
319 */
320static int
321check_test2 (void *cls,
322 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
323{
324 return GNUNET_OK;
325}
326
327
328/**
329 * Wrapper around receiving data. Calls client's rec function.
330 *
331 * @param cls our `struct ConnectPairInfo *`
332 * @param message message we received
333 */
334static void
335handle_test2 (void *cls,
336 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
337{
338 struct ConnectPairInfo *cpi = cls;
339 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cpi->ipi;
340 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
341
342 if (NULL != ccc->rec)
343 ccc->rec (ccc->cls,
344 ccc->p[ipi->off],
345 cpi->sender,
346 message);
347}
348
349
350/**
351 * Connect the peers as a clique.
352 *
353 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
354 */
355static void
356do_connect (void *cls)
357{
358 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
359
360 ccc->connect_task = NULL;
361 for (unsigned int i = 0; i < ccc->num_peers; i++)
362 for (unsigned int j = (ccc->bi_directional ? 0 : i + 1); j < ccc->num_peers;
363 j++)
364 {
365 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl;
366
367 if (i == j)
368 continue;
369 crl = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequestList);
370 GNUNET_CONTAINER_DLL_insert (ccc->crl_head,
371 ccc->crl_tail,
372 crl);
373 crl->ccc = ccc;
374 crl->p1 = ccc->p[i];
375 crl->p2 = ccc->p[j];
376 {
377 char *sender_c = GNUNET_strdup (GNUNET_i2s (&ccc->p[0]->id));
378
379 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
380 "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
381 ccc->p[0]->no,
382 sender_c,
383 ccc->p[1]->no,
384 GNUNET_i2s (&ccc->p[1]->id));
385 GNUNET_free (sender_c);
386 }
387 crl->cr = GNUNET_TRANSPORT_TESTING_connect_peers (ccc->p[i],
388 ccc->p[j],
389 &connect_cb,
390 crl);
391 }
392}
393
394
395/**
396 * Function called once we have successfully launched a peer.
397 * Once all peers have been launched, we connect all of them
398 * in a clique.
399 *
400 * @param cls our `struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *`
401 */
402static void
403start_cb (void *cls)
404{
405 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ipi = cls;
406 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = ipi->ccc;
407 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = ccc->p[ipi->off];
408
409 ccc->started++;
410 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
411 "Peer %u (`%s') started\n",
412 p->no,
413 GNUNET_i2s (&p->id));
414 if (ccc->started != ccc->num_peers)
415 return;
416 if (NULL != ccc->pre_connect_task)
417 {
418 /* Run the custom per-connect job, then give it a second to
419 go into effect before we continue connecting peers. */
420 ccc->pre_connect_task (ccc->pre_connect_task_cls);
421 ccc->connect_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
422 &do_connect,
423 ccc);
424 }
425 else
426 {
427 do_connect (ccc);
428 }
429}
430
431
432/**
433 * Function run from #GNUNET_TRANSPORT_TESTING_connect_check
434 * once the scheduler is up. Should launch the peers and
435 * then in the continuations try to connect them.
436 *
437 * @param cls our `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *`
438 * @param args ignored
439 * @param cfgfile ignored
440 * @param cfg configuration
441 */
442static void
443connect_check_run (void *cls,
444 char *const *args,
445 const char *cfgfile,
446 const struct GNUNET_CONFIGURATION_Handle *cfg)
447{
448 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
449 int ok;
450
451 ccc->cfg = cfg;
452 ccc->timeout_task = GNUNET_SCHEDULER_add_delayed (ccc->timeout,
453 &do_timeout,
454 ccc);
455 GNUNET_SCHEDULER_add_shutdown (&do_shutdown,
456 ccc);
457 ok = GNUNET_OK;
458 for (unsigned int i = 0; i < ccc->num_peers; i++)
459 {
460 struct GNUNET_MQ_MessageHandler handlers[] = {
461 GNUNET_MQ_hd_var_size (test,
462 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
463 struct GNUNET_TRANSPORT_TESTING_TestMessage,
464 NULL),
465 GNUNET_MQ_hd_var_size (test2,
466 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2,
467 struct GNUNET_TRANSPORT_TESTING_TestMessage,
468 NULL),
469 GNUNET_MQ_handler_end ()
470 };
471 ccc->p[i] = GNUNET_TRANSPORT_TESTING_start_peer (ccc->tth,
472 ccc->cfg_files[i],
473 i + 1,
474 handlers,
475 &my_nc,
476 &my_nd,
477 &ccc->ip[i],
478 &start_cb,
479 &ccc->ip[i]);
480 if (NULL == ccc->p[i])
481 ok = GNUNET_SYSERR;
482 }
483 if (GNUNET_OK != ok)
484 {
485 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
486 "Fail! Could not start peers!\n");
487 GNUNET_SCHEDULER_shutdown ();
488 }
489}
490
491
492/**
493 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
494 * Starts and connects the two peers, then invokes the
495 * `connect_continuation` from @a cls. Sets up a timeout to
496 * abort the test, and a shutdown handler to clean up properly
497 * on exit.
498 *
499 * @param cls closure of type `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
500 * @param tth_ initialized testing handle
501 * @param test_plugin_ name of the plugin
502 * @param test_name_ name of the test
503 * @param num_peers number of entries in the @a cfg_file array
504 * @param cfg_files array of names of configuration files for the peers
505 * @return #GNUNET_SYSERR on error
506 */
507int
508GNUNET_TRANSPORT_TESTING_connect_check (void *cls,
509 struct GNUNET_TRANSPORT_TESTING_Handle *
510 tth_,
511 const char *test_plugin_,
512 const char *test_name_,
513 unsigned int num_peers,
514 char *cfg_files[])
515{
516 static struct GNUNET_GETOPT_CommandLineOption options[] = {
517 GNUNET_GETOPT_OPTION_END
518 };
519 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc = cls;
520 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[num_peers];
521 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext ip[num_peers];
522 char *argv[] = {
523 (char *) test_name_,
524 "-c",
525 (char *) ccc->config_file,
526 NULL
527 };
528
529 ccc->num_peers = num_peers;
530 ccc->cfg_files = cfg_files;
531 ccc->test_plugin = test_plugin_;
532 ccc->test_name = test_name_;
533 ccc->tth = tth_;
534 ccc->global_ret = GNUNET_OK;
535 ccc->p = p;
536 ccc->ip = ip;
537 for (unsigned int i = 0; i < num_peers; i++)
538 {
539 ip[i].off = i;
540 ip[i].ccc = ccc;
541 }
542 if (GNUNET_OK !=
543 GNUNET_PROGRAM_run ((sizeof(argv) / sizeof(char *)) - 1,
544 argv,
545 test_name_,
546 "nohelp",
547 options,
548 &connect_check_run,
549 ccc))
550 return GNUNET_SYSERR;
551 return ccc->global_ret;
552}
553
554
555/**
556 * Setup testcase. Calls @a check with the data the test needs.
557 *
558 * @param argv0 binary name (argv[0])
559 * @param filename source file name (__FILE__)
560 * @param num_peers number of peers to start
561 * @param check main function to run
562 * @param check_cls closure for @a check
563 * @return #GNUNET_OK on success
564 */
565int
566GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
567 const char *filename,
568 unsigned int num_peers,
569 GNUNET_TRANSPORT_TESTING_CheckCallback check,
570 void *check_cls)
571{
572 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
573 char *test_name;
574 char *test_source;
575 char *test_plugin;
576 char *cfg_names[num_peers];
577 int ret;
578
579 ret = GNUNET_OK;
580 test_name = GNUNET_TRANSPORT_TESTING_get_test_name (argv0);
581 GNUNET_log_setup (test_name,
582 "WARNING",
583 NULL);
584 test_source = GNUNET_TRANSPORT_TESTING_get_test_source_name (filename);
585 test_plugin = GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv0,
586 test_source);
587 for (unsigned int i = 0; i < num_peers; i++)
588 cfg_names[i] = GNUNET_TRANSPORT_TESTING_get_config_name (argv0,
589 i + 1);
590 tth = GNUNET_TRANSPORT_TESTING_init ();
591 if (NULL == tth)
592 {
593 ret = GNUNET_SYSERR;
594 }
595 else
596 {
597 ret = check (check_cls,
598 tth,
599 test_plugin,
600 test_name,
601 num_peers,
602 cfg_names);
603 GNUNET_TRANSPORT_TESTING_done (tth);
604 }
605 for (unsigned int i = 0; i < num_peers; i++)
606 GNUNET_free (cfg_names[i]);
607 GNUNET_free (test_source);
608 GNUNET_free (test_plugin);
609 GNUNET_free (test_name);
610 return ret;
611}
612
613
614/* end of transport-testing-main.c */
diff --git a/src/service/transport/transport-testing-send2.c b/src/service/transport/transport-testing-send2.c
new file mode 100644
index 000000000..c48dc3a4a
--- /dev/null
+++ b/src/service/transport/transport-testing-send2.c
@@ -0,0 +1,241 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing-send.c
22 * @brief convenience transmission function for tests
23 * @author Christian Grothoff
24 */
25#include "platform.h"
26#include "transport-testing2.h"
27
28/**
29 * Acceptable transmission delay.
30 */
31#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply ( \
32 GNUNET_TIME_UNIT_SECONDS, 30)
33
34
35/**
36 * Return @a cx in @a cls.
37 */
38static void
39find_cr (void *cls,
40 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
41{
42 struct GNUNET_TRANSPORT_TESTING_ConnectRequest **cr = cls;
43
44 if (GNUNET_NO == cx->connected)
45 return;
46 *cr = cx;
47}
48
49
50/**
51 * Send a test message of type @a mtype and size @a msize from
52 * peer @a sender to peer @a receiver. The peers should be
53 * connected when this function is called.
54 *
55 * @param sender the sending peer
56 * @param receiver the receiving peer
57 * @param mtype message type to use
58 * @param msize size of the message, at least `sizeof (struct GNUNET_TRANSPORT_TESTING_TestMessage)`
59 * @param num unique message number
60 * @param cont continuation to call after transmission
61 * @param cont_cls closure for @a cont
62 * @return #GNUNET_OK if message was queued,
63 * #GNUNET_NO if peers are not connected
64 * #GNUNET_SYSERR if @a msize is illegal
65 */
66int
67GNUNET_TRANSPORT_TESTING_send (struct
68 GNUNET_TRANSPORT_TESTING_PeerContext *sender,
69 struct GNUNET_TRANSPORT_TESTING_PeerContext *
70 receiver,
71 uint16_t mtype,
72 uint16_t msize,
73 uint32_t num,
74 GNUNET_SCHEDULER_TaskCallback cont,
75 void *cont_cls)
76{
77 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cr;
78 struct GNUNET_MQ_Envelope *env;
79 struct GNUNET_TRANSPORT_TESTING_TestMessage *test;
80
81 if (msize < sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage))
82 {
83 GNUNET_break (0);
84 return GNUNET_SYSERR;
85 }
86 cr = NULL;
87 GNUNET_TRANSPORT_TESTING_find_connecting_context (sender,
88 receiver,
89 &find_cr,
90 &cr);
91 if (NULL == cr)
92 GNUNET_TRANSPORT_TESTING_find_connecting_context (receiver,
93 sender,
94 &find_cr,
95 &cr);
96 if (NULL == cr)
97 {
98 GNUNET_break (0);
99 return GNUNET_NO;
100 }
101 if (NULL == cr->mq)
102 {
103 GNUNET_break (0);
104 return GNUNET_NO;
105 }
106 {
107 char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
108
109 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
110 "Sending message from peer %u (`%s') -> peer %u (`%s') !\n",
111 sender->no,
112 GNUNET_i2s (&sender->id),
113 receiver->no,
114 receiver_s);
115 GNUNET_free (receiver_s);
116 }
117 env = GNUNET_MQ_msg_extra (test,
118 msize - sizeof(*test),
119 mtype);
120 test->num = htonl (num);
121 memset (&test[1],
122 num,
123 msize - sizeof(*test));
124 GNUNET_MQ_notify_sent (env,
125 cont,
126 cont_cls);
127 GNUNET_MQ_send (cr->mq,
128 env);
129 return GNUNET_OK;
130}
131
132
133/**
134 * Task that sends a test message from the
135 * first peer to the second peer.
136 *
137 * @param ccc context which should contain at least two peers, the
138 * first two of which should be currently connected
139 * @param size desired message size
140 * @param cont continuation to call after transmission
141 * @param cont_cls closure for @a cont
142 */
143static void
144do_send (struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
145 uint16_t size,
146 GNUNET_SCHEDULER_TaskCallback cont,
147 void *cont_cls)
148{
149 int ret;
150
151 ccc->global_ret = GNUNET_SYSERR;
152 ret = GNUNET_TRANSPORT_TESTING_send (ccc->p[0],
153 ccc->p[1],
154 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
155 size,
156 ccc->send_num_gen++,
157 cont,
158 cont_cls);
159 GNUNET_assert (GNUNET_SYSERR != ret);
160 if (GNUNET_NO == ret)
161 {
162 GNUNET_break (0);
163 ccc->global_ret = GNUNET_SYSERR;
164 GNUNET_SCHEDULER_shutdown ();
165 }
166}
167
168
169/**
170 * Task that sends a minimalistic test message from the
171 * first peer to the second peer.
172 *
173 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
174 * which should contain at least two peers, the first two
175 * of which should be currently connected
176 */
177void
178GNUNET_TRANSPORT_TESTING_simple_send (void *cls)
179{
180 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
181 int done;
182 size_t msize;
183
184 if (0 < sc->num_messages)
185 {
186 sc->num_messages--;
187 done = (0 == sc->num_messages);
188 }
189 else
190 {
191 done = 0; /* infinite loop */
192 }
193 msize = sizeof(struct GNUNET_TRANSPORT_TESTING_TestMessage);
194 if (NULL != sc->get_size_cb)
195 msize = sc->get_size_cb (sc->num_messages);
196 /* if this was the last message, call the continuation,
197 otherwise call this function again */
198 do_send (sc->ccc,
199 msize,
200 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_simple_send,
201 done ? sc->cont_cls : sc);
202}
203
204
205/**
206 * Task that sends a large test message from the
207 * first peer to the second peer.
208 *
209 * @param cls the `struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
210 * which should contain at least two peers, the first two
211 * of which should be currently connected
212 */
213void
214GNUNET_TRANSPORT_TESTING_large_send (void *cls)
215{
216 struct GNUNET_TRANSPORT_TESTING_SendClosure *sc = cls;
217 int done;
218 size_t msize;
219
220 if (0 < sc->num_messages)
221 {
222 sc->num_messages--;
223 done = (0 == sc->num_messages);
224 }
225 else
226 {
227 done = 0; /* infinite loop */
228 }
229 msize = 2600;
230 if (NULL != sc->get_size_cb)
231 msize = sc->get_size_cb (sc->num_messages);
232 /* if this was the last message, call the continuation,
233 otherwise call this function again */
234 do_send (sc->ccc,
235 msize,
236 done ? sc->cont : &GNUNET_TRANSPORT_TESTING_large_send,
237 done ? sc->cont_cls : sc);
238}
239
240
241/* end of transport-testing-send.c */
diff --git a/src/service/transport/transport-testing2.c b/src/service/transport/transport-testing2.c
new file mode 100644
index 000000000..877730630
--- /dev/null
+++ b/src/service/transport/transport-testing2.c
@@ -0,0 +1,871 @@
1/*
2 This file is part of GNUnet.
3 Copyright (C) 2006, 2009, 2015, 2016 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20/**
21 * @file transport-testing.c
22 * @brief testing lib for transport service
23 * @author Matthias Wachs
24 * @author Christian Grothoff
25 */
26#include "platform.h"
27#include "transport-testing2.h"
28
29
30#define LOG(kind, ...) GNUNET_log_from (kind, "transport-testing", __VA_ARGS__)
31
32
33static struct GNUNET_TRANSPORT_TESTING_PeerContext *
34find_peer_context (struct GNUNET_TRANSPORT_TESTING_Handle *tth,
35 const struct GNUNET_PeerIdentity *peer)
36{
37 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
38
39 for (t = tth->p_head; NULL != t; t = t->next)
40 if (0 == memcmp (&t->id,
41 peer,
42 sizeof(struct GNUNET_PeerIdentity)))
43 return t;
44 return NULL;
45}
46
47
48/**
49 * Find any connecting context matching the given pair of peers.
50 *
51 * @param p1 first peer
52 * @param p2 second peer
53 * @param cb function to call
54 * @param cb_cls closure for @a cb
55 */
56void
57GNUNET_TRANSPORT_TESTING_find_connecting_context (struct
58 GNUNET_TRANSPORT_TESTING_PeerContext
59 *p1,
60 struct
61 GNUNET_TRANSPORT_TESTING_PeerContext
62 *p2,
63 GNUNET_TRANSPORT_TESTING_ConnectContextCallback
64 cb,
65 void *cb_cls)
66{
67 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
68 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
69 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
70
71 for (cc = tth->cc_head; NULL != cc; cc = ccn)
72 {
73 ccn = cc->next;
74 if ((cc->p1 == p1) &&
75 (cc->p2 == p2))
76 cb (cb_cls,
77 cc);
78 }
79}
80
81
82static void
83set_p1c (void *cls,
84 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
85{
86 int *found = cls;
87
88 if (NULL != found)
89 *found = GNUNET_YES;
90 cx->p1_c = GNUNET_YES;
91}
92
93
94static void
95set_mq (void *cls,
96 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
97{
98 struct GNUNET_MQ_Handle *mq = cls;
99
100 cx->mq = mq;
101}
102
103
104static void
105set_p2c (void *cls,
106 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
107{
108 int *found = cls;
109
110 if (NULL != found)
111 *found = GNUNET_YES;
112 cx->p2_c = GNUNET_YES;
113}
114
115
116static void
117clear_p1c (void *cls,
118 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
119{
120 int *found = cls;
121
122 if (NULL != found)
123 *found = GNUNET_YES;
124 cx->p1_c = GNUNET_NO;
125}
126
127
128static void
129clear_p2c (void *cls,
130 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cx)
131{
132 int *found = cls;
133
134 if (NULL != found)
135 *found = GNUNET_YES;
136 cx->p2_c = GNUNET_NO;
137}
138
139
140static void *
141notify_connect (void *cls,
142 const struct GNUNET_PeerIdentity *peer,
143 struct GNUNET_MQ_Handle *mq)
144{
145 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
146 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
147 char *p2_s;
148 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
149 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
150 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
151 int found;
152 void *ret;
153
154 p2 = find_peer_context (p->tth,
155 peer);
156 if (NULL != p->nc)
157 ret = p->nc (p->cb_cls,
158 peer,
159 mq);
160 else
161 ret = NULL;
162
163 if (NULL != p2)
164 GNUNET_asprintf (&p2_s,
165 "%u (`%s')",
166 p2->no,
167 GNUNET_i2s (&p2->id));
168 else
169 GNUNET_asprintf (&p2_s,
170 "`%s'",
171 GNUNET_i2s (peer));
172 LOG (GNUNET_ERROR_TYPE_DEBUG,
173 "Peers %s connected to peer %u (`%s')\n",
174 p2_s,
175 p->no,
176 GNUNET_i2s (&p->id));
177 GNUNET_free (p2_s);
178 /* update flags in connecting contexts */
179 found = GNUNET_NO;
180 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
181 p2,
182 &set_p1c,
183 &found);
184 if (GNUNET_NO == found)
185 {
186 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
187 cc->p1 = p;
188 cc->p2 = p2;
189 cc->p1_c = GNUNET_YES;
190 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
191 tth->cc_tail,
192 cc);
193 }
194 found = GNUNET_NO;
195 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
196 p,
197 &set_p2c,
198 &found);
199 if (GNUNET_NO == found)
200 {
201 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
202 cc->p1 = p2;
203 cc->p2 = p;
204 cc->p1_c = GNUNET_YES;
205 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
206 tth->cc_tail,
207 cc);
208 }
209 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
210 p2,
211 &set_mq,
212 mq);
213 /* update set connected flag for all requests */
214 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
215 {
216 if (GNUNET_YES == cc->connected)
217 continue;
218 if ((GNUNET_YES == cc->p1_c) &&
219 (GNUNET_YES == cc->p2_c))
220 {
221 cc->connected = GNUNET_YES;
222 /* stop trying to connect */
223 if (NULL != cc->tct)
224 {
225 GNUNET_SCHEDULER_cancel (cc->tct);
226 cc->tct = NULL;
227 }
228 if (NULL != cc->ah_sh)
229 {
230 GNUNET_TRANSPORT_application_suggest_cancel (cc->ah_sh);
231 cc->ah_sh = NULL;
232 }
233 }
234 }
235 /* then notify application */
236 for (cc = tth->cc_head; NULL != cc; cc = ccn)
237 {
238 ccn = cc->next;
239 if ((GNUNET_YES == cc->connected) &&
240 (NULL != cc->cb))
241 {
242 cc->cb (cc->cb_cls);
243 cc->cb = NULL; /* only notify once! */
244 }
245 }
246 return ret;
247}
248
249
250static void
251notify_disconnect (void *cls,
252 const struct GNUNET_PeerIdentity *peer,
253 void *handler_cls)
254{
255 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
256 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
257 char *p2_s;
258 /* Find PeerContext */
259 int no = 0;
260 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2 = NULL;
261 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
262
263 p2 = find_peer_context (p->tth,
264 peer);
265 no = p->no;
266 if (NULL != p2)
267 GNUNET_asprintf (&p2_s,
268 "%u (`%s')",
269 p2->no,
270 GNUNET_i2s (&p2->id));
271 else
272 GNUNET_asprintf (&p2_s,
273 "`%s'",
274 GNUNET_i2s (peer));
275 LOG (GNUNET_ERROR_TYPE_DEBUG,
276 "Peers %s disconnected from peer %u (`%s')\n",
277 p2_s,
278 no,
279 GNUNET_i2s (&p->id));
280 GNUNET_free (p2_s);
281 /* notify about disconnect */
282 if (NULL != p->nd)
283 p->nd (p->cb_cls,
284 peer,
285 handler_cls);
286 if (NULL == p2)
287 return;
288 /* clear MQ, it is now invalid */
289 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
290 p2,
291 &set_mq,
292 NULL);
293 /* update set connected flags for all requests */
294 GNUNET_TRANSPORT_TESTING_find_connecting_context (p,
295 p2,
296 &clear_p1c,
297 NULL);
298 GNUNET_TRANSPORT_TESTING_find_connecting_context (p2,
299 p,
300 &clear_p2c,
301 NULL);
302 /* resume connectivity requests as necessary */
303 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
304 {
305 if (GNUNET_NO == cc->connected)
306 continue;
307 if ((GNUNET_YES != cc->p1_c) ||
308 (GNUNET_YES != cc->p2_c))
309 {
310 cc->connected = GNUNET_NO;
311 /* start trying to connect */
312 if (NULL == cc->ah_sh)
313 cc->ah_sh = GNUNET_TRANSPORT_application_suggest (cc->p1->ah,
314 &p2->id,
315 GNUNET_MQ_PRIO_BEST_EFFORT,
316 GNUNET_BANDWIDTH_ZERO);
317 }
318 }
319}
320
321
322static void
323retrieve_hello (void *cls);
324
325static void
326hello_iter_cb (void *cb_cls,
327 const struct GNUNET_PEERSTORE_Record *record,
328 const char *emsg)
329{
330 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cb_cls;
331 if (NULL == record)
332 {
333 p->pic = NULL;
334 if (NULL != p->start_cb)
335 p->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, p);
336 return;
337 }
338 // Check record type et al?
339 p->hello_size = record->value_size;
340 p->hello = GNUNET_malloc (p->hello_size);
341 memcpy (p->hello, record->value, p->hello_size);
342 p->hello[p->hello_size - 1] = '\0';
343
344 GNUNET_PEERSTORE_iteration_stop (p->pic);
345 p->pic = NULL;
346 if (NULL != p->start_cb)
347 {
348 LOG (GNUNET_ERROR_TYPE_DEBUG,
349 "Peer %u (`%s') successfully started\n",
350 p->no,
351 GNUNET_i2s (&p->id));
352 p->start_cb (p->start_cb_cls);
353 p->start_cb = NULL;
354 }
355}
356
357
358static void
359retrieve_hello (void *cls)
360{
361 struct GNUNET_TRANSPORT_TESTING_PeerContext *p = cls;
362 p->rh_task = NULL;
363 p->pic = GNUNET_PEERSTORE_iteration_start (p->ph,
364 "transport",
365 &p->id,
366 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
367 hello_iter_cb,
368 p);
369
370}
371
372
373struct GNUNET_TRANSPORT_TESTING_PeerContext *
374GNUNET_TRANSPORT_TESTING_start_peer (struct
375 GNUNET_TRANSPORT_TESTING_Handle *tth,
376 const char *cfgname,
377 int peer_id,
378 const struct
379 GNUNET_MQ_MessageHandler *handlers,
380 GNUNET_TRANSPORT_NotifyConnect nc,
381 GNUNET_TRANSPORT_NotifyDisconnect nd,
382 void *cb_cls,
383 GNUNET_SCHEDULER_TaskCallback start_cb,
384 void *start_cb_cls)
385{
386 char *emsg = NULL;
387 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
388 struct GNUNET_PeerIdentity dummy;
389 unsigned int i;
390
391 if (GNUNET_NO == GNUNET_DISK_file_test (cfgname))
392 {
393 LOG (GNUNET_ERROR_TYPE_ERROR,
394 "File not found: `%s'\n",
395 cfgname);
396 return NULL;
397 }
398
399 p = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_PeerContext);
400 p->tth = tth;
401 p->nc = nc;
402 p->nd = nd;
403 if (NULL != handlers)
404 {
405 for (i = 0; NULL != handlers[i].cb; i++)
406 ;
407 p->handlers = GNUNET_new_array (i + 1,
408 struct GNUNET_MQ_MessageHandler);
409 GNUNET_memcpy (p->handlers,
410 handlers,
411 i * sizeof(struct GNUNET_MQ_MessageHandler));
412 }
413 if (NULL != cb_cls)
414 p->cb_cls = cb_cls;
415 else
416 p->cb_cls = p;
417 p->start_cb = start_cb;
418 if (NULL != start_cb_cls)
419 p->start_cb_cls = start_cb_cls;
420 else
421 p->start_cb_cls = p;
422 GNUNET_CONTAINER_DLL_insert (tth->p_head,
423 tth->p_tail,
424 p);
425
426 /* Create configuration and call testing lib to modify it */
427 p->cfg = GNUNET_CONFIGURATION_create ();
428 GNUNET_assert (GNUNET_OK ==
429 GNUNET_CONFIGURATION_load (p->cfg, cfgname));
430 if (GNUNET_SYSERR ==
431 GNUNET_TESTING_configuration_create (tth->tl_system,
432 p->cfg))
433 {
434 LOG (GNUNET_ERROR_TYPE_ERROR,
435 "Testing library failed to create unique configuration based on `%s'\n",
436 cfgname);
437 GNUNET_CONFIGURATION_destroy (p->cfg);
438 GNUNET_free (p);
439 return NULL;
440 }
441
442 p->no = peer_id;
443 /* Configure peer with configuration */
444 p->peer = GNUNET_TESTING_peer_configure (tth->tl_system,
445 p->cfg,
446 p->no,
447 NULL,
448 &emsg);
449 if (NULL == p->peer)
450 {
451 LOG (GNUNET_ERROR_TYPE_ERROR,
452 "Testing library failed to create unique configuration based on `%s': `%s'\n",
453 cfgname,
454 emsg);
455 GNUNET_TRANSPORT_TESTING_stop_peer (p);
456 GNUNET_free (emsg);
457 return NULL;
458 }
459
460 if (GNUNET_OK != GNUNET_TESTING_peer_start (p->peer))
461 {
462 LOG (GNUNET_ERROR_TYPE_ERROR,
463 "Testing library failed to create unique configuration based on `%s'\n",
464 cfgname);
465 GNUNET_TRANSPORT_TESTING_stop_peer (p);
466 return NULL;
467 }
468
469 memset (&dummy,
470 '\0',
471 sizeof(dummy));
472 GNUNET_TESTING_peer_get_identity (p->peer,
473 &p->id);
474 if (0 == memcmp (&dummy,
475 &p->id,
476 sizeof(struct GNUNET_PeerIdentity)))
477 {
478 LOG (GNUNET_ERROR_TYPE_ERROR,
479 "Testing library failed to obtain peer identity for peer %u\n",
480 p->no);
481 GNUNET_TRANSPORT_TESTING_stop_peer (p);
482 return NULL;
483 }
484 LOG (GNUNET_ERROR_TYPE_DEBUG,
485 "Peer %u configured with identity `%s'\n",
486 p->no,
487 GNUNET_i2s_full (&p->id));
488 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
489 NULL,
490 handlers,
491 p,
492 &notify_connect,
493 &notify_disconnect);
494 if (NULL == p->th)
495 {
496 LOG (GNUNET_ERROR_TYPE_ERROR,
497 "Failed to connect to transport service for peer `%s': `%s'\n",
498 cfgname,
499 emsg);
500 GNUNET_TRANSPORT_TESTING_stop_peer (p);
501 GNUNET_free (emsg);
502 return NULL;
503 }
504 p->ah = GNUNET_TRANSPORT_application_init (p->cfg);
505 if (NULL == p->ah)
506 {
507 LOG (GNUNET_ERROR_TYPE_ERROR,
508 "Failed to connect to TNG service for peer `%s': `%s'\n",
509 cfgname,
510 emsg);
511 GNUNET_TRANSPORT_TESTING_stop_peer (p);
512 GNUNET_free (emsg);
513 return NULL;
514 }
515 p->ph = GNUNET_PEERSTORE_connect (p->cfg);
516 // FIXME Error handling
517 p->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, p);
518
519 return p;
520}
521
522
523int
524GNUNET_TRANSPORT_TESTING_restart_peer (struct
525 GNUNET_TRANSPORT_TESTING_PeerContext *p,
526 GNUNET_SCHEDULER_TaskCallback restart_cb,
527 void *restart_cb_cls)
528{
529 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
530 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
531
532 /* shutdown */
533 LOG (GNUNET_ERROR_TYPE_DEBUG,
534 "Stopping peer %u (`%s')\n",
535 p->no,
536 GNUNET_i2s (&p->id));
537 if (NULL != p->pic)
538 {
539 GNUNET_PEERSTORE_iteration_stop (p->pic);
540 p->pic = NULL;
541 }
542 if (NULL != p->th)
543 {
544 GNUNET_TRANSPORT_core_disconnect (p->th);
545 p->th = NULL;
546 }
547 for (cc = p->tth->cc_head; NULL != cc; cc = ccn)
548 {
549 ccn = cc->next;
550 if ((cc->p1 == p) ||
551 (cc->p2 == p))
552 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
553 }
554 if (NULL != p->ah)
555 {
556 GNUNET_TRANSPORT_application_done (p->ah);
557 p->ah = NULL;
558 }
559 if (GNUNET_SYSERR ==
560 GNUNET_TESTING_peer_stop (p->peer))
561 {
562 LOG (GNUNET_ERROR_TYPE_ERROR,
563 "Failed to stop peer %u (`%s')\n",
564 p->no,
565 GNUNET_i2s (&p->id));
566 return GNUNET_SYSERR;
567 }
568
569 sleep (5); // YUCK!
570
571 LOG (GNUNET_ERROR_TYPE_DEBUG,
572 "Restarting peer %u (`%s')\n",
573 p->no,
574 GNUNET_i2s (&p->id));
575 /* restart */
576 if (GNUNET_SYSERR == GNUNET_TESTING_peer_start (p->peer))
577 {
578 LOG (GNUNET_ERROR_TYPE_ERROR,
579 "Failed to restart peer %u (`%s')\n",
580 p->no,
581 GNUNET_i2s (&p->id));
582 return GNUNET_SYSERR;
583 }
584
585 GNUNET_assert (NULL == p->start_cb);
586 p->start_cb = restart_cb;
587 p->start_cb_cls = restart_cb_cls;
588
589 p->th = GNUNET_TRANSPORT_core_connect (p->cfg,
590 NULL,
591 p->handlers,
592 p,
593 &notify_connect,
594 &notify_disconnect);
595 GNUNET_assert (NULL != p->th);
596 p->ah = GNUNET_TRANSPORT_application_init (p->cfg);
597 p->pic = GNUNET_PEERSTORE_iteration_start (p->ph,
598 "transport",
599 &p->id,
600 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
601 hello_iter_cb,
602 p);
603 GNUNET_assert (NULL != p->pic);
604 return GNUNET_OK;
605}
606
607
608/**
609 * Shutdown the given peer
610 *
611 * @param p the peer
612 */
613void
614GNUNET_TRANSPORT_TESTING_stop_peer (struct
615 GNUNET_TRANSPORT_TESTING_PeerContext *p)
616{
617 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p->tth;
618 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
619 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
620 /* shutdown */
621 LOG (GNUNET_ERROR_TYPE_DEBUG,
622 "Stopping peer %u (`%s')\n",
623 p->no,
624 GNUNET_i2s (&p->id));
625
626 for (cc = tth->cc_head; NULL != cc; cc = ccn)
627 {
628 ccn = cc->next;
629 if ((cc->p1 == p) ||
630 (cc->p2 == p))
631 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
632 }
633 if (NULL != p->pic)
634 {
635 GNUNET_PEERSTORE_iteration_stop (p->pic);
636 p->pic = NULL;
637 }
638 if (NULL != p->th)
639 {
640 GNUNET_TRANSPORT_core_disconnect (p->th);
641 p->th = NULL;
642 }
643 if (NULL != p->ah)
644 {
645 GNUNET_TRANSPORT_application_done (p->ah);
646 p->ah = NULL;
647 }
648 if (NULL != p->ph)
649 {
650 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
651 "Disconnecting from PEERSTORE service\n");
652 GNUNET_PEERSTORE_disconnect (p->ph);
653 p->ph = NULL;
654 }
655
656 if (NULL != p->peer)
657 {
658 if (GNUNET_OK !=
659 GNUNET_TESTING_peer_stop (p->peer))
660 {
661 LOG (GNUNET_ERROR_TYPE_DEBUG,
662 "Testing lib failed to stop peer %u (`%s')\n",
663 p->no,
664 GNUNET_i2s (&p->id));
665 }
666 GNUNET_TESTING_peer_destroy (p->peer);
667 p->peer = NULL;
668 }
669 if (NULL != p->hello)
670 {
671 GNUNET_free (p->hello);
672 p->hello = NULL;
673 }
674 if (NULL != p->cfg)
675 {
676 GNUNET_CONFIGURATION_destroy (p->cfg);
677 p->cfg = NULL;
678 }
679 if (NULL != p->handlers)
680 {
681 GNUNET_free (p->handlers);
682 p->handlers = NULL;
683 }
684 GNUNET_CONTAINER_DLL_remove (tth->p_head,
685 tth->p_tail,
686 p);
687 LOG (GNUNET_ERROR_TYPE_DEBUG,
688 "Peer %u (`%s') stopped\n",
689 p->no,
690 GNUNET_i2s (&p->id));
691 if (NULL != p->rh_task)
692 GNUNET_SCHEDULER_cancel (p->rh_task);
693 p->rh_task = NULL;
694 GNUNET_free (p);
695}
696
697
698/**
699 * Function called after the HELLO was passed to the
700 * transport service.
701 * FIXME maybe schedule the application_validate somehow
702 */
703/*
704 static void
705 hello_offered (void *cls)
706 {
707 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc = cls;
708
709 cc->oh = NULL;
710 cc->tct = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
711 &offer_hello,
712 cc);
713 }*/
714
715
716/**
717 * Initiate a connection from p1 to p2 by offering p1 p2's HELLO message
718 *
719 * Remarks: start_peer's notify_connect callback can be called before.
720 *
721 * @param tth transport testing handle
722 * @param p1 peer 1
723 * @param p2 peer 2
724 * @param cb the callback to call when both peers notified that they are connected
725 * @param cls callback cls
726 * @return a connect request handle
727 */
728struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
729GNUNET_TRANSPORT_TESTING_connect_peers (struct
730 GNUNET_TRANSPORT_TESTING_PeerContext *p1,
731 struct
732 GNUNET_TRANSPORT_TESTING_PeerContext *p2,
733 GNUNET_SCHEDULER_TaskCallback cb,
734 void *cls)
735{
736 struct GNUNET_TRANSPORT_TESTING_Handle *tth = p1->tth;
737 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
738 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ccn;
739
740 ccn = NULL;
741 for (cc = tth->cc_head; NULL != cc; cc = cc->next)
742 {
743 if ((cc->p1 == p1) &&
744 (cc->p2 == p2))
745 {
746 ccn = cc;
747 break;
748 }
749 }
750
751 cc = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_ConnectRequest);
752 cc->p1 = p1;
753 cc->p2 = p2;
754 cc->cb = cb;
755 if (NULL != cls)
756 cc->cb_cls = cls;
757 else
758 cc->cb_cls = cc;
759 if (NULL != ccn)
760 {
761 cc->p1_c = ccn->p1_c;
762 cc->p2_c = ccn->p2_c;
763 cc->connected = ccn->connected;
764 }
765 GNUNET_CONTAINER_DLL_insert (tth->cc_head,
766 tth->cc_tail,
767 cc);
768 cc->ah_sh = GNUNET_TRANSPORT_application_suggest (cc->p1->ah,
769 &p2->id,
770 GNUNET_MQ_PRIO_BEST_EFFORT,
771 GNUNET_BANDWIDTH_ZERO);
772 LOG (GNUNET_ERROR_TYPE_DEBUG,
773 "New connect request %p\n",
774 cc);
775 return cc;
776}
777
778
779void
780GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
781 GNUNET_TRANSPORT_TESTING_ConnectRequest
782 *cc)
783{
784 struct GNUNET_TRANSPORT_TESTING_Handle *tth = cc->p1->tth;
785
786 LOG (GNUNET_ERROR_TYPE_DEBUG,
787 "Canceling connect request!\n");
788 if (NULL != cc->tct)
789 {
790 GNUNET_SCHEDULER_cancel (cc->tct);
791 cc->tct = NULL;
792 }
793 if (NULL != cc->ah_sh)
794 {
795 GNUNET_TRANSPORT_application_suggest_cancel (cc->ah_sh);
796 cc->ah_sh = NULL;
797 }
798 GNUNET_CONTAINER_DLL_remove (tth->cc_head,
799 tth->cc_tail,
800 cc);
801 GNUNET_free (cc);
802}
803
804
805/**
806 * Clean up the transport testing
807 *
808 * @param tth transport testing handle
809 */
810void
811GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth)
812{
813 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc;
814 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *ct;
815 struct GNUNET_TRANSPORT_TESTING_PeerContext *p;
816 struct GNUNET_TRANSPORT_TESTING_PeerContext *t;
817
818 if (NULL == tth)
819 return;
820 cc = tth->cc_head;
821 while (NULL != cc)
822 {
823 ct = cc->next;
824 LOG (GNUNET_ERROR_TYPE_ERROR,
825 "Developer forgot to cancel connect request!\n");
826 GNUNET_TRANSPORT_TESTING_connect_peers_cancel (cc);
827 cc = ct;
828 }
829 p = tth->p_head;
830 while (NULL != p)
831 {
832 t = p->next;
833 LOG (GNUNET_ERROR_TYPE_ERROR,
834 "Developer forgot to stop peer!\n");
835 GNUNET_TRANSPORT_TESTING_stop_peer (p);
836 p = t;
837 }
838 GNUNET_TESTING_system_destroy (tth->tl_system,
839 GNUNET_YES);
840
841 GNUNET_free (tth);
842}
843
844
845/**
846 * Initialize the transport testing
847 *
848 * @return transport testing handle
849 */
850struct GNUNET_TRANSPORT_TESTING_Handle *
851GNUNET_TRANSPORT_TESTING_init ()
852{
853 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
854
855 tth = GNUNET_new (struct GNUNET_TRANSPORT_TESTING_Handle);
856 tth->tl_system = GNUNET_TESTING_system_create ("transport-testing",
857 NULL,
858 NULL,
859 NULL);
860 if (NULL == tth->tl_system)
861 {
862 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
863 "Failed to initialize testing library!\n");
864 GNUNET_free (tth);
865 return NULL;
866 }
867 return tth;
868}
869
870
871/* end of transport-testing.c */
diff --git a/src/service/transport/transport-testing2.h b/src/service/transport/transport-testing2.h
new file mode 100644
index 000000000..a68c9df38
--- /dev/null
+++ b/src/service/transport/transport-testing2.h
@@ -0,0 +1,940 @@
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_peerstore_service.h"
32#include "gnunet_transport_core_service.h"
33#include "gnunet_transport_application_service.h"
34#include "gnunet_testing_lib.h"
35
36
37/* ************* Basic functions for starting/stopping/connecting *********** */
38
39/**
40 * Context for a single peer
41 */
42struct GNUNET_TRANSPORT_TESTING_PeerContext;
43
44/**
45 * Definition for a transport testing handle
46 */
47struct GNUNET_TRANSPORT_TESTING_Handle;
48
49
50/**
51 * Context for a single peer
52 */
53struct GNUNET_TRANSPORT_TESTING_PeerContext
54{
55 /**
56 * Next element in the DLL
57 */
58 struct GNUNET_TRANSPORT_TESTING_PeerContext *next;
59
60 /**
61 * Previous element in the DLL
62 */
63 struct GNUNET_TRANSPORT_TESTING_PeerContext *prev;
64
65 /**
66 * Transport testing handle this peer belongs to
67 */
68 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
69
70 /**
71 * Application handle
72 */
73 struct GNUNET_TRANSPORT_ApplicationHandle *ah;
74
75 /**
76 * Peer's configuration
77 */
78 struct GNUNET_CONFIGURATION_Handle *cfg;
79
80 /**
81 * Peer's transport service handle
82 */
83 struct GNUNET_TRANSPORT_CoreHandle *th;
84
85 /**
86 * Peer's PEERSTORE Handle
87 */
88 struct GNUNET_PEERSTORE_Handle *ph;
89
90 /**
91 * Peer's transport get hello handle to retrieve peer's HELLO message
92 */
93 struct GNUNET_PEERSTORE_IterateContext *pic;
94
95 /**
96 * Hello
97 */
98 char *hello;
99
100 /**
101 * Hello size
102 */
103 size_t hello_size;
104
105 /**
106 * Peer's testing handle
107 */
108 struct GNUNET_TESTING_Peer *peer;
109
110 /**
111 * Peer identity
112 */
113 struct GNUNET_PeerIdentity id;
114
115 /**
116 * Handle for the peer's ARM process
117 */
118 struct GNUNET_OS_Process *arm_proc;
119
120 /**
121 * Receive callback
122 */
123 struct GNUNET_MQ_MessageHandler *handlers;
124
125 /**
126 * Notify connect callback
127 */
128 GNUNET_TRANSPORT_NotifyConnect nc;
129
130 /**
131 * Notify disconnect callback
132 */
133 GNUNET_TRANSPORT_NotifyDisconnect nd;
134
135 /**
136 * Startup completed callback
137 */
138 GNUNET_SCHEDULER_TaskCallback start_cb;
139
140 /**
141 * Hello get task
142 */
143 struct GNUNET_SCHEDULER_Task *rh_task;
144
145 /**
146 * Closure for the @a nc and @a nd callbacks
147 */
148 void *cb_cls;
149
150 /**
151 * Closure for @e start_cb.
152 */
153 void *start_cb_cls;
154
155 /**
156 * An unique number to identify the peer
157 */
158 unsigned int no;
159};
160
161
162/**
163 * Handle for a request to connect two peers.
164 */
165struct GNUNET_TRANSPORT_TESTING_ConnectRequest
166{
167 /**
168 * Kept in a DLL.
169 */
170 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *next;
171
172 /**
173 * Kept in a DLL.
174 */
175 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *prev;
176
177 /**
178 * Peer we want to connect.
179 */
180 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1;
181
182 /**
183 * Peer we want to connect.
184 */
185 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2;
186
187 /**
188 * Task by which we accomplish the connection.
189 */
190 struct GNUNET_SCHEDULER_Task *tct;
191
192 /**
193 * Handle by which we ask TNG to facilitate the connection.
194 */
195 struct GNUNET_TRANSPORT_ApplicationSuggestHandle *ah_sh;
196
197 /**
198 * Function to call upon completion.
199 */
200 GNUNET_SCHEDULER_TaskCallback cb;
201
202 /**
203 * Closure for @e cb.
204 */
205 void *cb_cls;
206
207 /**
208 * Message queue for sending from @a p1 to @a p2.
209 */
210 struct GNUNET_MQ_Handle *mq;
211
212 /**
213 * Set if peer1 says the connection is up to peer2.
214 */
215 int p1_c;
216
217 /**
218 * Set if peer2 says the connection is up to peer1.
219 */
220 int p2_c;
221
222 /**
223 * #GNUNET_YES if both @e p1_c and @e p2_c are #GNUNET_YES.
224 */
225 int connected;
226};
227
228
229/**
230 * Handle for a test run.
231 */
232struct GNUNET_TRANSPORT_TESTING_Handle
233{
234 /**
235 * Testing library system handle
236 */
237 struct GNUNET_TESTING_System *tl_system;
238
239 /**
240 * head DLL of connect contexts
241 */
242 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_head;
243
244 /**
245 * head DLL of connect contexts
246 */
247 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc_tail;
248
249 /**
250 * head DLL of peers
251 */
252 struct GNUNET_TRANSPORT_TESTING_PeerContext *p_head;
253
254 /**
255 * tail DLL of peers
256 */
257 struct GNUNET_TRANSPORT_TESTING_PeerContext *p_tail;
258};
259
260
261/**
262 * Initialize the transport testing
263 *
264 * @return transport testing handle
265 */
266struct GNUNET_TRANSPORT_TESTING_Handle *
267GNUNET_TRANSPORT_TESTING_init (void);
268
269
270/**
271 * Clean up the transport testing
272 *
273 * @param tth transport testing handle
274 */
275void
276GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_Handle *tth);
277
278
279/**
280 * Start a peer with the given configuration
281 *
282 * @param tth the testing handle
283 * @param cfgname configuration file
284 * @param peer_id an identification number for the peer
285 * @param handlers functions for receiving messages
286 * @param nc connect callback
287 * @param nd disconnect callback
288 * @param cb_cls closure for @a nc and @a nd callback
289 * @param start_cb start callback
290 * @param start_cb_cls closure for @a start_cb
291 * @return the peer context
292 */
293struct GNUNET_TRANSPORT_TESTING_PeerContext *
294GNUNET_TRANSPORT_TESTING_start_peer (
295 struct GNUNET_TRANSPORT_TESTING_Handle *tth,
296 const char *cfgname,
297 int peer_id,
298 const struct GNUNET_MQ_MessageHandler *handlers,
299 GNUNET_TRANSPORT_NotifyConnect nc,
300 GNUNET_TRANSPORT_NotifyDisconnect nd,
301 void *cb_cls,
302 GNUNET_SCHEDULER_TaskCallback start_cb,
303 void *start_cb_cls);
304
305
306/**
307 * Shutdown the given peer
308 *
309 * @param p the peer
310 */
311void
312GNUNET_TRANSPORT_TESTING_stop_peer (
313 struct GNUNET_TRANSPORT_TESTING_PeerContext *pc);
314
315
316/**
317 * Stops and restarts the given peer, sleeping (!) for 5s in between.
318 *
319 * @param p the peer
320 * @param restart_cb restart callback
321 * @param restart_cb_cls callback closure
322 * @return #GNUNET_OK in success otherwise #GNUNET_SYSERR
323 */
324int
325GNUNET_TRANSPORT_TESTING_restart_peer (
326 struct GNUNET_TRANSPORT_TESTING_PeerContext *p,
327 GNUNET_SCHEDULER_TaskCallback restart_cb,
328 void *restart_cb_cls);
329
330
331/**
332 * Connect the given peers and call the callback when both peers
333 * report the inbound connection. Remarks: start_peer's notify_connect
334 * callback can be called before.
335 *
336 * @param p1 peer 1
337 * @param p2 peer 2
338 * @param cb the callback to call when both peers notified that they are
339 * connected
340 * @param cls callback cls
341 * @return a connect request handle
342 */
343struct GNUNET_TRANSPORT_TESTING_ConnectRequest *
344GNUNET_TRANSPORT_TESTING_connect_peers (
345 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
346 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
347 GNUNET_SCHEDULER_TaskCallback cb,
348 void *cls);
349
350
351/**
352 * Cancel the request to connect two peers. You MUST cancel the
353 * request if you stop the peers before the peers connected
354 * successfully.
355 *
356 * @param cc a connect request handle
357 */
358void
359GNUNET_TRANSPORT_TESTING_connect_peers_cancel (
360 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc);
361
362
363/**
364 * Function called on matching connect requests.
365 *
366 * @param cls closure
367 * @param cc request matching the query
368 */
369typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContextCallback) (
370 void *cls,
371 struct GNUNET_TRANSPORT_TESTING_ConnectRequest *cc);
372
373
374/**
375 * Find any connecting context matching the given pair of peers.
376 *
377 * @param p1 first peer
378 * @param p2 second peer
379 * @param cb function to call
380 * @param cb_cls closure for @a cb
381 */
382void
383GNUNET_TRANSPORT_TESTING_find_connecting_context (
384 struct GNUNET_TRANSPORT_TESTING_PeerContext *p1,
385 struct GNUNET_TRANSPORT_TESTING_PeerContext *p2,
386 GNUNET_TRANSPORT_TESTING_ConnectContextCallback cb,
387 void *cb_cls);
388
389
390/* ********************** high-level process functions *************** */
391
392
393/**
394 * Function called once the peers have been launched and
395 * connected by #GNUNET_TRANSPORT_TESTING_connect_check().
396 *
397 * @param cls closure
398 * @param num_peers size of the @a p array
399 * @param p the peers that were launched
400 */
401typedef void (*GNUNET_TRANSPORT_TESTING_ConnectContinuation) (
402 void *cls,
403 unsigned int num_peers,
404 struct GNUNET_TRANSPORT_TESTING_PeerContext *p[]);
405
406
407/**
408 * Internal data structure.
409 */
410struct GNUNET_TRANSPORT_TESTING_ConnectRequestList;
411
412/**
413 * Internal data structure.
414 */
415struct GNUNET_TRANSPORT_TESTING_InternalPeerContext;
416
417
418GNUNET_NETWORK_STRUCT_BEGIN
419struct GNUNET_TRANSPORT_TESTING_TestMessage
420{
421 /**
422 * Type is (usually) #GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE.
423 */
424 struct GNUNET_MessageHeader header;
425
426 /**
427 * Monotonically increasing counter throughout the test.
428 */
429 uint32_t num GNUNET_PACKED;
430};
431
432struct GNUNET_TRANSPORT_TESTING_PerformanceTestMessage
433{
434 /**
435 * Type is (usually) #GNUNET_TRANSPORT_TESTING_SIMPLE_PERFORMANCE_MTYPE.
436 */
437 struct GNUNET_MessageHeader header;
438
439 /**
440 * Time this message was send via transport api.
441 */
442 struct GNUNET_TIME_AbsoluteNBO time_send;
443
444 /**
445 * Monotonically increasing counter throughout the test.
446 */
447 uint32_t num GNUNET_PACKED;
448};
449
450GNUNET_NETWORK_STRUCT_END
451
452
453/**
454 * Function called by the transport for each received message.
455 *
456 * @param cls closure
457 * @param receiver receiver of the message
458 * @param sender sender of the message
459 * @param message the message
460 */
461typedef void (*GNUNET_TRANSPORT_TESTING_ReceiveCallback) (
462 void *cls,
463 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
464 const struct GNUNET_PeerIdentity *sender,
465 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message);
466
467
468/**
469 * Function called to notify transport users that another
470 * peer connected to us.
471 *
472 * @param cls closure
473 * @param me peer experiencing the event
474 * @param other peer that connected to @a me
475 */
476typedef void (*GNUNET_TRANSPORT_TESTING_NotifyConnect) (
477 void *cls,
478 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
479 const struct GNUNET_PeerIdentity *other);
480
481
482/**
483 * Function called to notify transport users that another
484 * peer disconnected from us.
485 *
486 * @param cls closure
487 * @param me peer experiencing the event
488 * @param other peer that disconnected from @a me
489 */
490typedef void (*GNUNET_TRANSPORT_TESTING_NotifyDisconnect) (
491 void *cls,
492 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
493 const struct GNUNET_PeerIdentity *other);
494
495
496/**
497 * Closure that must be passed to
498 * #GNUNET_TRANSPORT_TESTING_connect_check.
499 */
500struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext
501{
502 /**
503 * How should we continue after the connect?
504 */
505 GNUNET_SCHEDULER_TaskCallback connect_continuation;
506
507 /**
508 * Closure for @e connect_continuation.
509 */
510 void *connect_continuation_cls;
511
512 /**
513 * Which configuration file should we pass to the
514 * #GNUNET_PROGRAM_run() of the testcase?
515 */
516 const char *config_file;
517
518 /**
519 * Receiver argument to give for peers we start.
520 */
521 GNUNET_TRANSPORT_TESTING_ReceiveCallback rec;
522
523 /**
524 * Notify connect argument to give for peers we start.
525 */
526 GNUNET_TRANSPORT_TESTING_NotifyConnect nc;
527
528 /**
529 * Notify disconnect argument to give for peers we start.
530 */
531 GNUNET_TRANSPORT_TESTING_NotifyDisconnect nd;
532
533 /**
534 * Closure for @e rec, @e nc and @e nd.
535 */
536 void *cls;
537
538 /**
539 * Custom task to run on shutdown.
540 */
541 GNUNET_SCHEDULER_TaskCallback shutdown_task;
542
543 /**
544 * Closure for @e shutdown_task.
545 */
546 void *shutdown_task_cls;
547
548 /**
549 * Custom task to run after peers were started but before we try to
550 * connect them. If this function is set, we wait ONE second after
551 * running this function until we continue with connecting the
552 * peers.
553 */
554 GNUNET_SCHEDULER_TaskCallback pre_connect_task;
555
556 /**
557 * Closure for @e shutdown_task.
558 */
559 void *pre_connect_task_cls;
560
561 /**
562 * When should the testcase time out?
563 */
564 struct GNUNET_TIME_Relative timeout;
565
566 /**
567 * Should we try to create connections in both directions?
568 */
569 int bi_directional;
570
571 /* ******* fields set by #GNUNET_TRANSPORT_TESTING_connect_check **** */
572
573 /**
574 * Number of peers involved in the test.
575 */
576 unsigned int num_peers;
577
578 /**
579 * Configuration files we have, array with @e num_peers entries.
580 */
581 char **cfg_files;
582
583 /**
584 * Array with @e num_peers entries.
585 */
586 struct GNUNET_TRANSPORT_TESTING_PeerContext **p;
587
588 /**
589 * Name of the plugin.
590 */
591 const char *test_plugin;
592
593 /**
594 * Name of the testcase.
595 */
596 const char *test_name;
597
598 /**
599 * Configuration object for the testcase.
600 */
601 const struct GNUNET_CONFIGURATION_Handle *cfg;
602
603 /**
604 * Main testing handle.
605 */
606 struct GNUNET_TRANSPORT_TESTING_Handle *tth;
607
608 /**
609 * Result from the main function, set to #GNUNET_OK on success.
610 * Clients should set to #GNUNET_SYSERR to indicate test failure.
611 */
612 int global_ret;
613
614 /**
615 * Generator for the `num` field in test messages. Incremented each
616 * time #GNUNET_TRANSPORT_TESTING_simple_send or
617 * #GNUNET_TRANSPORT_TESTING_large_send are used to transmit a
618 * message.
619 */
620 uint32_t send_num_gen;
621
622 /* ******* internal state, clients should not mess with this **** */
623
624 /**
625 * Task run on timeout.
626 */
627 struct GNUNET_SCHEDULER_Task *timeout_task;
628
629 /**
630 * Task run to connect peers.
631 */
632 struct GNUNET_SCHEDULER_Task *connect_task;
633
634 /**
635 * Number of peers that have been started.
636 */
637 unsigned int started;
638
639 /**
640 * DLL of active connect requests.
641 */
642 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_head;
643
644 /**
645 * DLL of active connect requests.
646 */
647 struct GNUNET_TRANSPORT_TESTING_ConnectRequestList *crl_tail;
648
649 /**
650 * Array with @e num_peers entries.
651 */
652 struct GNUNET_TRANSPORT_TESTING_InternalPeerContext *ip;
653};
654
655
656/**
657 * Find peer by peer ID.
658 *
659 * @param ccc context to search
660 * @param peer peer to look for
661 * @return NULL if @a peer was not found
662 */
663struct GNUNET_TRANSPORT_TESTING_PeerContext *
664GNUNET_TRANSPORT_TESTING_find_peer (
665 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc,
666 const struct GNUNET_PeerIdentity *peer);
667
668
669/**
670 * Common implementation of the #GNUNET_TRANSPORT_TESTING_CheckCallback.
671 * Starts and connects the two peers, then invokes the
672 * `connect_continuation` from @a cls. Sets up a timeout to
673 * abort the test, and a shutdown handler to clean up properly
674 * on exit.
675 *
676 * @param cls closure of type `struct
677 * GNUNET_TRANSPORT_TESTING_ConnectCheckContext`
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 */
685int
686GNUNET_TRANSPORT_TESTING_connect_check (
687 void *cls,
688 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
689 const char *test_plugin_,
690 const char *test_name_,
691 unsigned int num_peers,
692 char *cfg_files[]);
693
694
695/**
696 * Main function of a testcase. Called with the initial setup data
697 * for the test as derived from the source name and the binary name.
698 *
699 * @param cls closure
700 * @param tth_ initialized testing handle
701 * @param test_plugin_ name of the plugin
702 * @param test_name_ name of the test
703 * @param num_peers number of entries in the @a cfg_file array
704 * @param cfg_files array of names of configuration files for the peers
705 * @return #GNUNET_SYSERR on error
706 */
707typedef int (*GNUNET_TRANSPORT_TESTING_CheckCallback) (
708 void *cls,
709 struct GNUNET_TRANSPORT_TESTING_Handle *tth_,
710 const char *test_plugin_,
711 const char *test_name_,
712 unsigned int num_peers,
713 char *cfg_files[]);
714
715
716/**
717 * Setup testcase. Calls @a check with the data the test needs.
718 *
719 * @param argv0 binary name (argv[0])
720 * @param filename source file name (__FILE__)
721 * @param num_peers number of peers to start
722 * @param check main function to run
723 * @param check_cls closure for @a check
724 * @return #GNUNET_OK on success
725 */
726int
727GNUNET_TRANSPORT_TESTING_main_ (const char *argv0,
728 const char *filename,
729 unsigned int num_peers,
730 GNUNET_TRANSPORT_TESTING_CheckCallback check,
731 void *check_cls);
732
733
734/**
735 * Setup testcase. Calls @a check with the data the test needs.
736 *
737 * @param num_peers number of peers to start
738 * @param check main function to run
739 * @param check_cls closure for @a check
740 * @return #GNUNET_OK on success
741 */
742#define GNUNET_TRANSPORT_TESTING_main(num_peers, check, check_cls) \
743 GNUNET_TRANSPORT_TESTING_main_ (argv[0], \
744 __FILE__, \
745 num_peers, \
746 check, \
747 check_cls)
748
749/* ***************** Convenience functions for sending ********* */
750
751/**
752 * Send a test message of type @a mtype and size @a msize from
753 * peer @a sender to peer @a receiver. The peers should be
754 * connected when this function is called.
755 *
756 * @param sender the sending peer
757 * @param receiver the receiving peer
758 * @param mtype message type to use
759 * @param msize size of the message, at least `sizeof (struct
760 * GNUNET_TRANSPORT_TESTING_TestMessage)`
761 * @param num unique message number
762 * @param cont continuation to call after transmission
763 * @param cont_cls closure for @a cont
764 * @return #GNUNET_OK if message was queued,
765 * #GNUNET_NO if peers are not connected
766 * #GNUNET_SYSERR if @a msize is illegal
767 */
768int
769GNUNET_TRANSPORT_TESTING_send (
770 struct GNUNET_TRANSPORT_TESTING_PeerContext *sender,
771 struct GNUNET_TRANSPORT_TESTING_PeerContext *receiver,
772 uint16_t mtype,
773 uint16_t msize,
774 uint32_t num,
775 GNUNET_SCHEDULER_TaskCallback cont,
776 void *cont_cls);
777
778
779/**
780 * Message type used by #GNUNET_TRANSPORT_TESTING_simple_send().
781 */
782#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE 12345
783
784/**
785 * Alternative message type for tests.
786 */
787#define GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE2 12346
788
789/**
790 * Message type used by #().
791 */
792#define GNUNET_TRANSPORT_TESTING_SIMPLE_PERFORMANCE_MTYPE 12347
793
794/**
795 * Type of the closure argument to pass to
796 * #GNUNET_TRANSPORT_TESTING_simple_send() and
797 * #GNUNET_TRANSPORT_TESTING_large_send().
798 */
799struct GNUNET_TRANSPORT_TESTING_SendClosure
800{
801 /**
802 * Context for the transmission.
803 */
804 struct GNUNET_TRANSPORT_TESTING_ConnectCheckContext *ccc;
805
806 /**
807 * Function that returns the desired message size. Overrides
808 * the message size, can be NULL in which case the message
809 * size is the default.
810 */
811 size_t (*get_size_cb) (unsigned int n);
812
813 /**
814 * Number of messages to be transmitted in a loop.
815 * Use zero for "forever" (until external shutdown).
816 */
817 unsigned int num_messages;
818
819 /**
820 * Function to call after all transmissions, can be NULL.
821 */
822 GNUNET_SCHEDULER_TaskCallback cont;
823
824 /**
825 * Closure for @e cont.
826 */
827 void *cont_cls;
828};
829
830
831/**
832 * Task that sends a minimalistic test message from the
833 * first peer to the second peer.
834 *
835 * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure`
836 * which should contain at least two peers, the first two
837 * of which should be currently connected
838 */
839void
840GNUNET_TRANSPORT_TESTING_simple_send (void *cls);
841
842/**
843 * Size of a message sent with
844 * #GNUNET_TRANSPORT_TESTING_large_send(). Big enough
845 * to usually force defragmentation.
846 */
847#define GNUNET_TRANSPORT_TESTING_LARGE_MESSAGE_SIZE 2600
848
849/**
850 * Task that sends a large test message from the
851 * first peer to the second peer.
852 *
853 * @param cls the `struct GNUNET_TRANSPORT_TESTING_SendClosure`
854 * which should contain at least two peers, the first two
855 * of which should be currently connected
856 */
857void
858GNUNET_TRANSPORT_TESTING_large_send (void *cls);
859
860
861/* ********************** log-only convenience functions ************* */
862
863
864/**
865 * Log a connect event.
866 *
867 * @param cls NULL
868 * @param me peer that had the event
869 * @param other peer that connected.
870 */
871void
872GNUNET_TRANSPORT_TESTING_log_connect (
873 void *cls,
874 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
875 const struct GNUNET_PeerIdentity *other);
876
877
878/**
879 * Log a disconnect event.
880 *
881 * @param cls NULL
882 * @param me peer that had the event
883 * @param other peer that disconnected.
884 */
885void
886GNUNET_TRANSPORT_TESTING_log_disconnect (
887 void *cls,
888 struct GNUNET_TRANSPORT_TESTING_PeerContext *me,
889 const struct GNUNET_PeerIdentity *other);
890
891
892/* ********************** low-level filename functions *************** */
893
894
895/**
896 * Extracts the test filename from an absolute file name and removes
897 * the extension.
898 *
899 * @param file absolute file name
900 * @return resulting test name
901 */
902char *
903GNUNET_TRANSPORT_TESTING_get_test_name (const char *file);
904
905
906/**
907 * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
908 * if existing ".exe"-prefix and adds the peer-number
909 *
910 * @param file filename of the test, e.g. argv[0]
911 * @param count peer number
912 * @return configuration name to use
913 */
914char *
915GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, int count);
916
917
918/**
919 * Extracts the plugin anme from an absolute file name and the test name
920 * @param file absolute file name
921 * @param test test name
922 * @return the plugin name
923 */
924char *
925GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *executable,
926 const char *testname);
927
928
929/**
930 * Extracts the filename from an absolute file name and removes the
931 * extension
932 *
933 * @param file absolute file name
934 * @return the source name
935 */
936char *
937GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file);
938
939#endif
940/* end of transport_testing.h */
diff --git a/src/service/transport/transport.conf.in b/src/service/transport/transport.conf.in
new file mode 100644
index 000000000..6fb8e9ad7
--- /dev/null
+++ b/src/service/transport/transport.conf.in
@@ -0,0 +1,32 @@
1[transport]
2START_ON_DEMAND = @START_ON_DEMAND@
3@JAVAPORT@PORT = 2091
4HOSTNAME = localhost
5BINARY = gnunet-service-transport
6# PREFIX = valgrind
7
8ACCEPT_FROM = 127.0.0.1;
9ACCEPT_FROM6 = ::1;
10UNIXPATH = $GNUNET_RUNTIME_DIR/gnunet-service-transport.sock
11# USERNAME =
12# DISABLEV6 =
13# REJECT_FROM =
14# REJECT_FROM6 =
15# BINDTO =
16
17[communicator-tcp]
18#PREFIX = valgrind --leak-check=full --track-origins=yes
19BINDTO = 2086
20DISABLE_V6 = NO
21BINARY = gnunet-communicator-tcp
22IMMEDIATE_START = YES
23
24[communicator-udp]
25#PREFIX = valgrind --leak-check=full --track-origins=yes --trace-children=yes --log-file=$GNUNET_TEST_HOME/vg_cupeer1-%p
26BINARY = gnunet-communicator-udp
27BINDTO = 2086
28DISABLE_V6 = NO
29IMMEDIATE_START = YES
30
31[communicator-quic]
32BINDTO = 127.0.0.1
diff --git a/src/service/transport/transport.h b/src/service/transport/transport.h
new file mode 100644
index 000000000..66f17ee5b
--- /dev/null
+++ b/src/service/transport/transport.h
@@ -0,0 +1,828 @@
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_util_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 * Similar to GNUNET_TRANSPORT_NotifyDisconnect but in and out quotas are
38 * included here. These values are not required outside transport_api
39 *
40 * @param cls closure
41 * @param peer the peer that connected
42 * @param bandwidth_in inbound bandwidth in NBO
43 * @param bandwidth_out outbound bandwidth in NBO
44 *
45 */
46typedef void (*NotifyConnect) (
47 void *cls,
48 const struct GNUNET_PeerIdentity *peer,
49 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
50 struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out);
51
52
53GNUNET_NETWORK_STRUCT_BEGIN
54
55
56/**
57 * Message from the transport service to the library
58 * asking to check if both processes agree about this
59 * peers identity.
60 */
61struct StartMessage
62{
63 /**
64 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_START
65 */
66 struct GNUNET_MessageHeader header;
67
68 /**
69 * 0: no options
70 * 1: The @e self field should be checked
71 * 2: this client is interested in payload traffic
72 */
73 uint32_t options;
74
75 /**
76 * Identity we think we have. If it does not match, the
77 * receiver should print out an error message and disconnect.
78 */
79 struct GNUNET_PeerIdentity self;
80};
81
82
83/**
84 * Message from the transport service to the library
85 * informing about neighbors.
86 */
87struct ConnectInfoMessage
88{
89 /**
90 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT
91 */
92 struct GNUNET_MessageHeader header;
93
94#if (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
95 defined(GNUNET_TRANSPORT_CORE_VERSION))
96
97 /**
98 * Always zero, for alignment.
99 */
100 uint32_t reserved GNUNET_PACKED;
101#else
102 /**
103 * Current outbound quota for this peer
104 */
105 struct GNUNET_BANDWIDTH_Value32NBO quota_out;
106#endif
107
108 /**
109 * Identity of the new neighbour.
110 */
111 struct GNUNET_PeerIdentity id;
112};
113
114
115/**
116 * Message from the transport service to the library
117 * informing about disconnects.
118 */
119struct DisconnectInfoMessage
120{
121 /**
122 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT
123 */
124 struct GNUNET_MessageHeader header;
125
126 /**
127 * Reserved, always zero.
128 */
129 uint32_t reserved GNUNET_PACKED;
130
131 /**
132 * Who got disconnected?
133 */
134 struct GNUNET_PeerIdentity peer;
135};
136
137
138/**
139 * Message used to notify the transport API about a message
140 * received from the network. The actual message follows.
141 */
142struct InboundMessage
143{
144 /**
145 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_RECV
146 */
147 struct GNUNET_MessageHeader header;
148
149 /**
150 * Which peer sent the message?
151 */
152 struct GNUNET_PeerIdentity peer;
153};
154
155
156/**
157 * Message used to notify the transport API that it can
158 * send another message to the transport service.
159 */
160struct SendOkMessage
161{
162 /**
163 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK
164 */
165 struct GNUNET_MessageHeader header;
166
167#if (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
168 defined(GNUNET_TRANSPORT_CORE_VERSION))
169
170 uint32_t reserved GNUNET_PACKED;
171#else
172 /**
173 * #GNUNET_OK if the transmission succeeded,
174 * #GNUNET_SYSERR if it failed (i.e. network disconnect);
175 * in either case, it is now OK for this client to
176 * send us another message for the given peer.
177 */
178 uint16_t success GNUNET_PACKED;
179
180 /**
181 * Size of message sent
182 */
183 uint16_t bytes_msg GNUNET_PACKED;
184
185 /**
186 * Size of message sent over wire.
187 * Includes plugin and protocol specific overheads.
188 */
189 uint32_t bytes_physical GNUNET_PACKED;
190#endif
191
192 /**
193 * Which peer can send more now?
194 */
195 struct GNUNET_PeerIdentity peer;
196};
197
198
199/**
200 * Message used to notify the transport API that it can
201 * send another message to the transport service.
202 * (Used to implement flow control.)
203 */
204struct RecvOkMessage
205{
206 /**
207 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK
208 */
209 struct GNUNET_MessageHeader header;
210
211 /**
212 * Number of messages by which to increase the window, greater or
213 * equal to one.
214 */
215 uint32_t increase_window_delta GNUNET_PACKED;
216
217 /**
218 * Which peer can CORE handle more from now?
219 */
220 struct GNUNET_PeerIdentity peer;
221};
222
223
224/**
225 * Message used to notify the transport service about a message
226 * to be transmitted to another peer. The actual message follows.
227 */
228struct OutboundMessage
229{
230 /**
231 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND
232 */
233 struct GNUNET_MessageHeader header;
234
235 /**
236 * An `enum GNUNET_MQ_PriorityPreferences` in NBO.
237 */
238 uint32_t priority GNUNET_PACKED;
239
240#if ! (defined(GNUNET_TRANSPORT_COMMUNICATION_VERSION) || \
241 defined(GNUNET_TRANSPORT_CORE_VERSION))
242
243 /**
244 * Allowed delay.
245 */
246 struct GNUNET_TIME_RelativeNBO timeout;
247#endif
248
249 /**
250 * Which peer should receive the message?
251 */
252 struct GNUNET_PeerIdentity peer;
253};
254
255
256/* *********************** TNG messages ***************** */
257
258/**
259 * Communicator goes online. Note which addresses it can
260 * work with.
261 */
262struct GNUNET_TRANSPORT_CommunicatorAvailableMessage
263{
264 /**
265 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR.
266 */
267 struct GNUNET_MessageHeader header;
268
269 /**
270 * NBO encoding of `enum GNUNET_TRANSPORT_CommunicatorCharacteristics`
271 */
272 uint32_t cc;
273
274 /* Followed by the address prefix of the communicator */
275};
276
277
278/**
279 * Add address to the list.
280 */
281struct GNUNET_TRANSPORT_AddAddressMessage
282{
283 /**
284 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS.
285 */
286 struct GNUNET_MessageHeader header;
287
288 /**
289 * Address identifier (used during deletion).
290 */
291 uint32_t aid GNUNET_PACKED;
292
293 /**
294 * When does the address expire?
295 */
296 struct GNUNET_TIME_RelativeNBO expiration;
297
298 /**
299 * An `enum GNUNET_NetworkType` in NBO.
300 */
301 uint32_t nt;
302
303 /* followed by UTF-8 encoded, 0-terminated human-readable address */
304};
305
306
307/**
308 * Remove address from the list.
309 */
310struct GNUNET_TRANSPORT_DelAddressMessage
311{
312 /**
313 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS.
314 */
315 struct GNUNET_MessageHeader header;
316
317 /**
318 * Address identifier.
319 */
320 uint32_t aid GNUNET_PACKED;
321};
322
323
324/**
325 * Inform transport about an incoming message.
326 */
327struct GNUNET_TRANSPORT_IncomingMessage
328{
329 /**
330 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG.
331 */
332 struct GNUNET_MessageHeader header;
333
334 /**
335 * Do we use flow control or not?
336 */
337 uint32_t fc_on GNUNET_PACKED;
338
339 /**
340 * 64-bit number to identify the matching ACK.
341 */
342 uint64_t fc_id GNUNET_PACKED;
343
344 /**
345 * How long does the communicator believe the address on which
346 * the message was received to remain valid?
347 */
348 struct GNUNET_TIME_RelativeNBO expected_address_validity;
349
350 /**
351 * Sender identifier.
352 */
353 struct GNUNET_PeerIdentity sender;
354
355 /**
356 * Direct neighbour sender identifier.
357 */
358 struct GNUNET_PeerIdentity neighbour_sender;
359
360 /* followed by the message */
361};
362
363
364/**
365 * Transport informs us about being done with an incoming message.
366 * (only sent if fc_on was set).
367 */
368struct GNUNET_TRANSPORT_IncomingMessageAck
369{
370 /**
371 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK.
372 */
373 struct GNUNET_MessageHeader header;
374
375 /**
376 * Reserved (0)
377 */
378 uint32_t reserved GNUNET_PACKED;
379
380 /**
381 * Which message is being ACKed?
382 */
383 uint64_t fc_id GNUNET_PACKED;
384
385 /**
386 * Sender identifier of the original message.
387 */
388 struct GNUNET_PeerIdentity sender;
389};
390
391
392/**
393 * Add queue to the transport
394 */
395struct GNUNET_TRANSPORT_AddQueueMessage
396{
397 /**
398 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP.
399 */
400 struct GNUNET_MessageHeader header;
401
402 /**
403 * Queue identifier (used to identify the queue).
404 */
405 uint32_t qid GNUNET_PACKED;
406
407 /**
408 * Receiver that can be addressed via the queue.
409 */
410 struct GNUNET_PeerIdentity receiver;
411
412 /**
413 * An `enum GNUNET_NetworkType` in NBO.
414 */
415 uint32_t nt;
416
417 /**
418 * Maximum transmission unit, in NBO. UINT32_MAX for unlimited.
419 */
420 uint32_t mtu;
421
422 /**
423 * Queue length, in NBO. Defines how many messages may be
424 * send through this queue. UINT64_MAX for unlimited.
425 */
426 uint64_t q_len;
427
428 /**
429 * Priority of the queue in relation to other queues.
430 */
431 uint32_t priority;
432
433 /**
434 * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO.
435 */
436 uint32_t cs;
437
438 /* followed by UTF-8 encoded, 0-terminated human-readable address */
439};
440
441
442/**
443 * Update queue
444 */
445struct GNUNET_TRANSPORT_UpdateQueueMessage
446{
447 /**
448 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP.
449 */
450 struct GNUNET_MessageHeader header;
451
452 /**
453 * Queue identifier (used to identify the queue).
454 */
455 uint32_t qid GNUNET_PACKED;
456
457 /**
458 * Receiver that can be addressed via the queue.
459 */
460 struct GNUNET_PeerIdentity receiver;
461
462 /**
463 * An `enum GNUNET_NetworkType` in NBO.
464 */
465 uint32_t nt;
466
467 /**
468 * Maximum transmission unit, in NBO. UINT32_MAX for unlimited.
469 */
470 uint32_t mtu;
471
472 /**
473 * Queue length, in NBO. Defines how many messages may be
474 * send through this queue. UINT64_MAX for unlimited.
475 */
476 uint64_t q_len;
477
478 /**
479 * Priority of the queue in relation to other queues.
480 */
481 uint32_t priority;
482
483 /**
484 * An `enum GNUNET_TRANSPORT_ConnectionStatus` in NBO.
485 */
486 uint32_t cs;
487};
488
489
490/**
491 * Remove queue, it is no longer available.
492 */
493struct GNUNET_TRANSPORT_DelQueueMessage
494{
495 /**
496 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN.
497 */
498 struct GNUNET_MessageHeader header;
499
500 /**
501 * Address identifier.
502 */
503 uint32_t qid GNUNET_PACKED;
504
505 /**
506 * Receiver that can be addressed via the queue.
507 */
508 struct GNUNET_PeerIdentity receiver;
509};
510
511
512/**
513 * Transport tells communicator that it wants a new queue.
514 */
515struct GNUNET_TRANSPORT_CreateQueue
516{
517 /**
518 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE.
519 */
520 struct GNUNET_MessageHeader header;
521
522 /**
523 * Unique ID for the request.
524 */
525 uint32_t request_id GNUNET_PACKED;
526
527 /**
528 * Receiver that can be addressed via the queue.
529 */
530 struct GNUNET_PeerIdentity receiver;
531
532 /* followed by UTF-8 encoded, 0-terminated human-readable address */
533};
534
535
536/**
537 * Communicator tells transport how queue creation went down.
538 */
539struct GNUNET_TRANSPORT_CreateQueueResponse
540{
541 /**
542 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK or
543 * #GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL.
544 */
545 struct GNUNET_MessageHeader header;
546
547 /**
548 * Unique ID for the request.
549 */
550 uint32_t request_id GNUNET_PACKED;
551};
552
553
554/**
555 * Inform communicator about transport's desire to send a message.
556 */
557struct GNUNET_TRANSPORT_SendMessageTo
558{
559 /**
560 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG.
561 */
562 struct GNUNET_MessageHeader header;
563
564 /**
565 * Which queue should we use?
566 */
567 uint32_t qid GNUNET_PACKED;
568
569 /**
570 * Message ID, used for flow control.
571 */
572 uint64_t mid GNUNET_PACKED;
573
574 /**
575 * Receiver identifier.
576 */
577 struct GNUNET_PeerIdentity receiver;
578
579 /* followed by the message */
580};
581
582
583/**
584 * Inform transport that message was sent.
585 */
586struct GNUNET_TRANSPORT_SendMessageToAck
587{
588 /**
589 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK.
590 */
591 struct GNUNET_MessageHeader header;
592
593 /**
594 * Success (#GNUNET_OK), failure (#GNUNET_SYSERR).
595 */
596 uint32_t status GNUNET_PACKED;
597
598 /**
599 * Message ID of the original message.
600 */
601 uint64_t mid GNUNET_PACKED;
602
603 /**
604 * Queue ID for the queue which was used to send the message.
605 */
606 uint32_t qid GNUNET_PACKED;
607
608 /**
609 * Receiver identifier.
610 */
611 struct GNUNET_PeerIdentity receiver;
612};
613
614
615/**
616 * Message from communicator to transport service asking for
617 * transmission of a backchannel message with the given peer @e pid
618 * and communicator.
619 */
620struct GNUNET_TRANSPORT_CommunicatorBackchannel
621{
622 /**
623 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL
624 */
625 struct GNUNET_MessageHeader header;
626
627 /**
628 * Always zero, for alignment.
629 */
630 uint32_t reserved;
631
632 /**
633 * Target peer.
634 */
635 struct GNUNET_PeerIdentity pid;
636
637 /* Followed by a `struct GNUNET_MessageHeader` with the encapsulated
638 message to the communicator */
639
640 /* Followed by the 0-terminated string specifying the desired
641 communicator at the target (@e pid) peer */
642};
643
644
645/**
646 * Message from transport to communicator passing along a backchannel
647 * message from the given peer @e pid.
648 */
649struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming
650{
651 /**
652 * Type will be
653 * #GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING
654 */
655 struct GNUNET_MessageHeader header;
656
657 /**
658 * Always zero, for alignment.
659 */
660 uint32_t reserved;
661
662 /**
663 * Origin peer.
664 */
665 struct GNUNET_PeerIdentity pid;
666
667 /* Followed by a `struct GNUNET_MessageHeader` with the encapsulated
668 message to the communicator */
669};
670
671
672/**
673 * Request to start monitoring.
674 */
675struct GNUNET_TRANSPORT_MonitorStart
676{
677 /**
678 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START.
679 */
680 struct GNUNET_MessageHeader header;
681
682 /**
683 * #GNUNET_YES for one-shot montoring, #GNUNET_NO for continuous monitoring.
684 */
685 uint32_t one_shot;
686
687 /**
688 * Target identifier to monitor, all zeros for "all peers".
689 */
690 struct GNUNET_PeerIdentity peer;
691};
692
693
694/**
695 * Monitoring data.
696 */
697struct GNUNET_TRANSPORT_MonitorData
698{
699 /**
700 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_DATA.
701 */
702 struct GNUNET_MessageHeader header;
703
704 /**
705 * Network type (an `enum GNUNET_NetworkType` in NBO).
706 */
707 uint32_t nt GNUNET_PACKED;
708
709 /**
710 * Target identifier.
711 */
712 struct GNUNET_PeerIdentity peer;
713
714 /**
715 * @deprecated To be discussed if we keep these...
716 */
717 struct GNUNET_TIME_AbsoluteNBO last_validation;
718 struct GNUNET_TIME_AbsoluteNBO valid_until;
719 struct GNUNET_TIME_AbsoluteNBO next_validation;
720
721 /**
722 * Current round-trip time estimate.
723 */
724 struct GNUNET_TIME_RelativeNBO rtt;
725
726 /**
727 * Connection status (in NBO).
728 */
729 uint32_t cs GNUNET_PACKED;
730
731 /**
732 * Messages pending (in NBO).
733 */
734 uint32_t num_msg_pending GNUNET_PACKED;
735
736 /**
737 * Bytes pending (in NBO).
738 */
739 uint32_t num_bytes_pending GNUNET_PACKED;
740
741 /* Followed by 0-terminated address of the peer */
742};
743
744
745/**
746 * Request to verify address.
747 */
748struct GNUNET_TRANSPORT_AddressToVerify
749{
750 /**
751 * Type will be #GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_CONSIDER_VERIFY.
752 */
753 struct GNUNET_MessageHeader header;
754
755 /**
756 * Reserved. 0.
757 */
758 uint32_t reserved;
759
760 /**
761 * Peer the address is from.
762 */
763 struct GNUNET_PeerIdentity peer;
764
765 /* followed by variable-size raw address */
766};
767
768
769/**
770 * Application client to TRANSPORT service: we would like to have
771 * address suggestions for this peer.
772 */
773struct ExpressPreferenceMessage
774{
775 /**
776 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST or
777 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL to stop
778 * suggestions.
779 */
780 struct GNUNET_MessageHeader header;
781
782 /**
783 * What type of performance preference does the client have?
784 * A `enum GNUNET_MQ_PreferenceKind` in NBO.
785 */
786 uint32_t pk GNUNET_PACKED;
787
788 /**
789 * Peer to get address suggestions for.
790 */
791 struct GNUNET_PeerIdentity peer;
792
793 /**
794 * How much bandwidth in bytes/second does the application expect?
795 */
796 struct GNUNET_BANDWIDTH_Value32NBO bw;
797};
798
799
800/**
801 * We got an address of another peer, TRANSPORT service
802 * should validate it. There is no response.
803 */
804struct RequestHelloValidationMessage
805{
806 /**
807 * Type is #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION.
808 */
809 struct GNUNET_MessageHeader header;
810
811 /**
812 * What type of network does the other peer claim this is?
813 * A `enum GNUNET_NetworkType` in NBO.
814 */
815 uint32_t nt GNUNET_PACKED;
816
817 /**
818 * Peer to the address is presumably for.
819 */
820 struct GNUNET_PeerIdentity peer;
821
822 /* followed by 0-terminated address to validate */
823};
824
825GNUNET_NETWORK_STRUCT_END
826
827/* end of transport.h */
828#endif
diff --git a/src/service/transport/transport_api2_application.c b/src/service/transport/transport_api2_application.c
new file mode 100644
index 000000000..00f5f62eb
--- /dev/null
+++ b/src/service/transport/transport_api2_application.c
@@ -0,0 +1,397 @@
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/service/transport/transport_api2_communication.c b/src/service/transport/transport_api2_communication.c
new file mode 100644
index 000000000..e0fdad214
--- /dev/null
+++ b/src/service/transport/transport_api2_communication.c
@@ -0,0 +1,1126 @@
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 "transport.h"
31
32
33/**
34 * How many messages do we keep at most in the queue to the
35 * transport service before we start to drop (default,
36 * can be changed via the configuration file).
37 */
38#define DEFAULT_MAX_QUEUE_LENGTH 16
39
40
41/**
42 * Information we track per packet to enable flow control.
43 */
44struct FlowControl
45{
46 /**
47 * Kept in a DLL.
48 */
49 struct FlowControl *next;
50
51 /**
52 * Kept in a DLL.
53 */
54 struct FlowControl *prev;
55
56 /**
57 * Function to call once the message was processed.
58 */
59 GNUNET_TRANSPORT_MessageCompletedCallback cb;
60
61 /**
62 * Closure for @e cb
63 */
64 void *cb_cls;
65
66 /**
67 * Which peer is this about?
68 */
69 struct GNUNET_PeerIdentity sender;
70
71 /**
72 * More-or-less unique ID for the message.
73 */
74 uint64_t id;
75};
76
77
78/**
79 * Information we track per message to tell the transport about
80 * success or failures.
81 */
82struct AckPending
83{
84 /**
85 * Kept in a DLL.
86 */
87 struct AckPending *next;
88
89 /**
90 * Kept in a DLL.
91 */
92 struct AckPending *prev;
93
94 /**
95 * Communicator this entry belongs to.
96 */
97 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
98
99 /**
100 * Which peer is this about?
101 */
102 struct GNUNET_PeerIdentity receiver;
103
104 /**
105 * More-or-less unique ID for the message.
106 */
107 uint64_t mid;
108
109 /**
110 * Queue ID of the queue which will be used for the message.
111 */
112 uint32_t qid;
113};
114
115
116/**
117 * Opaque handle to the transport service for communicators.
118 */
119struct GNUNET_TRANSPORT_CommunicatorHandle
120{
121 /**
122 * Head of DLL of addresses this communicator offers to the transport service.
123 */
124 struct GNUNET_TRANSPORT_AddressIdentifier *ai_head;
125
126 /**
127 * Tail of DLL of addresses this communicator offers to the transport service.
128 */
129 struct GNUNET_TRANSPORT_AddressIdentifier *ai_tail;
130
131 /**
132 * DLL of messages awaiting flow control confirmation (ack).
133 */
134 struct FlowControl *fc_head;
135
136 /**
137 * DLL of messages awaiting flow control confirmation (ack).
138 */
139 struct FlowControl *fc_tail;
140
141 /**
142 * DLL of messages awaiting transmission confirmation (ack).
143 */
144 struct AckPending *ap_head;
145
146 /**
147 * DLL of messages awaiting transmission confirmation (ack).
148 */
149 struct AckPending *ap_tail;
150
151 /**
152 * DLL of queues we offer.
153 */
154 struct GNUNET_TRANSPORT_QueueHandle *queue_head;
155
156 /**
157 * DLL of queues we offer.
158 */
159 struct GNUNET_TRANSPORT_QueueHandle *queue_tail;
160
161 /**
162 * Our configuration.
163 */
164 const struct GNUNET_CONFIGURATION_Handle *cfg;
165
166 /**
167 * Config section to use.
168 */
169 const char *config_section;
170
171 /**
172 * Address prefix to use.
173 */
174 const char *addr_prefix;
175
176 /**
177 * Function to call when the transport service wants us to initiate
178 * a communication channel with another peer.
179 */
180 GNUNET_TRANSPORT_CommunicatorMqInit mq_init;
181
182 /**
183 * Closure for @e mq_init.
184 */
185 void *mq_init_cls;
186
187 /**
188 * Function to call when the transport service receives messages
189 * for a communicator (i.e. for NAT traversal or for non-bidirectional
190 * communicators).
191 */
192 GNUNET_TRANSPORT_CommunicatorNotify notify_cb;
193
194 /**
195 * Closure for @e notify_Cb.
196 */
197 void *notify_cb_cls;
198
199 /**
200 * Queue to talk to the transport service.
201 */
202 struct GNUNET_MQ_Handle *mq;
203
204 /**
205 * Maximum permissible queue length.
206 */
207 unsigned long long max_queue_length;
208
209 /**
210 * Flow-control identifier generator.
211 */
212 uint64_t fc_gen;
213
214 /**
215 * Internal UUID for the address used in communication with the
216 * transport service.
217 */
218 uint32_t aid_gen;
219
220 /**
221 * Queue identifier generator.
222 */
223 uint32_t queue_gen;
224
225 /**
226 * Characteristics of the communicator.
227 */
228 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
229};
230
231
232/**
233 * Handle returned to identify the internal data structure the transport
234 * API has created to manage a message queue to a particular peer.
235 */
236struct GNUNET_TRANSPORT_QueueHandle
237{
238 /**
239 * Kept in a DLL.
240 */
241 struct GNUNET_TRANSPORT_QueueHandle *next;
242
243 /**
244 * Kept in a DLL.
245 */
246 struct GNUNET_TRANSPORT_QueueHandle *prev;
247
248 /**
249 * Handle this queue belongs to.
250 */
251 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
252
253 /**
254 * Address used by the communication queue.
255 */
256 char *address;
257
258 /**
259 * The queue itself.
260 */
261 struct GNUNET_MQ_Handle *mq;
262
263 /**
264 * Which peer we can communciate with.
265 */
266 struct GNUNET_PeerIdentity peer;
267
268 /**
269 * Network type of the communication queue.
270 */
271 enum GNUNET_NetworkType nt;
272
273 /**
274 * Communication status of the queue.
275 */
276 enum GNUNET_TRANSPORT_ConnectionStatus cs;
277
278 /**
279 * ID for this queue when talking to the transport service.
280 */
281 uint32_t queue_id;
282
283 /**
284 * Maximum transmission unit for the queue.
285 */
286 uint32_t mtu;
287
288 /**
289 * Queue length.
290 */
291 uint64_t q_len;
292 /**
293 * Queue priority.
294 */
295 uint32_t priority;
296};
297
298
299/**
300 * Internal representation of an address a communicator is
301 * currently providing for the transport service.
302 */
303struct GNUNET_TRANSPORT_AddressIdentifier
304{
305 /**
306 * Kept in a DLL.
307 */
308 struct GNUNET_TRANSPORT_AddressIdentifier *next;
309
310 /**
311 * Kept in a DLL.
312 */
313 struct GNUNET_TRANSPORT_AddressIdentifier *prev;
314
315 /**
316 * Transport handle where the address was added.
317 */
318 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
319
320 /**
321 * The actual address.
322 */
323 char *address;
324
325 /**
326 * When does the address expire? (Expected lifetime of the
327 * address.)
328 */
329 struct GNUNET_TIME_Relative expiration;
330
331 /**
332 * Internal UUID for the address used in communication with the
333 * transport service.
334 */
335 uint32_t aid;
336
337 /**
338 * Network type for the address.
339 */
340 enum GNUNET_NetworkType nt;
341};
342
343
344/**
345 * (re)connect our communicator to the transport service
346 *
347 * @param ch handle to reconnect
348 */
349static void
350reconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch);
351
352
353/**
354 * Send message to the transport service about address @a ai
355 * being now available.
356 *
357 * @param ai address to add
358 */
359static void
360send_add_address (struct GNUNET_TRANSPORT_AddressIdentifier *ai)
361{
362 struct GNUNET_MQ_Envelope *env;
363 struct GNUNET_TRANSPORT_AddAddressMessage *aam;
364
365 if (NULL == ai->ch->mq)
366 return;
367 env = GNUNET_MQ_msg_extra (aam,
368 strlen (ai->address) + 1,
369 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS);
370 aam->expiration = GNUNET_TIME_relative_hton (ai->expiration);
371 aam->nt = htonl ((uint32_t) ai->nt);
372 memcpy (&aam[1], ai->address, strlen (ai->address) + 1);
373 GNUNET_MQ_send (ai->ch->mq, env);
374}
375
376
377/**
378 * Send message to the transport service about address @a ai
379 * being no longer available.
380 *
381 * @param ai address to delete
382 */
383static void
384send_del_address (struct GNUNET_TRANSPORT_AddressIdentifier *ai)
385{
386 struct GNUNET_MQ_Envelope *env;
387 struct GNUNET_TRANSPORT_DelAddressMessage *dam;
388
389 if (NULL == ai->ch->mq)
390 return;
391 env = GNUNET_MQ_msg (dam, GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS);
392 dam->aid = htonl (ai->aid);
393 GNUNET_MQ_send (ai->ch->mq, env);
394}
395
396
397/**
398 * Send message to the transport service about queue @a qh
399 * being now available.
400 *
401 * @param qh queue to add
402 */
403static void
404send_add_queue (struct GNUNET_TRANSPORT_QueueHandle *qh)
405{
406 struct GNUNET_MQ_Envelope *env;
407 struct GNUNET_TRANSPORT_AddQueueMessage *aqm;
408
409 if (NULL == qh->ch->mq)
410 return;
411 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
412 "Sending `GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP` message\n");
413 env = GNUNET_MQ_msg_extra (aqm,
414 strlen (qh->address) + 1,
415 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP);
416 aqm->qid = htonl (qh->queue_id);
417 aqm->receiver = qh->peer;
418 aqm->nt = htonl ((uint32_t) qh->nt);
419 aqm->mtu = htonl (qh->mtu);
420 aqm->q_len = GNUNET_htonll (qh->q_len);
421 aqm->priority = htonl (qh->priority);
422 aqm->cs = htonl ((uint32_t) qh->cs);
423 memcpy (&aqm[1], qh->address, strlen (qh->address) + 1);
424 GNUNET_MQ_send (qh->ch->mq, env);
425}
426
427
428/**
429 * Send message to the transport service about queue @a qh
430 * updated.
431 *
432 * @param qh queue to add
433 */
434static void
435send_update_queue (struct GNUNET_TRANSPORT_QueueHandle *qh)
436{
437 struct GNUNET_MQ_Envelope *env;
438 struct GNUNET_TRANSPORT_UpdateQueueMessage *uqm;
439
440 if (NULL == qh->ch->mq)
441 return;
442 env = GNUNET_MQ_msg (uqm, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE);
443 uqm->qid = htonl (qh->queue_id);
444 uqm->receiver = qh->peer;
445 uqm->nt = htonl ((uint32_t) qh->nt);
446 uqm->mtu = htonl (qh->mtu);
447 uqm->q_len = GNUNET_htonll (qh->q_len);
448 uqm->priority = htonl (qh->priority);
449 uqm->cs = htonl ((uint32_t) qh->cs);
450 GNUNET_MQ_send (qh->ch->mq, env);
451}
452
453
454/**
455 * Send message to the transport service about queue @a qh
456 * being no longer available.
457 *
458 * @param qh queue to delete
459 */
460static void
461send_del_queue (struct GNUNET_TRANSPORT_QueueHandle *qh)
462{
463 struct GNUNET_MQ_Envelope *env;
464 struct GNUNET_TRANSPORT_DelQueueMessage *dqm;
465
466 if (NULL == qh->ch->mq)
467 return;
468 env = GNUNET_MQ_msg (dqm, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN);
469 dqm->qid = htonl (qh->queue_id);
470 dqm->receiver = qh->peer;
471 GNUNET_MQ_send (qh->ch->mq, env);
472}
473
474
475/**
476 * Disconnect from the transport service. Purges
477 * all flow control entries as we will no longer receive
478 * the ACKs. Purges the ack pending entries as the
479 * transport will no longer expect the confirmations.
480 *
481 * @param ch service to disconnect from
482 */
483static void
484disconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
485{
486 struct FlowControl *fcn;
487 struct AckPending *apn;
488
489 for (struct FlowControl *fc = ch->fc_head; NULL != fc; fc = fcn)
490 {
491 fcn = fc->next;
492 GNUNET_CONTAINER_DLL_remove (ch->fc_head, ch->fc_tail, fc);
493 fc->cb (fc->cb_cls, GNUNET_SYSERR);
494 GNUNET_free (fc);
495 }
496 for (struct AckPending *ap = ch->ap_head; NULL != ap; ap = apn)
497 {
498 apn = ap->next;
499 GNUNET_CONTAINER_DLL_remove (ch->ap_head, ch->ap_tail, ap);
500 GNUNET_free (ap);
501 }
502 if (NULL == ch->mq)
503 return;
504 GNUNET_MQ_destroy (ch->mq);
505 ch->mq = NULL;
506}
507
508
509/**
510 * Function called on MQ errors.
511 */
512static void
513error_handler (void *cls, enum GNUNET_MQ_Error error)
514{
515 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
516
517 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
518 "MQ failure %d, reconnecting to transport service.\n",
519 error);
520 disconnect (ch);
521 /* TODO: maybe do this with exponential backoff/delay */
522 reconnect (ch);
523}
524
525
526/**
527 * Transport service acknowledged a message we gave it
528 * (with flow control enabled). Tell the communicator.
529 *
530 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
531 * @param incoming_ack the ack
532 */
533static void
534handle_incoming_ack (
535 void *cls,
536 const struct GNUNET_TRANSPORT_IncomingMessageAck *incoming_ack)
537{
538 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
539
540 for (struct FlowControl *fc = ch->fc_head; NULL != fc; fc = fc->next)
541 {
542 if ((fc->id == incoming_ack->fc_id) &&
543 (0 == memcmp (&fc->sender,
544 &incoming_ack->sender,
545 sizeof(struct GNUNET_PeerIdentity))))
546 {
547 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
548 "Done with message with flow control id %" PRIu64
549 " for sender %s from sender %s\n",
550 incoming_ack->fc_id,
551 GNUNET_i2s (&fc->sender),
552 GNUNET_i2s (&incoming_ack->sender));
553 GNUNET_CONTAINER_DLL_remove (ch->fc_head, ch->fc_tail, fc);
554 fc->cb (fc->cb_cls, GNUNET_OK);
555 GNUNET_free (fc);
556 return;
557 }
558 }
559 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
560 "Message with flow control id %" PRIu64
561 " from sender %s not found\n",
562 incoming_ack->fc_id,
563 GNUNET_i2s (&incoming_ack->sender));
564 GNUNET_break (0);
565 disconnect (ch);
566 /* TODO: maybe do this with exponential backoff/delay */
567 reconnect (ch);
568}
569
570
571/**
572 * Transport service wants us to create a queue. Check if @a cq
573 * is well-formed.
574 *
575 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
576 * @param cq the queue creation request
577 * @return #GNUNET_OK if @a smt is well-formed
578 */
579static int
580check_create_queue (void *cls, const struct GNUNET_TRANSPORT_CreateQueue *cq)
581{
582 (void) cls;
583 GNUNET_MQ_check_zero_termination (cq);
584 return GNUNET_OK;
585}
586
587
588/**
589 * Transport service wants us to create a queue. Tell the communicator.
590 *
591 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
592 * @param cq the queue creation request
593 */
594static void
595handle_create_queue (void *cls, const struct GNUNET_TRANSPORT_CreateQueue *cq)
596{
597 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
598 const char *addr = (const char *) &cq[1];
599 struct GNUNET_TRANSPORT_CreateQueueResponse *cqr;
600 struct GNUNET_MQ_Envelope *env;
601 int ret = ch->mq_init (ch->mq_init_cls, &cq->receiver, addr);
602
603 if (GNUNET_NO == ret)
604 {
605 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
606 "Address `%s' is already (beging) connected to.\n",
607 addr);
608 env = GNUNET_MQ_msg (cqr, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL);
609 }
610 else if (GNUNET_SYSERR == ret)
611 {
612 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
613 "Address `%s' invalid for this communicator\n",
614 addr);
615 env = GNUNET_MQ_msg (cqr, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL);
616 }
617 else
618 {
619 env = GNUNET_MQ_msg (cqr, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK);
620 }
621 cqr->request_id = cq->request_id;
622 GNUNET_MQ_send (ch->mq, env);
623}
624
625
626/**
627 * Transport service wants us to send a message. Check if @a smt
628 * is well-formed.
629 *
630 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
631 * @param smt the transmission request
632 * @return #GNUNET_OK if @a smt is well-formed
633 */
634static int
635check_send_msg (void *cls, const struct GNUNET_TRANSPORT_SendMessageTo *smt)
636{
637 (void) cls;
638 GNUNET_MQ_check_boxed_message (smt);
639 return GNUNET_OK;
640}
641
642
643/**
644 * Notify transport service about @a status of a message with
645 * @a mid sent to @a receiver.
646 *
647 * @param ch handle
648 * @param status #GNUNET_OK on success, #GNUNET_SYSERR on failure
649 * @param receiver which peer was the receiver
650 * @param mid message that the ack is about
651 */
652static void
653send_ack (struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
654 int status,
655 const struct GNUNET_PeerIdentity *receiver,
656 uint64_t mid,
657 uint32_t qid)
658{
659 struct GNUNET_MQ_Envelope *env;
660 struct GNUNET_TRANSPORT_SendMessageToAck *ack;
661
662 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK);
663 ack->status = htonl (status);
664 ack->mid = mid;
665 ack->qid = qid;
666 ack->receiver = *receiver;
667 GNUNET_MQ_send (ch->mq, env);
668}
669
670
671/**
672 * Message queue transmission by communicator was successful,
673 * notify transport service.
674 *
675 * @param cls an `struct AckPending *`
676 */
677static void
678send_ack_cb (void *cls)
679{
680 struct AckPending *ap = cls;
681 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = ap->ch;
682
683 if (NULL != ch->ap_head && NULL != ap)
684 GNUNET_CONTAINER_DLL_remove (ch->ap_head, ch->ap_tail, ap);
685 if (NULL != ap)
686 {
687 send_ack (ch, GNUNET_OK, &ap->receiver, ap->mid, ap->qid);
688 GNUNET_free (ap);
689 }
690}
691
692
693/**
694 * Transport service wants us to send a message. Tell the communicator.
695 *
696 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
697 * @param smt the transmission request
698 */
699static void
700handle_send_msg (void *cls, const struct GNUNET_TRANSPORT_SendMessageTo *smt)
701{
702 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
703 const struct GNUNET_MessageHeader *mh;
704 struct GNUNET_MQ_Envelope *env;
705 struct AckPending *ap;
706 struct GNUNET_TRANSPORT_QueueHandle *qh;
707
708 for (qh = ch->queue_head; NULL != qh; qh = qh->next)
709 if ((qh->queue_id == ntohl (smt->qid)) &&
710 (0 == memcmp (&qh->peer,
711 &smt->receiver,
712 sizeof(struct GNUNET_PeerIdentity))))
713 break;
714 if (NULL == qh)
715 {
716 /* queue is already gone, tell transport this one failed */
717 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
718 "Transmission failed, queue no longer exists.\n");
719 send_ack (ch, GNUNET_NO, &smt->receiver, smt->mid, smt->qid);
720 return;
721 }
722 ap = GNUNET_new (struct AckPending);
723 ap->ch = ch;
724 ap->receiver = smt->receiver;
725 ap->mid = smt->mid;
726 ap->qid = smt->qid;
727 GNUNET_CONTAINER_DLL_insert (ch->ap_head, ch->ap_tail, ap);
728 mh = (const struct GNUNET_MessageHeader *) &smt[1];
729 env = GNUNET_MQ_msg_copy (mh);
730 GNUNET_MQ_notify_sent (env, &send_ack_cb, ap);
731 GNUNET_MQ_send (qh->mq, env);
732}
733
734
735/**
736 * Transport service gives us backchannel message. Check if @a bi
737 * is well-formed.
738 *
739 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
740 * @param bi the backchannel message
741 * @return #GNUNET_OK if @a smt is well-formed
742 */
743static int
744check_backchannel_incoming (
745 void *cls,
746 const struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *bi)
747{
748 (void) cls;
749 GNUNET_MQ_check_boxed_message (bi);
750 return GNUNET_OK;
751}
752
753
754/**
755 * Transport service gives us backchannel message. Handle it.
756 *
757 * @param cls our `struct GNUNET_TRANSPORT_CommunicatorHandle *`
758 * @param bi the backchannel message
759 */
760static void
761handle_backchannel_incoming (
762 void *cls,
763 const struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *bi)
764{
765 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = cls;
766 if (NULL != ch->notify_cb)
767 ch->notify_cb (ch->notify_cb_cls,
768 &bi->pid,
769 (const struct GNUNET_MessageHeader *) &bi[1]);
770 else
771 GNUNET_log (
772 GNUNET_ERROR_TYPE_INFO,
773 _ ("Dropped backchanel message: handler not provided by communicator\n"));
774}
775
776
777/**
778 * (re)connect our communicator to the transport service
779 *
780 * @param ch handle to reconnect
781 */
782static void
783reconnect (struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
784{
785 struct GNUNET_MQ_MessageHandler handlers[] =
786 { GNUNET_MQ_hd_fixed_size (incoming_ack,
787 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK,
788 struct GNUNET_TRANSPORT_IncomingMessageAck,
789 ch),
790 GNUNET_MQ_hd_var_size (create_queue,
791 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE,
792 struct GNUNET_TRANSPORT_CreateQueue,
793 ch),
794 GNUNET_MQ_hd_var_size (send_msg,
795 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG,
796 struct GNUNET_TRANSPORT_SendMessageTo,
797 ch),
798 GNUNET_MQ_hd_var_size (
799 backchannel_incoming,
800 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING,
801 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming,
802 ch),
803 GNUNET_MQ_handler_end () };
804 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam;
805 struct GNUNET_MQ_Envelope *env;
806
807 ch->mq =
808 GNUNET_CLIENT_connect (ch->cfg, "transport", handlers, &error_handler, ch);
809 if (NULL == ch->mq)
810 return;
811 env = GNUNET_MQ_msg_extra (cam,
812 strlen (ch->addr_prefix) + 1,
813 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR);
814 cam->cc = htonl ((uint32_t) ch->cc);
815 memcpy (&cam[1], ch->addr_prefix, strlen (ch->addr_prefix) + 1);
816 GNUNET_MQ_send (ch->mq, env);
817 for (struct GNUNET_TRANSPORT_AddressIdentifier *ai = ch->ai_head; NULL != ai;
818 ai = ai->next)
819 send_add_address (ai);
820 for (struct GNUNET_TRANSPORT_QueueHandle *qh = ch->queue_head; NULL != qh;
821 qh = qh->next)
822 send_add_queue (qh);
823}
824
825
826struct GNUNET_TRANSPORT_CommunicatorHandle *
827GNUNET_TRANSPORT_communicator_connect (
828 const struct GNUNET_CONFIGURATION_Handle *cfg,
829 const char *config_section,
830 const char *addr_prefix,
831 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc,
832 GNUNET_TRANSPORT_CommunicatorMqInit mq_init,
833 void *mq_init_cls,
834 GNUNET_TRANSPORT_CommunicatorNotify notify_cb,
835 void *notify_cb_cls)
836{
837 struct GNUNET_TRANSPORT_CommunicatorHandle *ch;
838
839 ch = GNUNET_new (struct GNUNET_TRANSPORT_CommunicatorHandle);
840 ch->cfg = cfg;
841 ch->config_section = config_section;
842 ch->addr_prefix = addr_prefix;
843 ch->mq_init = mq_init;
844 ch->mq_init_cls = mq_init_cls;
845 ch->notify_cb = notify_cb;
846 ch->notify_cb_cls = notify_cb_cls;
847 ch->cc = cc;
848 reconnect (ch);
849 if (GNUNET_OK !=
850 GNUNET_CONFIGURATION_get_value_number (cfg,
851 config_section,
852 "MAX_QUEUE_LENGTH",
853 &ch->max_queue_length))
854 ch->max_queue_length = DEFAULT_MAX_QUEUE_LENGTH;
855 if (NULL == ch->mq)
856 {
857 GNUNET_free (ch);
858 return NULL;
859 }
860 return ch;
861}
862
863
864/**
865 * Disconnect from the transport service.
866 *
867 * @param ch handle returned from connect
868 */
869void
870GNUNET_TRANSPORT_communicator_disconnect (
871 struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
872{
873 disconnect (ch);
874 while (NULL != ch->ai_head)
875 {
876 GNUNET_break (0); /* communicator forgot to remove address, warn! */
877 GNUNET_TRANSPORT_communicator_address_remove (ch->ai_head);
878 }
879 GNUNET_free (ch);
880}
881
882
883/* ************************* Receiving *************************** */
884
885
886int
887GNUNET_TRANSPORT_communicator_receive (
888 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
889 const struct GNUNET_PeerIdentity *sender,
890 const struct GNUNET_MessageHeader *msg,
891 struct GNUNET_TIME_Relative expected_addr_validity,
892 GNUNET_TRANSPORT_MessageCompletedCallback cb,
893 void *cb_cls)
894{
895 struct GNUNET_MQ_Envelope *env;
896 struct GNUNET_TRANSPORT_IncomingMessage *im;
897 uint16_t msize;
898
899
900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
901 "communicator receive\n");
902
903 if (NULL == ch->mq)
904 return GNUNET_SYSERR;
905 if ((NULL == cb) && (GNUNET_MQ_get_length (ch->mq) >= ch->max_queue_length))
906 {
907 GNUNET_log (
908 GNUNET_ERROR_TYPE_WARNING,
909 "Dropping message: transport is too slow, queue length %llu exceeded\n",
910 ch->max_queue_length);
911 return GNUNET_NO;
912 }
913
914 msize = ntohs (msg->size);
915 env =
916 GNUNET_MQ_msg_extra (im, msize, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG);
917 if (NULL == env)
918 {
919 GNUNET_break (0);
920 return GNUNET_SYSERR;
921 }
922 im->expected_address_validity =
923 GNUNET_TIME_relative_hton (expected_addr_validity);
924 im->sender = *sender;
925 // FIXME: this is expensive, would be better if we would
926 // re-design the API to allow us to create the envelope first,
927 // and then have the application fill in the body so we do
928 // not have to memcpy()
929 memcpy (&im[1], msg, msize);
930 im->fc_on = htonl (GNUNET_NO);
931 if (NULL != cb)
932 {
933 struct FlowControl *fc;
934
935 im->fc_on = htonl (GNUNET_YES);
936 im->fc_id = ch->fc_gen++;
937 fc = GNUNET_new (struct FlowControl);
938 fc->sender = *sender;
939 fc->id = im->fc_id;
940 fc->cb = cb;
941 fc->cb_cls = cb_cls;
942 GNUNET_CONTAINER_DLL_insert (ch->fc_head, ch->fc_tail, fc);
943 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
944 "Created flow control id %" PRIu64 " for sender %s\n",
945 fc->id,
946 GNUNET_i2s (&fc->sender));
947 }
948 GNUNET_MQ_send (ch->mq, env);
949 return GNUNET_OK;
950}
951
952
953/* ************************* Discovery *************************** */
954
955
956struct GNUNET_TRANSPORT_QueueHandle *
957GNUNET_TRANSPORT_communicator_mq_add (
958 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
959 const struct GNUNET_PeerIdentity *peer,
960 const char *address,
961 uint32_t mtu,
962 uint64_t q_len,
963 uint32_t priority,
964 enum GNUNET_NetworkType nt,
965 enum GNUNET_TRANSPORT_ConnectionStatus cs,
966 struct GNUNET_MQ_Handle *mq)
967{
968 struct GNUNET_TRANSPORT_QueueHandle *qh;
969
970 // Do not notify the service if there is no intial capacity.
971 GNUNET_assert (0 < q_len);
972
973 qh = GNUNET_new (struct GNUNET_TRANSPORT_QueueHandle);
974 qh->ch = ch;
975 qh->peer = *peer;
976 qh->address = GNUNET_strdup (address);
977 qh->nt = nt;
978 qh->mtu = mtu;
979 qh->q_len = q_len;
980 qh->priority = priority;
981 qh->cs = cs;
982 qh->mq = mq;
983 qh->queue_id = ch->queue_gen++;
984 GNUNET_CONTAINER_DLL_insert (ch->queue_head, ch->queue_tail, qh);
985 send_add_queue (qh);
986 return qh;
987}
988
989
990void
991GNUNET_TRANSPORT_communicator_mq_update (
992 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
993 const struct GNUNET_TRANSPORT_QueueHandle *u_qh,
994 uint64_t q_len,
995 uint32_t priority)
996{
997 struct GNUNET_TRANSPORT_QueueHandle *qh;
998
999 for (qh = ch->queue_head; NULL != qh; qh = qh->next)
1000 {
1001 if (u_qh == qh)
1002 break;
1003 }
1004 GNUNET_assert (NULL != qh);
1005 qh->q_len = q_len;
1006 qh->priority = priority;
1007 send_update_queue (qh);
1008}
1009
1010
1011/**
1012 * Notify transport service that an MQ became unavailable due to a
1013 * disconnect or timeout.
1014 *
1015 * @param qh handle for the queue that must be invalidated
1016 */
1017void
1018GNUNET_TRANSPORT_communicator_mq_del (struct GNUNET_TRANSPORT_QueueHandle *qh)
1019{
1020 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = qh->ch;
1021
1022 send_del_queue (qh);
1023 GNUNET_CONTAINER_DLL_remove (ch->queue_head, ch->queue_tail, qh);
1024 GNUNET_MQ_destroy (qh->mq);
1025 GNUNET_free (qh->address);
1026 GNUNET_free (qh);
1027}
1028
1029
1030/**
1031 * Notify transport service about an address that this communicator
1032 * provides for this peer.
1033 *
1034 * @param ch connection to transport service
1035 * @param address our address in human-readable format, 0-terminated, UTF-8
1036 * @param nt which network type does the address belong to?
1037 * @param expiration when does the communicator forsee this address expiring?
1038 */
1039struct GNUNET_TRANSPORT_AddressIdentifier *
1040GNUNET_TRANSPORT_communicator_address_add (
1041 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1042 const char *address,
1043 enum GNUNET_NetworkType nt,
1044 struct GNUNET_TIME_Relative expiration)
1045{
1046 struct GNUNET_TRANSPORT_AddressIdentifier *ai;
1047
1048 ai = GNUNET_new (struct GNUNET_TRANSPORT_AddressIdentifier);
1049 ai->ch = ch;
1050 ai->address = GNUNET_strdup (address);
1051 ai->nt = nt;
1052 ai->expiration = expiration;
1053 ai->aid = ch->aid_gen++;
1054 GNUNET_CONTAINER_DLL_insert (ch->ai_head, ch->ai_tail, ai);
1055 send_add_address (ai);
1056 return ai;
1057}
1058
1059
1060/**
1061 * Notify transport service about an address that this communicator no
1062 * longer provides for this peer.
1063 *
1064 * @param ai address that is no longer provided
1065 */
1066void
1067GNUNET_TRANSPORT_communicator_address_remove (
1068 struct GNUNET_TRANSPORT_AddressIdentifier *ai)
1069{
1070 struct GNUNET_TRANSPORT_CommunicatorHandle *ch = ai->ch;
1071
1072 send_del_address (ai);
1073 GNUNET_CONTAINER_DLL_remove (ch->ai_head, ch->ai_tail, ai);
1074 GNUNET_free (ai->address);
1075 GNUNET_free (ai);
1076 ai = NULL;
1077}
1078
1079
1080/**
1081 * Notify transport service that this communicator no longer provides all its addresses for this peer.
1082 *
1083 * @param ch The communicator handle.
1084 */
1085void
1086GNUNET_TRANSPORT_communicator_address_remove_all (
1087 struct GNUNET_TRANSPORT_CommunicatorHandle *ch)
1088{
1089 struct GNUNET_TRANSPORT_AddressIdentifier *ai = ch->ai_head;
1090 while (NULL != ai)
1091 {
1092 struct GNUNET_TRANSPORT_AddressIdentifier *ai_next = ai->next;
1093 GNUNET_TRANSPORT_communicator_address_remove (ai);
1094 ai = ai_next;
1095 }
1096}
1097
1098
1099/* ************************* Backchannel *************************** */
1100
1101
1102void
1103GNUNET_TRANSPORT_communicator_notify (
1104 struct GNUNET_TRANSPORT_CommunicatorHandle *ch,
1105 const struct GNUNET_PeerIdentity *pid,
1106 const char *comm,
1107 const struct GNUNET_MessageHeader *header)
1108{
1109 struct GNUNET_MQ_Envelope *env;
1110 struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb;
1111 size_t slen = strlen (comm) + 1;
1112 uint16_t mlen = ntohs (header->size);
1113
1114 GNUNET_assert (mlen + slen + sizeof(*cb) < UINT16_MAX);
1115 env =
1116 GNUNET_MQ_msg_extra (cb,
1117 slen + mlen,
1118 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL);
1119 cb->pid = *pid;
1120 memcpy (&cb[1], header, mlen);
1121 memcpy (((char *) &cb[1]) + mlen, comm, slen);
1122 GNUNET_MQ_send (ch->mq, env);
1123}
1124
1125
1126/* end of transport_api2_communication.c */
diff --git a/src/service/transport/transport_api2_core.c b/src/service/transport/transport_api2_core.c
new file mode 100644
index 000000000..598eef184
--- /dev/null
+++ b/src/service/transport/transport_api2_core.c
@@ -0,0 +1,845 @@
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_protocols.h"
31#include "gnunet_transport_core_service.h"
32#include "transport.h"
33
34#define LOG(kind, ...) GNUNET_log_from (kind, "transport-api-core", __VA_ARGS__)
35
36/**
37 * How large to start with for the hashmap of neighbours.
38 */
39#define STARTING_NEIGHBOURS_SIZE 16
40
41/**
42 * Window size. How many messages to the same target do we pass
43 * to TRANSPORT without a SEND_OK in between? Small values limit
44 * thoughput, large values will increase latency.
45 *
46 * FIXME-OPTIMIZE: find out what good values are experimentally,
47 * maybe set adaptively (i.e. to observed available bandwidth).
48 */
49#define SEND_WINDOW_SIZE 4
50
51
52/**
53 * Entry in hash table of all of our current (connected) neighbours.
54 */
55struct Neighbour
56{
57 /**
58 * Identity of this neighbour.
59 */
60 struct GNUNET_PeerIdentity id;
61
62 /**
63 * Overall transport handle.
64 */
65 struct GNUNET_TRANSPORT_CoreHandle *h;
66
67 /**
68 * Active message queue for the peer.
69 */
70 struct GNUNET_MQ_Handle *mq;
71
72 /**
73 * Envelope with the message we are currently transmitting (or NULL).
74 */
75 struct GNUNET_MQ_Envelope *env;
76
77 /**
78 * Closure for @e mq handlers.
79 */
80 void *handlers_cls;
81
82 /**
83 * How many messages can we still send to this peer before we should
84 * throttle?
85 */
86 unsigned int ready_window;
87
88 /**
89 * Used to indicate our status if @e env is non-NULL. Set to
90 * #GNUNET_YES if we did pass a message to the MQ and are waiting
91 * for the call to #notify_send_done(). Set to #GNUNET_NO if the @e
92 * ready_window is 0 and @e env is waiting for a
93 * #GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK?
94 */
95 int16_t awaiting_done;
96
97 /**
98 * Size of the message in @e env.
99 */
100 uint16_t env_size;
101};
102
103
104/**
105 * Handle for the transport service (includes all of the
106 * state for the transport service).
107 */
108struct GNUNET_TRANSPORT_CoreHandle
109{
110 /**
111 * Closure for the callbacks.
112 */
113 void *cls;
114
115 /**
116 * Functions to call for received data (template for
117 * new message queues).
118 */
119 struct GNUNET_MQ_MessageHandler *handlers;
120
121 /**
122 * function to call on connect events
123 */
124 GNUNET_TRANSPORT_NotifyConnect nc_cb;
125
126 /**
127 * function to call on disconnect events
128 */
129 GNUNET_TRANSPORT_NotifyDisconnect nd_cb;
130
131 /**
132 * My client connection to the transport service.
133 */
134 struct GNUNET_MQ_Handle *mq;
135
136 /**
137 * My configuration.
138 */
139 const struct GNUNET_CONFIGURATION_Handle *cfg;
140
141 /**
142 * Hash map of the current connected neighbours of this peer.
143 * Maps peer identities to `struct Neighbour` entries.
144 */
145 struct GNUNET_CONTAINER_MultiPeerMap *neighbours;
146
147 /**
148 * Peer identity as assumed by this process, or all zeros.
149 */
150 struct GNUNET_PeerIdentity self;
151
152 /**
153 * ID of the task trying to reconnect to the service.
154 */
155 struct GNUNET_SCHEDULER_Task *reconnect_task;
156
157 /**
158 * Delay until we try to reconnect.
159 */
160 struct GNUNET_TIME_Relative reconnect_delay;
161
162 /**
163 * Transport connection started at.
164 */
165 struct GNUNET_TIME_Absolute restarted_at;
166
167 /**
168 * Should we check that @e self matches what the service thinks?
169 * (if #GNUNET_NO, then @e self is all zeros!).
170 */
171 int check_self;
172};
173
174
175/**
176 * Function that will schedule the job that will try
177 * to connect us again to the client.
178 *
179 * @param h transport service to reconnect
180 */
181static void
182disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h);
183
184
185/**
186 * Get the neighbour list entry for the given peer
187 *
188 * @param h our context
189 * @param peer peer to look up
190 * @return NULL if no such peer entry exists
191 */
192static struct Neighbour *
193neighbour_find (struct GNUNET_TRANSPORT_CoreHandle *h,
194 const struct GNUNET_PeerIdentity *peer)
195{
196 return GNUNET_CONTAINER_multipeermap_get (h->neighbours, peer);
197}
198
199
200/**
201 * Iterator over hash map entries, for deleting state of a neighbour.
202 *
203 * @param cls the `struct GNUNET_TRANSPORT_CoreHandle *`
204 * @param key peer identity
205 * @param value value in the hash map, the neighbour entry to delete
206 * @return #GNUNET_YES if we should continue to
207 * iterate,
208 * #GNUNET_NO if not.
209 */
210static int
211neighbour_delete (void *cls, const struct GNUNET_PeerIdentity *key, void *value)
212{
213 struct GNUNET_TRANSPORT_CoreHandle *handle = cls;
214 struct Neighbour *n = value;
215
216 LOG (GNUNET_ERROR_TYPE_DEBUG,
217 "Dropping entry for neighbour `%s'.\n",
218 GNUNET_i2s (key));
219 if (NULL != handle->nd_cb)
220 handle->nd_cb (handle->cls, &n->id, n->handlers_cls);
221 if (NULL != n->env)
222 {
223 GNUNET_MQ_send_cancel (n->env);
224 n->env = NULL;
225 }
226 GNUNET_MQ_destroy (n->mq);
227 GNUNET_assert (NULL == n->mq);
228 GNUNET_assert (
229 GNUNET_YES ==
230 GNUNET_CONTAINER_multipeermap_remove (handle->neighbours, key, n));
231 GNUNET_free (n);
232 return GNUNET_YES;
233}
234
235
236/**
237 * Generic error handler, called with the appropriate
238 * error code and the same closure specified at the creation of
239 * the message queue.
240 * Not every message queue implementation supports an error handler.
241 *
242 * @param cls closure with the `struct GNUNET_TRANSPORT_CoreHandle *`
243 * @param error error code
244 */
245static void
246mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
247{
248 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
249
250 LOG (GNUNET_ERROR_TYPE_DEBUG,
251 "Error %u received from transport service, disconnecting temporarily.\n",
252 error);
253 disconnect_and_schedule_reconnect (h);
254}
255
256
257/**
258 * A message from the handler's message queue to a neighbour was
259 * transmitted. Now trigger (possibly delayed) notification of the
260 * neighbour's message queue that we are done and thus ready for
261 * the next message. Note that the MQ being ready is independent
262 * of the send window, as we may queue many messages and simply
263 * not pass them to TRANSPORT if the send window is insufficient.
264 *
265 * @param cls the `struct Neighbour` where the message was sent
266 */
267static void
268notify_send_done (void *cls)
269{
270 struct Neighbour *n = cls;
271
272 n->awaiting_done = GNUNET_NO;
273 n->env = NULL;
274 if (0 < n->ready_window)
275 GNUNET_MQ_impl_send_continue (n->mq);
276}
277
278
279/**
280 * We have an envelope waiting for transmission at @a n, and
281 * our transmission window is positive. Perform the transmission.
282 *
283 * @param n neighbour to perform transmission for
284 */
285static void
286do_send (struct Neighbour *n)
287{
288 GNUNET_assert (0 < n->ready_window);
289 GNUNET_assert (NULL != n->env);
290 n->ready_window--;
291 n->awaiting_done = GNUNET_YES;
292 GNUNET_MQ_notify_sent (n->env, &notify_send_done, n);
293 GNUNET_MQ_send (n->h->mq, n->env);
294 LOG (GNUNET_ERROR_TYPE_DEBUG,
295 "Passed message of type %u for neighbour `%s' to TRANSPORT. ready_window %u\n",
296 ntohs (GNUNET_MQ_env_get_msg (n->env)->type),
297 GNUNET_i2s (&n->id),
298 n->ready_window);
299}
300
301
302/**
303 * Implement sending functionality of a message queue.
304 * Called one message at a time. Should send the @a msg
305 * to the transport service and then notify the queue
306 * once we are ready for the next one.
307 *
308 * @param mq the message queue
309 * @param msg the message to send
310 * @param impl_state state of the implementation
311 */
312static void
313mq_send_impl (struct GNUNET_MQ_Handle *mq,
314 const struct GNUNET_MessageHeader *msg,
315 void *impl_state)
316{
317 struct Neighbour *n = impl_state;
318 struct OutboundMessage *obm;
319 uint16_t msize;
320
321 msize = ntohs (msg->size);
322 if (msize >= GNUNET_MAX_MESSAGE_SIZE - sizeof(*obm))
323 {
324 GNUNET_break (0);
325 GNUNET_MQ_impl_send_continue (mq);
326 return;
327 }
328 LOG (GNUNET_ERROR_TYPE_DEBUG,
329 "CORE requested transmission of message of type %u to neighbour `%s'.\n",
330 ntohs (msg->type),
331 GNUNET_i2s (&n->id));
332
333 GNUNET_assert (NULL == n->env);
334 n->env =
335 GNUNET_MQ_msg_nested_mh (obm, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, msg);
336 n->env_size = ntohs (msg->size);
337 {
338 struct GNUNET_MQ_Envelope *env;
339
340 env = GNUNET_MQ_get_current_envelope (mq);
341 obm->priority = htonl ((uint32_t) GNUNET_MQ_env_get_options (env));
342 }
343 obm->peer = n->id;
344 if (0 == n->ready_window)
345 {
346 LOG (GNUNET_ERROR_TYPE_DEBUG,
347 "Flow control delays transmission to CORE until we see SEND_OK.\n");
348 return; /* can't send yet, need to wait for SEND_OK */
349 }
350 do_send (n);
351}
352
353
354/**
355 * Handle destruction of a message queue. Implementations must not
356 * free @a mq, but should take care of @a impl_state.
357 *
358 * @param mq the message queue to destroy
359 * @param impl_state state of the implementation
360 */
361static void
362mq_destroy_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
363{
364 struct Neighbour *n = impl_state;
365
366 GNUNET_assert (mq == n->mq);
367 n->mq = NULL;
368}
369
370
371/**
372 * Implementation function that cancels the currently sent message.
373 * Should basically undo whatever #mq_send_impl() did.
374 *
375 * @param mq message queue
376 * @param impl_state state specific to the implementation
377 */
378static void
379mq_cancel_impl (struct GNUNET_MQ_Handle *mq, void *impl_state)
380{
381 struct Neighbour *n = impl_state;
382
383 n->ready_window++;
384 if (GNUNET_YES == n->awaiting_done)
385 {
386 GNUNET_MQ_send_cancel (n->env);
387 n->env = NULL;
388 n->awaiting_done = GNUNET_NO;
389 }
390 else
391 {
392 GNUNET_assert (0 == n->ready_window);
393 n->env = NULL;
394 }
395}
396
397
398/**
399 * We had an error processing a message we forwarded from a peer to
400 * the CORE service. We should just complain about it but otherwise
401 * continue processing.
402 *
403 * @param cls closure
404 * @param error error code
405 */
406static void
407peer_mq_error_handler (void *cls, enum GNUNET_MQ_Error error)
408{
409 struct Neighbour *n = cls;
410
411 if (GNUNET_MQ_ERROR_MALFORMED == error)
412 GNUNET_break_op (0);
413 //TODO Look into bug #7887
414
415 GNUNET_TRANSPORT_core_receive_continue (n->h, &n->id);
416}
417
418
419/**
420 * Function we use for handling incoming connect messages.
421 *
422 * @param cls closure, a `struct GNUNET_TRANSPORT_Handle *`
423 * @param cim message received
424 */
425static void
426handle_connect (void *cls, const struct ConnectInfoMessage *cim)
427{
428 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
429 struct Neighbour *n;
430
431 LOG (GNUNET_ERROR_TYPE_DEBUG,
432 "Receiving CONNECT message for `%s'\n",
433 GNUNET_i2s (&cim->id));
434 n = neighbour_find (h, &cim->id);
435 if (NULL != n)
436 {
437 GNUNET_break (0);
438 disconnect_and_schedule_reconnect (h);
439 return;
440 }
441 n = GNUNET_new (struct Neighbour);
442 n->id = cim->id;
443 n->h = h;
444 n->ready_window = SEND_WINDOW_SIZE;
445 GNUNET_assert (GNUNET_OK ==
446 GNUNET_CONTAINER_multipeermap_put (
447 h->neighbours,
448 &n->id,
449 n,
450 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
451
452 n->mq = GNUNET_MQ_queue_for_callbacks (&mq_send_impl,
453 &mq_destroy_impl,
454 &mq_cancel_impl,
455 n,
456 h->handlers,
457 &peer_mq_error_handler,
458 n);
459 if (NULL != h->nc_cb)
460 {
461 n->handlers_cls = h->nc_cb (h->cls, &n->id, n->mq);
462 GNUNET_MQ_set_handlers_closure (n->mq, n->handlers_cls);
463 }
464}
465
466
467/**
468 * Function we use for handling incoming disconnect messages.
469 *
470 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
471 * @param dim message received
472 */
473static void
474handle_disconnect (void *cls, const struct DisconnectInfoMessage *dim)
475{
476 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
477 struct Neighbour *n;
478
479 GNUNET_break (ntohl (dim->reserved) == 0);
480 LOG (GNUNET_ERROR_TYPE_DEBUG,
481 "Receiving DISCONNECT message for `%s'.\n",
482 GNUNET_i2s (&dim->peer));
483 n = neighbour_find (h, &dim->peer);
484 if (NULL == n)
485 {
486 GNUNET_break (0);
487 disconnect_and_schedule_reconnect (h);
488 return;
489 }
490 GNUNET_assert (GNUNET_YES == neighbour_delete (h, &dim->peer, n));
491}
492
493
494/**
495 * Function we use for handling incoming send-ok messages.
496 *
497 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
498 * @param okm message received
499 */
500static void
501handle_send_ok (void *cls, const struct SendOkMessage *okm)
502{
503 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
504 struct Neighbour *n;
505
506 LOG (GNUNET_ERROR_TYPE_DEBUG,
507 "Receiving SEND_OK message for transmission to %s\n",
508 GNUNET_i2s (&okm->peer));
509
510 n = neighbour_find (h, &okm->peer);
511
512 if (NULL == n)
513 {
514 /* We should never get a 'SEND_OK' for a peer that we are not
515 connected to */
516 GNUNET_break (0);
517 disconnect_and_schedule_reconnect (h);
518 return;
519 }
520
521 if ((GNUNET_NO == n->awaiting_done) &&
522 (NULL != n->env) &&
523 (0 == n->ready_window))
524 {
525 n->ready_window++;
526 do_send (n);
527 return;
528 }
529 else if ((GNUNET_NO == n->awaiting_done) &&
530 (0 == n->ready_window))
531 {
532 n->ready_window++;
533 GNUNET_MQ_impl_send_continue (n->mq);
534 return;
535 }
536 n->ready_window++;
537}
538
539
540/**
541 * Function we use for checking incoming "inbound" messages.
542 *
543 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
544 * @param im message received
545 */
546static int
547check_recv (void *cls, const struct InboundMessage *im)
548{
549 const struct GNUNET_MessageHeader *imm;
550 uint16_t size;
551
552 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
553 "check_recv\n");
554 size = ntohs (im->header.size) - sizeof(*im);
555 if (size < sizeof(struct GNUNET_MessageHeader))
556 {
557 GNUNET_break (0);
558 return GNUNET_SYSERR;
559 }
560 imm = (const struct GNUNET_MessageHeader *) &im[1];
561 if (ntohs (imm->size) != size)
562 {
563 GNUNET_break (0);
564 return GNUNET_SYSERR;
565 }
566 return GNUNET_OK;
567}
568
569
570/**
571 * Function we use for handling incoming messages.
572 *
573 * @param cls closure, a `struct GNUNET_TRANSPORT_CoreHandle *`
574 * @param im message received
575 */
576static void
577handle_recv (void *cls, const struct InboundMessage *im)
578{
579 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
580 const struct GNUNET_MessageHeader *imm =
581 (const struct GNUNET_MessageHeader *) &im[1];
582 struct Neighbour *n;
583
584 LOG (GNUNET_ERROR_TYPE_DEBUG,
585 "Received message of type %u with %u bytes from `%s'.\n",
586 (unsigned int) ntohs (imm->type),
587 (unsigned int) ntohs (imm->size),
588 GNUNET_i2s (&im->peer));
589 n = neighbour_find (h, &im->peer);
590 if (NULL == n)
591 {
592 GNUNET_break (0);
593 disconnect_and_schedule_reconnect (h);
594 return;
595 }
596 GNUNET_MQ_inject_message (n->mq, imm);
597}
598
599
600/**
601 * Try again to connect to transport service.
602 *
603 * @param cls the handle to the transport service
604 */
605static void
606reconnect (void *cls)
607{
608 struct GNUNET_TRANSPORT_CoreHandle *h = cls;
609 struct GNUNET_MQ_MessageHandler handlers[] =
610 { GNUNET_MQ_hd_fixed_size (connect,
611 GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT,
612 struct ConnectInfoMessage,
613 h),
614 GNUNET_MQ_hd_fixed_size (disconnect,
615 GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT,
616 struct DisconnectInfoMessage,
617 h),
618 GNUNET_MQ_hd_fixed_size (send_ok,
619 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK,
620 struct SendOkMessage,
621 h),
622 GNUNET_MQ_hd_var_size (recv,
623 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV,
624 struct InboundMessage,
625 h),
626 GNUNET_MQ_handler_end () };
627 struct GNUNET_MQ_Envelope *env;
628 struct StartMessage *s;
629 uint32_t options;
630
631 h->reconnect_task = NULL;
632 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n");
633 GNUNET_assert (NULL == h->mq);
634 h->mq =
635 GNUNET_CLIENT_connect (h->cfg, "transport", handlers, &mq_error_handler, h);
636 h->restarted_at = GNUNET_TIME_absolute_get ();
637 if (NULL == h->mq)
638 return;
639 env = GNUNET_MQ_msg (s, GNUNET_MESSAGE_TYPE_TRANSPORT_START);
640 options = 0;
641 if (h->check_self)
642 options |= 1;
643 if (NULL != h->handlers)
644 options |= 2;
645 s->options = htonl (options);
646 s->self = h->self;
647 GNUNET_MQ_send (h->mq, env);
648}
649
650
651/**
652 * Disconnect from the transport service.
653 *
654 * @param h transport service to reconnect
655 */
656static void
657disconnect (struct GNUNET_TRANSPORT_CoreHandle *h)
658{
659 GNUNET_CONTAINER_multipeermap_iterate (h->neighbours, &neighbour_delete, h);
660 if (NULL != h->mq)
661 {
662 GNUNET_MQ_destroy (h->mq);
663 h->mq = NULL;
664 }
665}
666
667
668/**
669 * Function that will schedule the job that will try
670 * to connect us again to the client.
671 *
672 * @param h transport service to reconnect
673 */
674static void
675disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_CoreHandle *h)
676{
677 GNUNET_assert (NULL == h->reconnect_task);
678 disconnect (h);
679 {
680 /* Reduce delay based on runtime of the connection,
681 so that there is a cool-down if a connection is up
682 for a while. */
683 struct GNUNET_TIME_Relative runtime;
684 unsigned int minutes;
685
686 runtime = GNUNET_TIME_absolute_get_duration (h->restarted_at);
687 minutes = runtime.rel_value_us / GNUNET_TIME_UNIT_MINUTES.rel_value_us;
688 if (minutes > 31)
689 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
690 else
691 h->reconnect_delay.rel_value_us >>= minutes;
692 }
693 LOG (GNUNET_ERROR_TYPE_DEBUG,
694 "Scheduling task to reconnect to transport service in %s.\n",
695 GNUNET_STRINGS_relative_time_to_string (h->reconnect_delay, GNUNET_YES));
696 h->reconnect_task =
697 GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
698 h->reconnect_delay = GNUNET_TIME_STD_BACKOFF (h->reconnect_delay);
699}
700
701
702/**
703 * Checks if a given peer is connected to us and get the message queue.
704 *
705 * @param handle connection to transport service
706 * @param peer the peer to check
707 * @return NULL if disconnected, otherwise message queue for @a peer
708 */
709struct GNUNET_MQ_Handle *
710GNUNET_TRANSPORT_core_get_mq (struct GNUNET_TRANSPORT_CoreHandle *handle,
711 const struct GNUNET_PeerIdentity *peer)
712{
713 struct Neighbour *n;
714
715 n = neighbour_find (handle, peer);
716 if (NULL == n)
717 return NULL;
718 return n->mq;
719}
720
721
722/**
723 * Notification from the CORE service to the TRANSPORT service
724 * that the CORE service has finished processing a message from
725 * TRANSPORT (via the @code{handlers} of #GNUNET_TRANSPORT_core_connect())
726 * and that it is thus now OK for TRANSPORT to send more messages
727 * for @a pid.
728 *
729 * Used to provide flow control, this is our equivalent to
730 * #GNUNET_SERVICE_client_continue() of an ordinary service.
731 *
732 * Note that due to the use of a window, TRANSPORT may send multiple
733 * messages destined for the same peer even without an intermediate
734 * call to this function. However, CORE must still call this function
735 * once per message received, as otherwise eventually the window will
736 * be full and TRANSPORT will stop providing messages to CORE for @a
737 * pid.
738 *
739 * @param ch core handle
740 * @param pid which peer was the message from that was fully processed by CORE
741 */
742void
743GNUNET_TRANSPORT_core_receive_continue (struct GNUNET_TRANSPORT_CoreHandle *ch,
744 const struct GNUNET_PeerIdentity *pid)
745{
746 struct GNUNET_MQ_Envelope *env;
747 struct RecvOkMessage *rok;
748
749 LOG (GNUNET_ERROR_TYPE_DEBUG,
750 "Message for %s finished CORE processing, sending RECV_OK.\n",
751 GNUNET_i2s (pid));
752 if (NULL == ch->mq)
753 return;
754 env = GNUNET_MQ_msg (rok, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK);
755 rok->increase_window_delta = htonl (1);
756 rok->peer = *pid;
757 GNUNET_MQ_send (ch->mq, env);
758}
759
760
761/**
762 * Connect to the transport service. Note that the connection may
763 * complete (or fail) asynchronously.
764 *
765 * @param cfg configuration to use
766 * @param self our own identity (API should check that it matches
767 * the identity found by transport), or NULL (no check)
768 * @param cls closure for the callbacks
769 * @param rec receive function to call
770 * @param nc function to call on connect events
771 * @param nd function to call on disconnect events
772 * @return NULL on error
773 */
774struct GNUNET_TRANSPORT_CoreHandle *
775GNUNET_TRANSPORT_core_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
776 const struct GNUNET_PeerIdentity *self,
777 const struct GNUNET_MQ_MessageHandler *handlers,
778 void *cls,
779 GNUNET_TRANSPORT_NotifyConnect nc,
780 GNUNET_TRANSPORT_NotifyDisconnect nd)
781{
782 struct GNUNET_TRANSPORT_CoreHandle *h;
783 unsigned int i;
784
785 h = GNUNET_new (struct GNUNET_TRANSPORT_CoreHandle);
786 if (NULL != self)
787 {
788 h->self = *self;
789 h->check_self = GNUNET_YES;
790 }
791 h->cfg = cfg;
792 h->cls = cls;
793 h->nc_cb = nc;
794 h->nd_cb = nd;
795 h->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
796 if (NULL != handlers)
797 {
798 for (i = 0; NULL != handlers[i].cb; i++)
799 ;
800 h->handlers = GNUNET_new_array (i + 1, struct GNUNET_MQ_MessageHandler);
801 GNUNET_memcpy (h->handlers,
802 handlers,
803 i * sizeof(struct GNUNET_MQ_MessageHandler));
804 }
805 LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service\n");
806 reconnect (h);
807 if (NULL == h->mq)
808 {
809 GNUNET_free (h->handlers);
810 GNUNET_free (h);
811 return NULL;
812 }
813 h->neighbours =
814 GNUNET_CONTAINER_multipeermap_create (STARTING_NEIGHBOURS_SIZE, GNUNET_YES);
815 return h;
816}
817
818
819/**
820 * Disconnect from the transport service.
821 *
822 * @param handle handle to the service as returned from
823 * #GNUNET_TRANSPORT_core_connect()
824 */
825void
826GNUNET_TRANSPORT_core_disconnect (struct GNUNET_TRANSPORT_CoreHandle *handle)
827{
828 LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n");
829 /* this disconnects all neighbours... */
830 disconnect (handle);
831 /* and now we stop trying to connect again... */
832 if (NULL != handle->reconnect_task)
833 {
834 GNUNET_SCHEDULER_cancel (handle->reconnect_task);
835 handle->reconnect_task = NULL;
836 }
837 GNUNET_CONTAINER_multipeermap_destroy (handle->neighbours);
838 handle->neighbours = NULL;
839 GNUNET_free (handle->handlers);
840 handle->handlers = NULL;
841 GNUNET_free (handle);
842}
843
844
845/* end of transport_api_core.c */
diff --git a/src/service/transport/transport_api2_monitor.c b/src/service/transport/transport_api2_monitor.c
new file mode 100644
index 000000000..67aa1985e
--- /dev/null
+++ b/src/service/transport/transport_api2_monitor.c
@@ -0,0 +1,292 @@
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/service/transport/transport_api_cmd_backchannel_check.c b/src/service/transport/transport_api_cmd_backchannel_check.c
new file mode 100644
index 000000000..8788139b7
--- /dev/null
+++ b/src/service/transport/transport_api_cmd_backchannel_check.c
@@ -0,0 +1,554 @@
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 "transport-testing-cmds.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log_from (kind, "udp-backchannel",__VA_ARGS__)
38
39#define UDP "udp"
40
41/**
42 * Maximum length allowed for line input.
43 */
44#define MAX_LINE_LENGTH 1024
45
46/**
47 * Struct to store information needed in callbacks.
48 *
49 */
50struct CheckState
51{
52 /**
53 * Context for our asynchronous completion.
54 */
55 struct GNUNET_TESTING_AsyncContext ac;
56
57 /**
58 * The number of the node in a network namespace.
59 */
60 unsigned int node_n;
61
62 /**
63 * The number of the network namespace.
64 */
65 unsigned int namespace_n;
66
67 /**
68 * The testing system of this node.
69 */
70 const struct GNUNET_TESTING_System *tl_system;
71
72 // Label of the cmd which started the test system.
73 const char *create_label;
74
75 /**
76 * Number globally identifying the node.
77 *
78 */
79 uint32_t num;
80
81 /**
82 * Label of the cmd to start a peer.
83 *
84 */
85 const char *start_peer_label;
86
87 /**
88 * The topology of the test setup.
89 */
90 struct GNUNET_TESTING_NetjailTopology *topology;
91
92 /**
93 * Connections to other peers.
94 */
95 struct GNUNET_TESTING_NodeConnection *node_connections_head;
96
97 /**
98 * Number of connections.
99 */
100 unsigned int con_num;
101
102 /**
103 * Number of received backchannel messages.
104 */
105 unsigned int received_backchannel_msgs;
106
107 /**
108 * Array with search strings.
109 */
110 char **search_string;
111
112 /**
113 * File handle for log file.
114 */
115 struct GNUNET_DISK_FileHandle *fh;
116
117 /**
118 * Task which handles the reading
119 */
120 struct GNUNET_SCHEDULER_Task *task;
121
122 /**
123 * Stream to read log file lines.
124 */
125 FILE *stream;
126};
127
128/**
129 *
130 * @param cls The cmd state CheckState.
131 */
132static void
133read_from_log (void *cls)
134{
135 struct CheckState *cs = cls;
136 char line[MAX_LINE_LENGTH + 1];
137 char *search_string;
138
139
140 LOG (GNUNET_ERROR_TYPE_DEBUG,
141 "read_from_log\n");
142
143 cs->fh = GNUNET_DISK_file_open ("test.out",
144 GNUNET_DISK_OPEN_READ,
145 GNUNET_DISK_PERM_USER_READ);
146
147 cs->task = NULL;
148
149 /* read message from line and handle it */
150 cs->stream = fdopen (cs->fh->fd, "r");
151 memset (line, 0, MAX_LINE_LENGTH + 1);
152
153 // fgets (line, MAX_LINE_LENGTH, cs->stream);
154 // while (NULL != line && 0 != strcmp (line, ""))// '\0' != line[0])
155 while (NULL != fgets (line, MAX_LINE_LENGTH, cs->stream))
156 {
157 /*LOG (GNUNET_ERROR_TYPE_DEBUG,
158 "cs->received_backchannel_msgs: %u\n",
159 cs->received_backchannel_msgs);*/
160 /*if (NULL == strstr (line, "line"))
161 LOG (GNUNET_ERROR_TYPE_DEBUG,
162 "line: %s",
163 line);*/
164
165
166 for (int i = 0; i < cs->con_num; i++)
167 {
168 search_string = cs->search_string[i];
169 /*LOG (GNUNET_ERROR_TYPE_DEBUG,
170 "search %u %u: %s %p\n",
171 i,
172 cs->con_num,
173 cs->search_string[i],
174 cs->search_string);
175 fprintf (stderr,
176 line);*/
177 if (NULL != strstr (line,
178 search_string))
179 // "Delivering backchannel message from 4TTC to F7B5 of type 1460 to udp"))
180 // cs->search_string[i]))
181 {
182 cs->received_backchannel_msgs++;
183 LOG (GNUNET_ERROR_TYPE_DEBUG,
184 "received_backchannel_msgs %u con_num %u\n",
185 cs->received_backchannel_msgs,
186 cs->con_num);
187 if (cs->received_backchannel_msgs == cs->con_num)
188 {
189 LOG (GNUNET_ERROR_TYPE_DEBUG,
190 "search finished %lu %lu %u\n",
191 strlen (cs->search_string[i]),
192 strlen (
193 "Delivering backchannel message from 4TTC to F7B5 of type 1460 to udp"),
194 strcmp (
195 "Delivering backchannel message from 4TTC to F7B5 of type 1460 to udp",
196 cs->search_string[i]));
197 GNUNET_TESTING_async_finish (&cs->ac);
198 fclose (cs->stream);
199 return;
200 }
201 }
202 }
203 }
204 LOG (GNUNET_ERROR_TYPE_DEBUG,
205 "read_from_log end\n");
206 fclose (cs->stream);
207 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES,
208 &read_from_log,
209 cs);
210 /*if (NULL == fgets (line, MAX_LINE_LENGTH, cs->stream))
211 {
212 LOG (GNUNET_ERROR_TYPE_DEBUG,
213 "read null\n");
214 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
215 &read_from_log,
216 cs);
217 return;
218 }*/
219 /*else {
220 cs->task =
221 GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
222 cs->fh,
223 &read_from_log,
224 cs);
225
226
227 }*/
228}
229
230
231static enum GNUNET_GenericReturnValue
232will_the_other_node_connect_via_udp (
233 struct CheckState *cs,
234 const struct GNUNET_TESTING_NetjailNode *node)
235// struct GNUNET_TESTING_NodeConnection *connection)
236{
237 // struct GNUNET_TESTING_NetjailTopology *topology = cs->topology;
238 // unsigned int node_n = connection->node_n;
239 // unsigned int namespace_n = connection->namespace_n;
240 // struct GNUNET_HashCode hc;
241 // struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
242 // struct GNUNET_HashCode hc_namespace;
243 /*struct GNUNET_ShortHashCode *key_namespace = GNUNET_new (struct
244 GNUNET_ShortHashCode);*/
245 // struct GNUNET_TESTING_NetjailNode *node;
246 struct GNUNET_TESTING_NodeConnection *pos_connection;
247 struct GNUNET_TESTING_AddressPrefix *pos_prefix;
248 // struct GNUNET_TESTING_NetjailNamespace *namespace;
249 // struct GNUNET_CONTAINER_MultiShortmap *map;
250
251 /* if (0 == connection->namespace_n) */
252 /* { */
253 /* map = topology->map_globals; */
254 /* } */
255 /* else */
256 /* { */
257 /* GNUNET_CRYPTO_hash (&namespace_n, sizeof(namespace_n), &hc_namespace); */
258 /* memcpy (key_namespace, */
259 /* &hc_namespace, */
260 /* sizeof (*key_namespace)); */
261 /* if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains ( */
262 /* topology->map_namespaces, */
263 /* key_namespace)) */
264 /* { */
265 /* namespace = GNUNET_CONTAINER_multishortmap_get (topology->map_namespaces, */
266 /* key_namespace); */
267 /* map = namespace->nodes; */
268 /* } */
269 /* else */
270 /* GNUNET_assert (0); */
271 /* } */
272
273 /* GNUNET_CRYPTO_hash (&node_n, sizeof(node_n), &hc); */
274 /* memcpy (key, */
275 /* &hc, */
276 /* sizeof (*key)); */
277 /* if (GNUNET_YES == GNUNET_CONTAINER_multishortmap_contains ( */
278 /* map, */
279 /* key)) */
280 /* { */
281 /* node = GNUNET_CONTAINER_multishortmap_get (cs->topology->map_globals, */
282 /* key); */
283 /* for (pos_connection = node->node_connections_head; NULL != pos_connection; */
284 /* pos_connection = pos_connection->next) */
285 /* { */
286 /* if ((node->namespace_n == pos_connection->namespace_n) && */
287 /* (node->node_n == pos_connection->node_n) ) */
288 /* { */
289 /* for (pos_prefix = pos_connection->address_prefixes_head; NULL != */
290 /* pos_prefix; */
291 /* pos_prefix = */
292 /* pos_prefix->next) */
293 /* { */
294 /* if (0 == strcmp (UDP, pos_prefix->address_prefix)) */
295 /* { */
296 /* return GNUNET_YES; */
297 /* } */
298 /* } */
299 /* } */
300 /* } */
301 /* } */
302
303 for (pos_connection = node->node_connections_head; NULL != pos_connection;
304 pos_connection = pos_connection->next)
305 {
306 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
307 "connect via udp %u %u %u %u\n",
308 node->namespace_n,
309 cs->namespace_n,
310 node->node_n,
311 cs->node_n);
312 if ((pos_connection->namespace_n == cs->namespace_n) &&
313 (pos_connection->node_n == cs->node_n) )
314 {
315 for (pos_prefix = pos_connection->address_prefixes_head; NULL !=
316 pos_prefix;
317 pos_prefix =
318 pos_prefix->next)
319 {
320 if (0 == strcmp (UDP, pos_prefix->address_prefix))
321 {
322 return GNUNET_YES;
323 }
324 }
325 }
326 }
327
328 return GNUNET_NO;
329}
330
331
332static void
333add_search_string (struct CheckState *cs, const struct
334 GNUNET_TESTING_NetjailNode *node)
335{
336 unsigned int num;
337 struct GNUNET_PeerIdentity *peer;
338 struct GNUNET_PeerIdentity *us;
339 char *buf;
340 char *part_one = "Delivering backchannel message from ";
341 char *part_two = " to ";
342 char *part_three = " of type 1460 to udp";
343 char *peer_id;
344 char *us_id;
345
346 if (0 == node->namespace_n)
347 num = node->node_n;
348 else
349 num = (node->namespace_n - 1) * cs->topology->nodes_m + node->node_n
350 + cs->topology->nodes_x;
351
352 // num = GNUNET_TESTING_calculate_num (pos_connection, cs->topology);
353 peer = GNUNET_TESTING_get_peer (num, cs->tl_system);
354 LOG (GNUNET_ERROR_TYPE_DEBUG,
355 "peer: %s num %u\n",
356 GNUNET_i2s (peer),
357 num);
358 us = GNUNET_TESTING_get_peer (cs->num, cs->tl_system);
359 LOG (GNUNET_ERROR_TYPE_DEBUG,
360 "us: %s cs->num %d\n",
361 GNUNET_i2s (us),
362 cs->num);
363
364 GNUNET_asprintf (&peer_id,
365 "%s",
366 GNUNET_i2s (peer));
367 GNUNET_asprintf (&us_id,
368 "%s",
369 GNUNET_i2s (us));
370
371 if (0 < GNUNET_asprintf (&buf,
372 "%s%s%s%s%s",
373 part_one,
374 us_id,
375 part_two,
376 peer_id,
377 part_three))
378 {
379 GNUNET_array_append (cs->search_string,
380 cs->con_num,
381 buf);
382 /*LOG (GNUNET_ERROR_TYPE_DEBUG,
383 "con_num: %u search: %s %p\n",
384 cs->con_num,
385 cs->search_string[cs->con_num - 1],
386 cs->search_string);*/
387 }
388 else
389 GNUNET_assert (0);
390 GNUNET_free (peer);
391 GNUNET_free (us);
392}
393
394
395/**
396 * The run method of this cmd will connect to peers.
397 *
398 */
399static void
400backchannel_check_run (void *cls,
401 struct GNUNET_TESTING_Interpreter *is)
402{
403 struct CheckState *cs = cls;
404 const struct GNUNET_TESTING_Command *system_cmd;
405 const struct GNUNET_TESTING_System *tl_system;
406 const struct GNUNET_TESTING_Command *peer1_cmd;
407 const struct GNUNET_TRANSPORT_ApplicationHandle *ah;
408 struct GNUNET_CONTAINER_MultiShortmapIterator *node_it;
409 struct GNUNET_CONTAINER_MultiShortmapIterator *namespace_it;
410 struct GNUNET_ShortHashCode node_key;
411 struct GNUNET_ShortHashCode namespace_key;
412 const struct GNUNET_TESTING_NetjailNode *node;
413 const struct GNUNET_TESTING_NetjailNamespace *namespace;
414
415 LOG (GNUNET_ERROR_TYPE_DEBUG,
416 "check run 1\n");
417
418 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
419 cs->start_peer_label);
420 GNUNET_TRANSPORT_TESTING_get_trait_application_handle (peer1_cmd,
421 &ah);
422
423 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
424 cs->create_label);
425 GNUNET_TESTING_get_trait_test_system (system_cmd,
426 &tl_system);
427
428 cs->tl_system = tl_system;
429
430 cs->node_connections_head = GNUNET_TESTING_get_connections (cs->num,
431 cs->topology);
432
433 LOG (GNUNET_ERROR_TYPE_DEBUG,
434 "check run 2\n");
435
436
437 node_it = GNUNET_CONTAINER_multishortmap_iterator_create (
438 cs->topology->map_globals);
439
440 while (GNUNET_YES == GNUNET_CONTAINER_multishortmap_iterator_next (node_it,
441 &node_key,
442 (const
443 void**) &
444 node))
445 {
446 LOG (GNUNET_ERROR_TYPE_DEBUG,
447 "namespace_n %u node_n %u\n",
448 node->namespace_n,
449 node->node_n);
450 if (GNUNET_YES == will_the_other_node_connect_via_udp (cs, node))
451 {
452 add_search_string (cs, node);
453 }
454 }
455 GNUNET_free (node_it);
456 namespace_it = GNUNET_CONTAINER_multishortmap_iterator_create (
457 cs->topology->map_namespaces);
458 while (GNUNET_YES == GNUNET_CONTAINER_multishortmap_iterator_next (
459 namespace_it,
460 &namespace_key,
461 (const
462 void**) &namespace))
463 {
464 LOG (GNUNET_ERROR_TYPE_DEBUG,
465 "namespace_n %u\n",
466 node->namespace_n);
467 node_it = GNUNET_CONTAINER_multishortmap_iterator_create (
468 namespace->nodes);
469 while (GNUNET_YES == GNUNET_CONTAINER_multishortmap_iterator_next (node_it,
470 &node_key
471 ,
472 (const
473 void**)
474 &node))
475 {
476 LOG (GNUNET_ERROR_TYPE_DEBUG,
477 "namespace_n %u node_n %u\n",
478 node->namespace_n,
479 node->node_n);
480 if (GNUNET_YES == will_the_other_node_connect_via_udp (cs, node))
481 {
482 add_search_string (cs, node);
483 }
484 }
485 GNUNET_free (node_it);
486 }
487
488 if (0 != cs->con_num)
489 {
490 cs->task =
491 GNUNET_SCHEDULER_add_now (&read_from_log,
492 cs);
493 }
494 else
495 GNUNET_TESTING_async_finish (&cs->ac);
496
497 GNUNET_free (namespace_it);
498}
499
500
501/**
502 * Trait function of this cmd does nothing.
503 *
504 */
505static int
506backchannel_check_traits (void *cls,
507 const void **ret,
508 const char *trait,
509 unsigned int index)
510{
511 return GNUNET_OK;
512}
513
514
515/**
516 * The cleanup function of this cmd frees resources the cmd allocated.
517 *
518 */
519static void
520backchannel_check_cleanup (void *cls)
521{
522 struct ConnectPeersState *cs = cls;
523
524 GNUNET_free (cs);
525}
526
527
528struct GNUNET_TESTING_Command
529GNUNET_TRANSPORT_cmd_backchannel_check (const char *label,
530 const char *start_peer_label,
531 const char *create_label,
532 uint32_t num,
533 unsigned int node_n,
534 unsigned int namespace_n,
535 struct GNUNET_TESTING_NetjailTopology *
536 topology)
537{
538 struct CheckState *cs;
539
540 cs = GNUNET_new (struct CheckState);
541 cs->start_peer_label = start_peer_label;
542 cs->num = num;
543 cs->create_label = create_label;
544 cs->topology = topology;
545 cs->node_n = node_n;
546 cs->namespace_n = namespace_n;
547
548 return GNUNET_TESTING_command_new_ac (cs,
549 label,
550 &backchannel_check_run,
551 &backchannel_check_cleanup,
552 &backchannel_check_traits,
553 &cs->ac);
554}
diff --git a/src/service/transport/transport_api_cmd_connecting_peers.c b/src/service/transport/transport_api_cmd_connecting_peers.c
new file mode 100644
index 000000000..6b851262d
--- /dev/null
+++ b/src/service/transport/transport_api_cmd_connecting_peers.c
@@ -0,0 +1,314 @@
1/*
2 This file is part of GNUnet
3 Copyright (C) 2021 GNUnet e.V.
4
5 GNUnet is free software: you can redistribute it and/or modify it
6 under the terms of the GNU Affero General Public License as published
7 by the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 GNUnet is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Affero General Public License for more details.
14
15 You should have received a copy of the GNU Affero General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17
18 SPDX-License-Identifier: AGPL3.0-or-later
19 */
20
21/**
22 * @file testing_api_cmd_start_peer.c
23 * @brief cmd to start a peer.
24 * @author t3sserakt
25 */
26#include "platform.h"
27#include "gnunet_util_lib.h"
28#include "gnunet_testing_ng_lib.h"
29#include "gnunet_transport_testing_ng_lib.h"
30#include "transport-testing-cmds.h"
31#include "gnunet_transport_application_service.h"
32
33/**
34 * Generic logging shortcut
35 */
36#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
37
38/**
39 * The run method of this cmd will connect to peers.
40 *
41 */
42static void
43connect_peers_run (void *cls,
44 struct GNUNET_TESTING_Interpreter *is)
45{
46 struct ConnectPeersState *cps = cls;
47 const struct GNUNET_TESTING_Command *system_cmd;
48 const struct GNUNET_TESTING_System *tl_system;
49
50
51 const struct GNUNET_TESTING_Command *peer1_cmd;
52 const struct GNUNET_TRANSPORT_ApplicationHandle *ah;
53 struct GNUNET_PeerIdentity *peer;
54 char *addr;
55 char *addr_and_port;
56 enum GNUNET_NetworkType nt = 0;
57 uint32_t num;
58 struct GNUNET_TESTING_NodeConnection *pos_connection;
59 struct GNUNET_TESTING_AddressPrefix *pos_prefix;
60 unsigned int con_num = 0;
61 const enum GNUNET_GenericReturnValue *broadcast;
62
63 cps->is = is;
64 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
65 cps->start_peer_label);
66 if (GNUNET_YES == cps->wait_for_connect)
67 {
68 LOG (GNUNET_ERROR_TYPE_DEBUG,
69 "Wait for connect.\n");
70 GNUNET_TRANSPORT_TESTING_get_trait_application_handle (peer1_cmd,
71 &ah);
72 }
73 else
74 {
75 LOG (GNUNET_ERROR_TYPE_DEBUG,
76 "Not waiting for connect.\n");
77 GNUNET_TRANSPORT_TESTING_get_trait_application_handle (peer1_cmd,
78 &ah);
79 }
80
81 GNUNET_TRANSPORT_TESTING_get_trait_broadcast (peer1_cmd,
82 &broadcast);
83
84 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
85 cps->create_label);
86 GNUNET_TESTING_get_trait_test_system (system_cmd,
87 &tl_system);
88
89 cps->tl_system = tl_system;
90
91 LOG (GNUNET_ERROR_TYPE_DEBUG,
92 "cps->num: %u \n",
93 cps->num);
94
95 cps->node_connections_head = GNUNET_TESTING_get_connections (cps->num,
96 cps->topology);
97
98 for (pos_connection = cps->node_connections_head; NULL != pos_connection;
99 pos_connection = pos_connection->next)
100 {
101 con_num++;
102 num = GNUNET_TESTING_calculate_num (pos_connection, cps->topology);
103 for (pos_prefix = pos_connection->address_prefixes_head; NULL != pos_prefix;
104 pos_prefix =
105 pos_prefix->next)
106 {
107 addr = GNUNET_TESTING_get_address (pos_connection,
108 pos_prefix->address_prefix);
109 if (NULL != addr)
110 {
111 char *natted_p = strstr (pos_prefix->address_prefix, "_");
112
113 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
114 "0 validating peer number %s %s %s\n",
115 natted_p,
116 pos_prefix->address_prefix,
117 addr);
118 if (0 == GNUNET_memcmp (pos_prefix->address_prefix, "udp"))
119 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
120 "validating memcmp\n");
121 if (GNUNET_YES == *broadcast)
122 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
123 "validating broadcast\n");
124 if ((0 == GNUNET_memcmp (pos_prefix->address_prefix, "udp")) &&
125 (GNUNET_YES == *broadcast) )
126 GNUNET_asprintf (&addr_and_port,
127 "%s:2086",
128 addr);
129 else if (NULL == natted_p)
130 GNUNET_asprintf (&addr_and_port,
131 "%s:60002",
132 addr);
133 else if (NULL != natted_p)
134 {
135 char *prefix;
136 char *rest;
137 char *address;
138
139 prefix = strtok (addr, "_");
140 rest = strtok (NULL, "_");
141 strtok (rest, "-");
142 address = strtok (NULL, "-");
143
144 GNUNET_asprintf (&addr_and_port,
145 "%s-%s:0",
146 prefix,
147 address);
148
149 }
150 peer = GNUNET_TESTING_get_peer (num, tl_system);
151 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
152 "validating peer number %u with identity %s and address %s %u %s and handle %p\n",
153 num,
154 GNUNET_i2s (peer),
155 addr_and_port,
156 *broadcast,
157 pos_prefix->address_prefix,
158 ah);
159 GNUNET_TRANSPORT_application_validate ((struct
160 GNUNET_TRANSPORT_ApplicationHandle
161 *) ah,
162 peer,
163 nt,
164 addr_and_port);
165 GNUNET_free (peer);
166 GNUNET_free (addr);
167 GNUNET_free (addr_and_port);
168 }
169 }
170 }
171 cps->con_num = con_num;
172}
173
174
175/**
176 * Callback from start peer cmd for signaling a peer got connected.
177 *
178 */
179static void *
180notify_connect (struct GNUNET_TESTING_Interpreter *is,
181 const struct GNUNET_PeerIdentity *peer)
182{
183 const struct GNUNET_TESTING_Command *cmd;
184 struct ConnectPeersState *cps;
185 struct GNUNET_PeerIdentity *peer_connection;
186 unsigned int num;
187 unsigned int con_num;
188 void *ret = NULL;
189
190 cmd = GNUNET_TESTING_interpreter_lookup_command_all (is,
191 "connect-peers");
192 cps = cmd->cls; // WTF? Never go directly into cls of another command! FIXME!
193 con_num = cps->con_num_notified;
194 for (struct GNUNET_TESTING_NodeConnection *pos_connection =
195 cps->node_connections_head;
196 NULL != pos_connection;
197 pos_connection = pos_connection->next)
198 {
199 num = GNUNET_TESTING_calculate_num (pos_connection,
200 cps->topology);
201 peer_connection = GNUNET_TESTING_get_peer (num,
202 cps->tl_system);
203 if (0 == GNUNET_memcmp (peer,
204 peer_connection))
205 cps->con_num_notified++;
206 GNUNET_free (peer_connection);
207 }
208 if (cps->con_num_notified == con_num)
209 cps->additional_connects_notified++;
210
211 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
212 "con_num: %u add: %u num_notified: %u add_notified: %u peer: %s\n",
213 cps->con_num,
214 cps->additional_connects,
215 cps->con_num_notified,
216 cps->additional_connects_notified,
217 GNUNET_i2s (peer));
218 if ((cps->con_num == cps->con_num_notified) &&
219 (cps->additional_connects <= cps->additional_connects_notified))
220 {
221 GNUNET_TESTING_async_finish (&cps->ac);
222 }
223 return ret;
224}
225
226
227/**
228 * The cleanup function of this cmd frees resources the cmd allocated.
229 *
230 */
231static void
232connect_peers_cleanup (void *cls)
233{
234 struct ConnectPeersState *cps = cls;
235
236 GNUNET_free (cps);
237}
238
239
240/**
241 * This function prepares an array with traits.
242 *
243 */
244enum GNUNET_GenericReturnValue
245connect_peers_traits (void *cls,
246 const void **ret,
247 const char *trait,
248 unsigned int index)
249{
250 struct ConnectPeersState *cps = cls;
251 struct GNUNET_TESTING_Trait traits[] = {
252 GNUNET_TRANSPORT_TESTING_make_trait_connect_peer_state ((const void *) cps),
253 GNUNET_TESTING_trait_end ()
254 };
255 return GNUNET_TESTING_get_trait (traits,
256 ret,
257 trait,
258 index);
259}
260
261
262struct GNUNET_TESTING_Command
263GNUNET_TRANSPORT_cmd_connect_peers (const char *label,
264 const char *start_peer_label,
265 const char *create_label,
266 uint32_t num,
267 struct GNUNET_TESTING_NetjailTopology *
268 topology,
269 unsigned int additional_connects,
270 unsigned int wait_for_connect)
271{
272 struct ConnectPeersState *cps;
273 unsigned int node_additional_connects;
274
275 node_additional_connects = GNUNET_TESTING_get_additional_connects (num,
276 topology);
277
278 LOG (GNUNET_ERROR_TYPE_DEBUG,
279 "global: %u and local: %u additional_connects\n",
280 additional_connects,
281 node_additional_connects);
282
283 if (0 != node_additional_connects)
284 additional_connects = node_additional_connects;
285
286 cps = GNUNET_new (struct ConnectPeersState);
287 cps->start_peer_label = start_peer_label;
288 cps->num = num;
289 cps->create_label = create_label;
290 cps->topology = topology;
291 cps->notify_connect = notify_connect;
292 cps->additional_connects = additional_connects;
293 cps->wait_for_connect = wait_for_connect;
294
295 // FIXME: wrap with cmd_make_unblocking!
296 if (GNUNET_YES == wait_for_connect)
297 return GNUNET_TESTING_command_new_ac (cps,
298 label,
299 &connect_peers_run,
300 &connect_peers_cleanup,
301 &connect_peers_traits,
302 &cps->ac);
303 else
304 return GNUNET_TESTING_command_new (cps,
305 label,
306 &connect_peers_run,
307 &connect_peers_cleanup,
308 &connect_peers_traits);
309}
310
311
312// FIXME: likely not ideally placed here, move to its own file
313GNUNET_TRANSPORT_TESTING_SIMPLE_TRAITS (GNUNET_TESTING_MAKE_IMPL_SIMPLE_TRAIT,
314 GNUNET_TRANSPORT_TESTING)
diff --git a/src/service/transport/transport_api_cmd_send_simple.c b/src/service/transport/transport_api_cmd_send_simple.c
new file mode 100644
index 000000000..59e5a6e6f
--- /dev/null
+++ b/src/service/transport/transport_api_cmd_send_simple.c
@@ -0,0 +1,161 @@
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 with mq %p\n",
94 mq);
95
96 env = GNUNET_MQ_msg_extra (test,
97 1000 - sizeof(*test),
98 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE);
99 test->num = htonl (sss->num);
100 memset (&test[1],
101 sss->num,
102 1000 - sizeof(*test));
103 GNUNET_MQ_send (mq,
104 env);
105 return GNUNET_OK;
106}
107
108
109/**
110 * The run method of this cmd will send a simple message to the connected peers.
111 *
112 */
113static void
114send_simple_run (void *cls,
115 struct GNUNET_TESTING_Interpreter *is)
116{
117 struct SendSimpleState *sss = cls;
118 const struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
119 const struct GNUNET_TESTING_Command *peer1_cmd;
120 const struct GNUNET_TESTING_Command *system_cmd;
121 const struct GNUNET_TESTING_System *tl_system;
122
123 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
124 sss->start_peer_label);
125 GNUNET_TRANSPORT_TESTING_get_trait_connected_peers_map (peer1_cmd,
126 &connected_peers_map);
127
128 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
129 sss->create_label);
130 GNUNET_TESTING_get_trait_test_system (system_cmd,
131 &tl_system);
132
133 GNUNET_CONTAINER_multishortmap_iterate (
134 (struct GNUNET_CONTAINER_MultiShortmap *)
135 connected_peers_map, send_simple_cb,
136 sss);
137}
138
139
140struct GNUNET_TESTING_Command
141GNUNET_TRANSPORT_cmd_send_simple (const char *label,
142 const char *start_peer_label,
143 const char *create_label,
144 uint32_t num,
145 struct GNUNET_TESTING_NetjailTopology *
146 topology)
147{
148 struct SendSimpleState *sss;
149
150 sss = GNUNET_new (struct SendSimpleState);
151 sss->num = num;
152 sss->start_peer_label = start_peer_label;
153 sss->create_label = create_label;
154 sss->topology = topology;
155
156 return GNUNET_TESTING_command_new (sss,
157 label,
158 &send_simple_run,
159 &send_simple_cleanup,
160 NULL);
161}
diff --git a/src/service/transport/transport_api_cmd_send_simple_performance.c b/src/service/transport/transport_api_cmd_send_simple_performance.c
new file mode 100644
index 000000000..5e00712d4
--- /dev/null
+++ b/src/service/transport/transport_api_cmd_send_simple_performance.c
@@ -0,0 +1,219 @@
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 SendSimplePerfState
43{
44 /**
45 * Context for our asynchronous completion.
46 */
47 struct GNUNET_TESTING_AsyncContext ac;
48
49 /**
50 * Label of the cmd to start a peer.
51 *
52 */
53 const char *start_peer_label;
54
55 /**
56 * Label of the cmd which started the test system.
57 *
58 */
59 const char *create_label;
60
61 /**
62 * The topology we get the connected nodes from.
63 */
64 struct GNUNET_TESTING_NetjailTopology *topology;
65
66 /**
67 * Size of the message in bytes.
68 */
69 unsigned int size;
70
71 /**
72 * Maximum number of messages per peer.
73 */
74 unsigned int max_send;
75};
76
77struct MQWrapper
78{
79 /**
80 * State of the command.
81 */
82 struct SendSimplePerfState *sss;
83
84 /**
85 * Message queue for a peer.
86 */
87 struct GNUNET_MQ_Handle *mq;
88
89 /**
90 * Number of messages allready send.
91 */
92 uint32_t num_send;
93};
94
95/**
96 * The cleanup function of this cmd frees resources the cmd allocated.
97 *
98 */
99static void
100send_simple_cleanup (void *cls)
101{
102 struct SendSimpleState *sss = cls;
103
104 GNUNET_free (sss);
105}
106
107
108static void
109send_simple_single (void *cls)
110{
111 struct MQWrapper *mq_wrapper = cls;
112 struct GNUNET_MQ_Envelope *env;
113 struct GNUNET_TRANSPORT_TESTING_PerformanceTestMessage *test;
114 struct GNUNET_TIME_Absolute now;
115
116 now = GNUNET_TIME_absolute_get ();
117 mq_wrapper->num_send++;
118 LOG (GNUNET_ERROR_TYPE_DEBUG,
119 "Sending simple test message with size %u number %u with mq %p max %u\n",
120 mq_wrapper->sss->size,
121 mq_wrapper->num_send,
122 mq_wrapper->mq,
123 mq_wrapper->sss->max_send);
124
125 env = GNUNET_MQ_msg_extra (test,
126 mq_wrapper->sss->size - sizeof(*test),
127 GNUNET_TRANSPORT_TESTING_SIMPLE_PERFORMANCE_MTYPE);
128 test->num = htonl (mq_wrapper->num_send);
129 test->time_send = GNUNET_TIME_absolute_hton (now);
130 memset (&test[1],
131 '1',
132 mq_wrapper->sss->size - sizeof(*test));
133 GNUNET_MQ_send (mq_wrapper->mq,
134 env);
135 if (mq_wrapper->sss->max_send > mq_wrapper->num_send)
136 GNUNET_SCHEDULER_add_now (&send_simple_single, mq_wrapper);
137 else
138 GNUNET_TESTING_async_finish (&mq_wrapper->sss->ac);
139}
140
141
142static int
143send_simple_cb (void *cls,
144 const struct GNUNET_ShortHashCode *key,
145 void *value)
146{
147 struct SendSimplePerfState *sss = cls;
148 struct GNUNET_MQ_Handle *mq = value;
149 struct MQWrapper *mq_wrapper = GNUNET_new (struct MQWrapper);
150
151 mq_wrapper->sss = sss;
152 mq_wrapper->mq = mq;
153 send_simple_single (mq_wrapper);
154
155 return GNUNET_OK;
156}
157
158
159/**
160 * The run method of this cmd will send a simple message to the connected peers.
161 *
162 */
163static void
164send_simple_run (void *cls,
165 struct GNUNET_TESTING_Interpreter *is)
166{
167 struct SendSimplePerfState *sss = cls;
168 const struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map;
169 const struct GNUNET_TESTING_Command *peer1_cmd;
170 const struct GNUNET_TESTING_Command *system_cmd;
171 const struct GNUNET_TESTING_System *tl_system;
172
173
174 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
175 sss->start_peer_label);
176 GNUNET_TRANSPORT_TESTING_get_trait_connected_peers_map (peer1_cmd,
177 &connected_peers_map);
178
179 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
180 sss->create_label);
181 GNUNET_TESTING_get_trait_test_system (system_cmd,
182 &tl_system);
183
184 GNUNET_CONTAINER_multishortmap_iterate (
185 (struct GNUNET_CONTAINER_MultiShortmap *)
186 connected_peers_map, send_simple_cb,
187 sss);
188}
189
190
191struct GNUNET_TESTING_Command
192GNUNET_TRANSPORT_cmd_send_simple_performance (const char *label,
193 const char *start_peer_label,
194 const char *create_label,
195 uint32_t num,
196 int size,
197 int max_send,
198 struct
199 GNUNET_TESTING_NetjailTopology *
200 topology)
201{
202 struct SendSimplePerfState *sss;
203 struct GNUNET_TESTING_Command cmd;
204
205 sss = GNUNET_new (struct SendSimplePerfState);
206 sss->start_peer_label = start_peer_label;
207 sss->create_label = create_label;
208 sss->topology = topology;
209 sss->size = size;
210 sss->max_send = max_send;
211 cmd = GNUNET_TESTING_command_new_ac (sss,
212 label,
213 &send_simple_run,
214 &send_simple_cleanup,
215 NULL,
216 &sss->ac);
217 cmd.asynchronous_finish = GNUNET_YES;
218 return cmd;
219}
diff --git a/src/service/transport/transport_api_cmd_start_peer.c b/src/service/transport/transport_api_cmd_start_peer.c
new file mode 100644
index 000000000..5492a7684
--- /dev/null
+++ b/src/service/transport/transport_api_cmd_start_peer.c
@@ -0,0 +1,484 @@
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 GNUNET_TESTING_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 LOG (GNUNET_ERROR_TYPE_DEBUG,
68 "Our hello %s\n",
69 sps->hello);
70 GNUNET_PEERSTORE_iteration_stop (sps->pic);
71 sps->pic = NULL;
72 GNUNET_TESTING_async_finish (&sps->ac);
73}
74
75
76/**
77 * Function to start the retrieval task to retrieve the hello of this peer
78 * from the peerstore.
79 *
80 */
81static void
82retrieve_hello (void *cls)
83{
84 struct GNUNET_TESTING_StartPeerState *sps = cls;
85 sps->rh_task = NULL;
86 sps->pic = GNUNET_PEERSTORE_iteration_start (sps->ph,
87 "transport",
88 &sps->id,
89 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
90 hello_iter_cb,
91 sps);
92
93}
94
95
96/**
97 * Disconnect callback for the connection to the core service.
98 *
99 */
100static void
101notify_disconnect (void *cls,
102 const struct GNUNET_PeerIdentity *peer,
103 void *handler_cls)
104{
105 struct GNUNET_TESTING_StartPeerState *sps = cls;
106
107 LOG (GNUNET_ERROR_TYPE_DEBUG,
108 "Peer %s disconnected from peer %u (`%s')\n",
109 GNUNET_i2s (peer),
110 sps->no,
111 GNUNET_i2s (&sps->id));
112
113}
114
115
116/**
117 * Connect callback for the connection to the core service.
118 *
119 */
120static void *
121notify_connect (void *cls,
122 const struct GNUNET_PeerIdentity *peer,
123 struct GNUNET_MQ_Handle *mq)
124{
125 struct GNUNET_TESTING_StartPeerState *sps = cls;
126 struct GNUNET_ShortHashCode *key = GNUNET_new (struct GNUNET_ShortHashCode);
127 struct GNUNET_HashCode hc;
128 struct GNUNET_CRYPTO_EddsaPublicKey public_key = peer->public_key;
129
130 void *ret = (struct GNUNET_PeerIdentity *) peer;
131
132 LOG (GNUNET_ERROR_TYPE_DEBUG,
133 "This Peer %s \n",
134 GNUNET_i2s (&sps->id));
135
136
137 GNUNET_CRYPTO_hash (&public_key, sizeof(public_key), &hc);
138
139 LOG (GNUNET_ERROR_TYPE_DEBUG,
140 "Peer %s connected to peer number %u with mq %p\n",
141 GNUNET_i2s (peer),
142 sps->no,
143 mq);
144
145
146 memcpy (key,
147 &hc,
148 sizeof (*key));
149 GNUNET_CONTAINER_multishortmap_put (sps->connected_peers_map,
150 key,
151 mq,
152 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
153
154 GNUNET_free (key);
155
156 sps->notify_connect (sps->ac.is,
157 peer);
158
159 return ret;
160}
161
162
163/**
164 * The run method of this cmd will start all services of a peer to test the transport service.
165 *
166 */
167static void
168start_peer_run (void *cls,
169 struct GNUNET_TESTING_Interpreter *is)
170{
171 struct GNUNET_TESTING_StartPeerState *sps = cls;
172 char *emsg = NULL;
173 struct GNUNET_PeerIdentity dummy;
174 const struct GNUNET_TESTING_Command *system_cmd;
175 const struct GNUNET_TESTING_System *tl_system;
176 char *home;
177 char *transport_unix_path;
178 char *tcp_communicator_unix_path;
179 char *udp_communicator_unix_path;
180 char *bindto;
181 char *bindto_udp;
182
183 if (GNUNET_NO == GNUNET_DISK_file_test (sps->cfgname))
184 {
185 LOG (GNUNET_ERROR_TYPE_ERROR,
186 "File not found: `%s'\n",
187 sps->cfgname);
188 GNUNET_TESTING_interpreter_fail (is);
189 return;
190 }
191
192
193 sps->cfg = GNUNET_CONFIGURATION_create ();
194 GNUNET_assert (GNUNET_OK ==
195 GNUNET_CONFIGURATION_load (sps->cfg, sps->cfgname));
196
197 GNUNET_asprintf (&home,
198 "$GNUNET_TMP/test-transport/api-tcp-p%u",
199 sps->no);
200
201 GNUNET_asprintf (&transport_unix_path,
202 "$GNUNET_RUNTIME_DIR/tng-p%u.sock",
203 sps->no);
204
205 GNUNET_asprintf (&tcp_communicator_unix_path,
206 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
207 sps->no);
208
209 GNUNET_asprintf (&udp_communicator_unix_path,
210 "$GNUNET_RUNTIME_DIR/tcp-comm-p%u.sock",
211 sps->no);
212
213 GNUNET_asprintf (&bindto,
214 "%s:60002",
215 sps->node_ip);
216
217 GNUNET_asprintf (&bindto_udp,
218 "2086");
219
220 LOG (GNUNET_ERROR_TYPE_DEBUG,
221 "node_ip %s\n",
222 bindto);
223
224 LOG (GNUNET_ERROR_TYPE_DEBUG,
225 "bind_udp %s\n",
226 GNUNET_YES == sps->broadcast ?
227 bindto_udp : bindto);
228
229 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "PATHS", "GNUNET_TEST_HOME",
230 home);
231 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "transport", "UNIXPATH",
232 transport_unix_path);
233 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
234 "BINDTO",
235 bindto);
236 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-udp",
237 "BINDTO",
238 GNUNET_YES == sps->broadcast ?
239 bindto_udp : bindto);
240 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-tcp",
241 "UNIXPATH",
242 tcp_communicator_unix_path);
243 GNUNET_CONFIGURATION_set_value_string (sps->cfg, "communicator-udp",
244 "UNIXPATH",
245 udp_communicator_unix_path);
246
247
248 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
249 sps->system_label);
250 GNUNET_TESTING_get_trait_test_system (system_cmd,
251 &tl_system);
252
253 sps->tl_system = tl_system;
254
255 LOG (GNUNET_ERROR_TYPE_DEBUG,
256 "Creating testing library with key number %u\n",
257 sps->no);
258
259 if (GNUNET_SYSERR ==
260 GNUNET_TESTING_configuration_create ((struct
261 GNUNET_TESTING_System *) tl_system,
262 sps->cfg))
263 {
264 LOG (GNUNET_ERROR_TYPE_DEBUG,
265 "Testing library failed to create unique configuration based on `%s'\n",
266 sps->cfgname);
267 GNUNET_CONFIGURATION_destroy (sps->cfg);
268 GNUNET_TESTING_interpreter_fail (is);
269 return;
270 }
271
272 sps->peer = GNUNET_TESTING_peer_configure ((struct
273 GNUNET_TESTING_System *) sps->
274 tl_system,
275 sps->cfg,
276 sps->no,
277 NULL,
278 &emsg);
279 if (NULL == sps->peer)
280 {
281 LOG (GNUNET_ERROR_TYPE_ERROR,
282 "Testing library failed to create unique configuration based on `%s': `%s' with key number %u\n",
283 sps->cfgname,
284 emsg,
285 sps->no);
286 GNUNET_free (emsg);
287 GNUNET_TESTING_interpreter_fail (is);
288 return;
289 }
290
291 if (GNUNET_OK != GNUNET_TESTING_peer_start (sps->peer))
292 {
293 LOG (GNUNET_ERROR_TYPE_ERROR,
294 "Testing library failed to create unique configuration based on `%s'\n",
295 sps->cfgname);
296 GNUNET_free (emsg);
297 GNUNET_TESTING_interpreter_fail (is);
298 return;
299 }
300
301 memset (&dummy,
302 '\0',
303 sizeof(dummy));
304
305 GNUNET_TESTING_peer_get_identity (sps->peer,
306 &sps->id);
307
308 if (0 == memcmp (&dummy,
309 &sps->id,
310 sizeof(struct GNUNET_PeerIdentity)))
311 {
312 LOG (GNUNET_ERROR_TYPE_ERROR,
313 "Testing library failed to obtain peer identity for peer %u\n",
314 sps->no);
315 GNUNET_free (emsg);
316 GNUNET_TESTING_interpreter_fail (is);
317 return;
318 }
319 LOG (GNUNET_ERROR_TYPE_DEBUG,
320 "Peer %u configured with identity `%s'\n",
321 sps->no,
322 GNUNET_i2s_full (&sps->id));
323
324 sps->th = GNUNET_TRANSPORT_core_connect (sps->cfg,
325 NULL,
326 sps->handlers,
327 sps,
328 &notify_connect,
329 &notify_disconnect);
330 if (NULL == sps->th)
331 {
332 LOG (GNUNET_ERROR_TYPE_ERROR,
333 "Failed to connect to transport service for peer `%s': `%s'\n",
334 sps->cfgname,
335 emsg);
336 GNUNET_free (emsg);
337 GNUNET_TESTING_interpreter_fail (is);
338 return;
339 }
340
341 sps->ph = GNUNET_PEERSTORE_connect (sps->cfg);
342 if (NULL == sps->ph)
343 {
344 LOG (GNUNET_ERROR_TYPE_ERROR,
345 "Failed to connect to peerstore service for peer `%s': `%s'\n",
346 sps->cfgname,
347 emsg);
348 GNUNET_free (emsg);
349 GNUNET_TESTING_interpreter_fail (is);
350 return;
351 }
352
353 sps->ah = GNUNET_TRANSPORT_application_init (sps->cfg);
354 if (NULL == sps->ah)
355 {
356 LOG (GNUNET_ERROR_TYPE_ERROR,
357 "Failed to initialize the TRANSPORT application suggestion client handle for peer `%s': `%s'\n",
358 sps->cfgname,
359 emsg);
360 GNUNET_free (emsg);
361 GNUNET_TESTING_interpreter_fail (is);
362 return;
363 }
364 sps->rh_task = GNUNET_SCHEDULER_add_now (retrieve_hello, sps);
365 GNUNET_free (home);
366 GNUNET_free (transport_unix_path);
367 GNUNET_free (tcp_communicator_unix_path);
368 GNUNET_free (udp_communicator_unix_path);
369 GNUNET_free (bindto);
370 GNUNET_free (bindto_udp);
371}
372
373
374/**
375 * The cleanup function of this cmd frees resources the cmd allocated.
376 *
377 */
378static void
379start_peer_cleanup (void *cls)
380{
381 struct GNUNET_TESTING_StartPeerState *sps = cls;
382
383 if (NULL != sps->handlers)
384 {
385 GNUNET_free (sps->handlers);
386 sps->handlers = NULL;
387 }
388 // TODO Investigate why this caused problems during shutdown.
389 /*if (NULL != sps->cfg)
390 {
391 GNUNET_CONFIGURATION_destroy (sps->cfg);
392 sps->cfg = NULL;
393 }*/
394 GNUNET_free (sps->cfgname);
395 GNUNET_free (sps->node_ip);
396 GNUNET_free (sps->system_label);
397 GNUNET_free (sps->hello);
398 GNUNET_free (sps->connected_peers_map);
399 GNUNET_free (sps);
400}
401
402
403/**
404 * This function prepares an array with traits.
405 *
406 */
407static int
408start_peer_traits (void *cls,
409 const void **ret,
410 const char *trait,
411 unsigned int index)
412{
413 struct GNUNET_TESTING_StartPeerState *sps = cls;
414 struct GNUNET_TRANSPORT_ApplicationHandle *ah = sps->ah;
415 struct GNUNET_PeerIdentity *id = &sps->id;
416 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
417 sps->connected_peers_map;
418 char *hello = sps->hello;
419 size_t hello_size = sps->hello_size;
420
421
422 struct GNUNET_TESTING_Trait traits[] = {
423 GNUNET_TRANSPORT_TESTING_make_trait_application_handle ((const void *) ah),
424 GNUNET_TRANSPORT_TESTING_make_trait_peer_id ((const void *) id),
425 GNUNET_TRANSPORT_TESTING_make_trait_connected_peers_map ((const
426 void *)
427 connected_peers_map),
428 GNUNET_TRANSPORT_TESTING_make_trait_hello ((const void *) hello),
429 GNUNET_TRANSPORT_TESTING_make_trait_hello_size ((const void *) hello_size),
430 GNUNET_TRANSPORT_TESTING_make_trait_state ((const void *) sps),
431 GNUNET_TRANSPORT_TESTING_make_trait_broadcast ((const
432 void *) &sps->broadcast),
433 GNUNET_TESTING_trait_end ()
434 };
435
436 return GNUNET_TESTING_get_trait (traits,
437 ret,
438 trait,
439 index);
440}
441
442
443struct GNUNET_TESTING_Command
444GNUNET_TRANSPORT_cmd_start_peer (const char *label,
445 const char *system_label,
446 uint32_t no,
447 const char *node_ip,
448 struct GNUNET_MQ_MessageHandler *handlers,
449 const char *cfgname,
450 GNUNET_TRANSPORT_notify_connect_cb
451 notify_connect,
452 unsigned int broadcast)
453{
454 struct GNUNET_TESTING_StartPeerState *sps;
455 struct GNUNET_CONTAINER_MultiShortmap *connected_peers_map =
456 GNUNET_CONTAINER_multishortmap_create (1,GNUNET_NO);
457 unsigned int i;
458
459 sps = GNUNET_new (struct GNUNET_TESTING_StartPeerState);
460 sps->no = no;
461 sps->system_label = GNUNET_strdup (system_label);
462 sps->connected_peers_map = connected_peers_map;
463 sps->cfgname = GNUNET_strdup (cfgname);
464 sps->node_ip = GNUNET_strdup (node_ip);
465 sps->notify_connect = notify_connect;
466 sps->broadcast = broadcast;
467
468 if (NULL != handlers)
469 {
470 for (i = 0; NULL != handlers[i].cb; i++)
471 ;
472 sps->handlers = GNUNET_new_array (i + 1,
473 struct GNUNET_MQ_MessageHandler);
474 GNUNET_memcpy (sps->handlers,
475 handlers,
476 i * sizeof(struct GNUNET_MQ_MessageHandler));
477 }
478 return GNUNET_TESTING_command_new_ac (sps,
479 label,
480 &start_peer_run,
481 &start_peer_cleanup,
482 &start_peer_traits,
483 &sps->ac);
484}
diff --git a/src/service/transport/transport_api_cmd_stop_peer.c b/src/service/transport/transport_api_cmd_stop_peer.c
new file mode 100644
index 000000000..76a30d638
--- /dev/null
+++ b/src/service/transport/transport_api_cmd_stop_peer.c
@@ -0,0 +1,153 @@
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 GNUNET_TESTING_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_TESTING_get_trait_state (start_cmd,
67 &sps);
68
69 if (NULL != sps->pic)
70 {
71 GNUNET_PEERSTORE_iteration_stop (sps->pic);
72 }
73 if (NULL != sps->th)
74 {
75 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
76 "Disconnecting from TRANSPORT service\n");
77 GNUNET_TRANSPORT_core_disconnect (sps->th);
78 }
79 if (NULL != sps->ah)
80 {
81 GNUNET_TRANSPORT_application_done (sps->ah);
82 }
83 if (NULL != sps->ph)
84 {
85 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
86 "Disconnecting from PEERSTORE service\n");
87 GNUNET_PEERSTORE_disconnect (sps->ph);
88 }
89 if (NULL != sps->peer)
90 {
91 if (GNUNET_OK !=
92 GNUNET_TESTING_peer_stop (sps->peer))
93 {
94 LOG (GNUNET_ERROR_TYPE_ERROR,
95 "Testing lib failed to stop peer %u (`%s')\n",
96 sps->no,
97 GNUNET_i2s (&sps->id));
98 }
99 GNUNET_TESTING_peer_destroy (sps->peer);
100 }
101 if (NULL != sps->rh_task)
102 GNUNET_SCHEDULER_cancel (sps->rh_task);
103}
104
105
106/**
107 * The cleanup function of this cmd frees resources the cmd allocated.
108 *
109 */
110static void
111stop_peer_cleanup (void *cls)
112{
113 struct StopPeerState *sps = cls;
114
115 GNUNET_free (sps);
116}
117
118
119/**
120 * Trait function of this cmd does nothing.
121 *
122 */
123static int
124stop_peer_traits (void *cls,
125 const void **ret,
126 const char *trait,
127 unsigned int index)
128{
129 return GNUNET_OK;
130}
131
132
133/**
134 * Create command.
135 *
136 * @param label name for command.
137 * @param start_label Label of the cmd to start the peer.
138 * @return command.
139 */
140struct GNUNET_TESTING_Command
141GNUNET_TRANSPORT_cmd_stop_peer (const char *label,
142 const char *start_label)
143{
144 struct StopPeerState *sps;
145
146 sps = GNUNET_new (struct StopPeerState);
147 sps->start_label = start_label;
148 return GNUNET_TESTING_command_new (sps,
149 label,
150 &stop_peer_run,
151 &stop_peer_cleanup,
152 &stop_peer_traits);
153}
diff --git a/src/service/transport/transport_api_traits.c b/src/service/transport/transport_api_traits.c
new file mode 100644
index 000000000..ec53f6f2b
--- /dev/null
+++ b/src/service/transport/transport_api_traits.c
@@ -0,0 +1,32 @@
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_TESTING_MAKE_IMPL_SIMPLE_TRAIT, GNUNET_TRANSPORT_TESTING)
diff --git a/src/service/transport/upnp.sh b/src/service/transport/upnp.sh
new file mode 100755
index 000000000..d01a1a1a1
--- /dev/null
+++ b/src/service/transport/upnp.sh
@@ -0,0 +1,22 @@
1#!/bin/bash
2
3if [ $2 -eq 1 ]
4then
5 if [ ! -d /tmp/netjail_scripts ]
6 then
7 mkdir /tmp/netjail_scripts
8 fi
9
10 ext_ifname=$(ip addr |grep UP|grep "@"|awk -F: '{printf $2"\n"}'|tr -d " "|awk -F@ '{printf $1" "}'|awk '{printf $1}')
11 listening_ip=$(ip addr |grep UP|grep "@"|awk -F: '{printf $2"\n"}'|tr -d " "|awk -F@ '{printf $1" "}'|awk '{printf $2}')
12 uuid=$(uuidgen)
13 cat miniupnpd.conf |sed 's/#ext_ifname=eth1/ext_ifname='$ext_ifname'/g'|sed 's/#listening_ip=eth0/listening_ip='$listening_ip'/g'|sed 's/uuid=73a9cb68-a00b-4d2c-8412-75fc989f0c6/uuid='$uuid'/g'|grep -v "^#"|grep -v '^$' > /tmp/netjail_scripts/gargoyle.txt
14 miniupnpd -d -f /tmp/netjail_scripts/gargoyle.txt -P /tmp/netjail_scripts/miniupnpd_$1.pid &
15else
16 kill $(cat /tmp/netjail_scripts/miniupnpd_$1.pid)
17fi
18
19
20
21
22