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.am446
-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.c12663
-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.build491
-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.c397
-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.c478
-rw-r--r--src/service/transport/test_transport_plugin_cmd_udp_backchannel.c364
-rwxr-xr-xsrc/service/transport/test_transport_simple_send.sh4
-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.c120
-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_transport_traits.c35
-rw-r--r--src/service/transport/transport-testing-cmds.h261
-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.c315
-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
-rwxr-xr-xsrc/service/transport/upnp.sh22
124 files changed, 44204 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..d25dc296f
--- /dev/null
+++ b/src/service/transport/Makefile.am
@@ -0,0 +1,446 @@
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 gnunet-communicator-udp
19
20TESTING_LIBS = \
21 libgnunettestingtransport.la
22
23lib_LTLIBRARIES = \
24 libgnunettransportapplication.la \
25 libgnunettransportcore.la \
26 libgnunettransportcommunicator.la \
27 libgnunettransportmonitor.la \
28 $(TESTING_LIBS)
29
30libgnunettestingtransport_la_SOURCES = \
31 testing_transport_traits.c
32# transport_api_cmd_connecting_peers.c \
33# transport_api_cmd_backchannel_check.c \
34# transport_api_cmd_send_simple.c \
35# transport_api_cmd_send_simple_performance.c \
36# transport-testing2.c transport-testing2.h \
37# transport-testing-cmds.h \
38# transport-testing-filenames2.c \
39# transport-testing-loggers2.c \
40# transport-testing-main2.c \
41# transport-testing-send2.c \
42# transport-testing-communicator.c transport-testing-communicator.h
43libgnunettestingtransport_la_LIBADD = \
44 libgnunettransportapplication.la \
45 libgnunettransportcore.la \
46 $(top_builddir)/src/service/testbed/libgnunettestbed.la \
47 $(top_builddir)/src/service/arm/libgnunetarm.la \
48 $(top_builddir)/src/lib/testing/libgnunettesting.la \
49 $(top_builddir)/src/lib/hello/libgnunethello.la \
50 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
51 $(top_builddir)/src/lib/util/libgnunetutil.la
52libgnunettransporttesting2_la_LDFLAGS = \
53 $(GN_LIBINTL) \
54 $(GN_LIB_LDFLAGS) \
55 -version-info 0:0:0
56
57libgnunettransportapplication_la_SOURCES = \
58 transport_api2_application.c
59libgnunettransportapplication_la_LIBADD = \
60 $(top_builddir)/src/lib/util/libgnunetutil.la \
61 $(LTLIBINTL)
62libgnunettransportapplication_la_LDFLAGS = \
63 $(GN_LIB_LDFLAGS) \
64 -version-info 0:0:0
65
66
67libgnunettransportcore_la_SOURCES = \
68 transport_api2_core.c
69libgnunettransportcore_la_LIBADD = \
70 $(top_builddir)/src/lib/util/libgnunetutil.la \
71 $(GN_LIBINTL)
72libgnunettransportcore_la_LDFLAGS = \
73 $(GN_LIB_LDFLAGS) \
74 -version-info 0:0:0
75
76libgnunettransportcommunicator_la_SOURCES = \
77 transport_api2_communication.c
78libgnunettransportcommunicator_la_LIBADD = \
79 $(top_builddir)/src/lib/util/libgnunetutil.la \
80 $(GN_LIBINTL)
81libgnunettransportcommunicator_la_LDFLAGS = \
82 $(GN_LIB_LDFLAGS) \
83 -version-info 0:0:0
84
85
86libgnunettransportmonitor_la_SOURCES = \
87 transport_api2_monitor.c
88libgnunettransportmonitor_la_LIBADD = \
89 $(top_builddir)/src/lib/util/libgnunetutil.la \
90 $(GN_LIBINTL)
91libgnunettransportmonitor_la_LDFLAGS = \
92 $(GN_LIB_LDFLAGS) \
93 -version-info 0:0:0
94
95
96libexec_PROGRAMS = \
97 gnunet-service-transport \
98 gnunet-communicator-unix \
99 gnunet-communicator-udp \
100 gnunet-communicator-tcp
101if HAVE_EXPERIMENTAL
102if HAVE_QUICHE
103libexec_PROGRAMS += \
104 gnunet-communicator-quic
105endif
106endif
107
108
109#bin_PROGRAMS = \
110# gnunet-transport
111
112bin_SCRIPTS = \
113 gnunet-transport-certificate-creation
114
115# See: https://www.gnu.org/software/automake/manual/html_node/Scripts.html#Scripts
116do_subst = sed -e 's,[@]pkgdatadir[@],$(pkgdatadir),g'
117
118
119gnunet-transport-certificate-creation: gnunet-transport-certificate-creation.in Makefile
120 $(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
121 @chmod +x gnunet-transport-certificate-creation
122
123
124
125
126gnunet_communicator_unix_SOURCES = \
127 gnunet-communicator-unix.c
128gnunet_communicator_unix_LDADD = \
129 libgnunettransportcommunicator.la \
130 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
131 $(top_builddir)/src/lib/util/libgnunetutil.la
132
133gnunet_communicator_tcp_SOURCES = \
134 gnunet-communicator-tcp.c
135gnunet_communicator_tcp_LDADD = \
136 libgnunettransportcommunicator.la \
137 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
138 $(top_builddir)/src/service/nat/libgnunetnatnew.la \
139 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
140 $(top_builddir)/src/lib/util/libgnunetutil.la \
141 $(LIBGCRYPT_LIBS)
142
143gnunet_communicator_udp_SOURCES = \
144 gnunet-communicator-udp.c
145gnunet_communicator_udp_LDADD = \
146 libgnunettransportapplication.la \
147 libgnunettransportcommunicator.la \
148 $(top_builddir)/src/service/nat/libgnunetnatnew.la \
149 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
150 $(top_builddir)/src/lib/util/libgnunetutil.la \
151 $(LIBGCRYPT_LIBS)
152
153if HAVE_EXPERIMENTAL
154if HAVE_QUICHE
155gnunet_communicator_quic_SOURCES = \
156 gnunet-communicator-quic.c
157gnunet_communicator_quic_LDADD = \
158 libgnunettransportapplication.la \
159 libgnunettransportcommunicator.la \
160 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
161 $(top_builddir)/src/service/nat/libgnunetnatnew.la \
162 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
163 $(top_builddir)/src/lib/util/libgnunetutil.la \
164 -lquiche \
165 $(LIBGCRYPT_LIBS)
166endif
167endif
168
169#gnunet_transport_SOURCES = \
170# gnunet-transport.c
171#gnunet_transport_LDADD = \
172# libgnunettransport.la \
173# $(top_builddir)/src/lib/hello/libgnunethello.la \
174# $(top_builddir)/src/lib/util/libgnunetutil.la \
175# $(GN_LIBINTL)
176
177gnunet_service_transport_SOURCES = \
178 gnunet-service-transport.c transport.h
179gnunet_service_transport_LDADD = \
180 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
181 $(top_builddir)/src/lib/hello/libgnunethello.la \
182 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
183 $(top_builddir)/src/service/nat/libgnunetnatnew.la \
184 $(top_builddir)/src/lib/util/libgnunetutil.la \
185 $(LIBGCRYPT_LIBS) \
186 $(GN_LIBINTL)
187
188#plugin_LTLIBRARIES = \
189# libgnunet_test_transport_plugin_cmd_simple_send_performance.la \
190# libgnunet_test_transport_plugin_cmd_nat_upnp.la \
191# libgnunet_test_transport_plugin_cmd_simple_send.la \
192# libgnunet_test_transport_plugin_cmd_simple_send_broadcast.la \
193# libgnunet_test_transport_plugin_cmd_simple_send_dv.la \
194# libgnunet_test_transport_plugin_cmd_udp_backchannel.la
195
196libgnunet_test_transport_plugin_cmd_nat_upnp_la_SOURCES = \
197 test_transport_plugin_cmd_nat_upnp.c
198libgnunet_test_transport_plugin_cmd_nat_upnp_la_LIBADD = \
199 libgnunettransporttesting2.la \
200 libgnunettransportapplication.la \
201 libgnunettransportcore.la \
202 $(top_builddir)/src/lib/testing/libgnunettesting.la \
203 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
204 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
205 $(top_builddir)/src/lib/hello/libgnunethello.la \
206 $(top_builddir)/src/service/arm/libgnunetarm.la \
207 $(top_builddir)/src/lib/util/libgnunetutil.la \
208 $(LTLIBINTL)
209libgnunet_test_transport_plugin_cmd_nat_upnp_la_LDFLAGS = \
210 $(GN_PLUGIN_LDFLAGS)
211
212libgnunet_test_transport_plugin_cmd_udp_backchannel_la_SOURCES = \
213 test_transport_plugin_cmd_udp_backchannel.c
214libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LIBADD = \
215 libgnunettransporttesting2.la \
216 libgnunettransportapplication.la \
217 libgnunettransportcore.la \
218 $(top_builddir)/src/lib/testing/libgnunettesting.la \
219 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
220 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
221 $(top_builddir)/src/lib/hello/libgnunethello.la \
222 $(top_builddir)/src/service/arm/libgnunetarm.la \
223 $(top_builddir)/src/lib/util/libgnunetutil.la \
224 $(LTLIBINTL)
225libgnunet_test_transport_plugin_cmd_udp_backchannel_la_LDFLAGS = \
226 $(GN_PLUGIN_LDFLAGS)
227
228libgnunet_test_transport_plugin_cmd_simple_send_la_SOURCES = \
229 test_transport_plugin_cmd_simple_send.c
230libgnunet_test_transport_plugin_cmd_simple_send_la_LIBADD = \
231 libgnunettransporttesting2.la \
232 libgnunettransportapplication.la \
233 libgnunettransportcore.la \
234 $(top_builddir)/src/lib/testing/libgnunettesting.la \
235 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
236 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
237 $(top_builddir)/src/lib/hello/libgnunethello.la \
238 $(top_builddir)/src/service/arm/libgnunetarm.la \
239 $(top_builddir)/src/lib/util/libgnunetutil.la \
240 $(LTLIBINTL)
241libgnunet_test_transport_plugin_cmd_simple_send_la_LDFLAGS = \
242 $(GN_PLUGIN_LDFLAGS)
243
244libgnunet_test_transport_plugin_cmd_simple_send_performance_la_SOURCES = \
245 test_transport_plugin_cmd_simple_send_performance.c
246libgnunet_test_transport_plugin_cmd_simple_send_performance_la_LIBADD = \
247 libgnunettransporttesting2.la \
248 libgnunettransportapplication.la \
249 libgnunettransportcore.la \
250 $(top_builddir)/src/lib/testing/libgnunettesting.la \
251 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
252 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
253 $(top_builddir)/src/lib/hello/libgnunethello.la \
254 $(top_builddir)/src/service/arm/libgnunetarm.la \
255 $(top_builddir)/src/lib/util/libgnunetutil.la \
256 $(LTLIBINTL)
257libgnunet_test_transport_plugin_cmd_simple_send_performance_la_LDFLAGS = \
258 $(GN_PLUGIN_LDFLAGS)
259
260libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_SOURCES = \
261 test_transport_plugin_cmd_simple_send_broadcast.c
262libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_LIBADD = \
263 libgnunettransporttesting2.la \
264 libgnunettransportapplication.la \
265 libgnunettransportcore.la \
266 $(top_builddir)/src/lib/testing/libgnunettesting.la \
267 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
268 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
269 $(top_builddir)/src/lib/hello/libgnunethello.la \
270 $(top_builddir)/src/service/arm/libgnunetarm.la \
271 $(top_builddir)/src/lib/util/libgnunetutil.la \
272 $(LTLIBINTL)
273libgnunet_test_transport_plugin_cmd_simple_send_broadcast_la_LDFLAGS = \
274 $(GN_PLUGIN_LDFLAGS)
275
276libgnunet_test_transport_plugin_cmd_simple_send_dv_la_SOURCES = \
277 test_transport_plugin_cmd_simple_send_dv.c
278libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LIBADD = \
279 libgnunettransporttesting2.la \
280 libgnunettransportapplication.la \
281 libgnunettransportcore.la \
282 $(top_builddir)/src/lib/testing/libgnunettesting.la \
283 $(top_builddir)/src/service/peerstore/libgnunetpeerstore.la \
284 $(top_builddir)/src/service/statistics/libgnunetstatistics.la \
285 $(top_builddir)/src/lib/hello/libgnunethello.la \
286 $(top_builddir)/src/service/arm/libgnunetarm.la \
287 $(top_builddir)/src/lib/util/libgnunetutil.la \
288 $(LTLIBINTL)
289libgnunet_test_transport_plugin_cmd_simple_send_dv_la_LDFLAGS = \
290 $(GN_PLUGIN_LDFLAGS)
291
292#check_PROGRAMS = \
293# test_communicator_basic-tcp \
294# test_communicator_basic-udp \
295# test_communicator_rekey-tcp \
296# test_communicator_bidirect-tcp \
297# test_communicator_rekey-udp \
298# test_communicator_backchannel-udp
299
300if HAVE_EXPERIMENTAL
301#check_PROGRAMS += test_communicator_basic-quic \
302# test_communicator_basic-unix
303check_SCRIPTS= \
304 test_transport_start_testcase.sh \
305 test_transport_simple_send_performance.sh \
306 test_transport_nat_icmp_tcp.sh \
307 test_transport_nat_upnp.sh \
308 test_transport_simple_send_string.sh \
309 test_transport_simple_send.sh \
310 test_transport_simple_send_broadcast.sh \
311 test_transport_udp_backchannel.sh \
312 test_transport_simple_send_dv_circle.sh \
313 test_transport_simple_send_dv_inverse.sh
314endif
315
316if ENABLE_TEST_RUN
317AM_TESTS_ENVIRONMENT=export GNUNET_PREFIX=$${GNUNET_PREFIX:-@libdir@};export PATH=$${GNUNET_PREFIX:-@prefix@}/bin:$$PATH;unset XDG_DATA_HOME;unset XDG_CONFIG_HOME;
318TESTS = \
319 $(check_SCRIPTS) \
320 $(check_PROGRAMS)
321endif
322
323
324
325test_communicator_basic_unix_SOURCES = \
326 test_communicator_basic.c
327test_communicator_basic_unix_LDADD = \
328 libgnunettransporttesting2.la \
329 $(top_builddir)/src/lib/testing/libgnunettesting.la \
330 $(top_builddir)/src/lib/util/libgnunetutil.la \
331 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
332
333test_communicator_basic_tcp_SOURCES = \
334 test_communicator_basic.c
335test_communicator_basic_tcp_LDADD = \
336 libgnunettransporttesting2.la \
337 $(top_builddir)/src/lib/testing/libgnunettesting.la \
338 $(top_builddir)/src/lib/util/libgnunetutil.la \
339 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
340
341test_communicator_basic_udp_SOURCES = \
342 test_communicator_basic.c
343test_communicator_basic_udp_LDADD = \
344 libgnunettransporttesting2.la \
345 $(top_builddir)/src/lib/testing/libgnunettesting.la \
346 $(top_builddir)/src/lib/util/libgnunetutil.la \
347 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
348
349test_communicator_basic_quic_SOURCES = \
350 test_communicator_basic.c
351test_communicator_basic_quic_LDADD = \
352 libgnunettransporttesting2.la \
353 $(top_builddir)/src/lib/testing/libgnunettesting.la \
354 $(top_builddir)/src/lib/util/libgnunetutil.la \
355 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
356
357test_communicator_rekey_tcp_SOURCES = \
358 test_communicator_basic.c
359test_communicator_rekey_tcp_LDADD = \
360 libgnunettransporttesting2.la \
361 $(top_builddir)/src/lib/testing/libgnunettesting.la \
362 $(top_builddir)/src/lib/util/libgnunetutil.la \
363 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
364
365test_communicator_rekey_udp_SOURCES = \
366 test_communicator_basic.c
367test_communicator_rekey_udp_LDADD = \
368 libgnunettransporttesting2.la \
369 $(top_builddir)/src/lib/testing/libgnunettesting.la \
370 $(top_builddir)/src/lib/util/libgnunetutil.la \
371 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
372
373test_communicator_backchannel_udp_SOURCES = \
374 test_communicator_basic.c
375test_communicator_backchannel_udp_LDADD = \
376 libgnunettransporttesting2.la \
377 $(top_builddir)/src/lib/testing/libgnunettesting.la \
378 $(top_builddir)/src/lib/util/libgnunetutil.la \
379 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
380
381test_communicator_bidirect_tcp_SOURCES = \
382 test_communicator_basic.c
383test_communicator_bidirect_tcp_LDADD = \
384 libgnunettransporttesting2.la \
385 $(top_builddir)/src/lib/testing/libgnunettesting.la \
386 $(top_builddir)/src/lib/util/libgnunetutil.la \
387 $(top_builddir)/src/service/statistics/libgnunetstatistics.la
388
389test_transport_api2_tcp_SOURCES = \
390 test_transport_api2.c
391test_transport_api2_tcp_LDADD = \
392 $(top_builddir)/src/lib/hello/libgnunethello.la \
393 $(top_builddir)/src/lib/util/libgnunetutil.la \
394 libgnunettransporttesting2.la
395
396EXTRA_DIST = \
397test_transport_start_testcase.sh \
398test_transport_simple_send_performance.sh \
399test_transport_nat_icmp_tcp.sh \
400test_transport_nat_upnp.sh \
401test_transport_simple_send_string.sh \
402test_transport_simple_send.sh \
403test_transport_simple_send_broadcast.sh \
404test_transport_udp_backchannel.sh \
405test_transport_simple_send_dv_circle.sh \
406test_transport_simple_send_dv_inverse.sh \
407gnunet-transport-certificate-creation.in \
408test_plugin_hostkey \
409test_plugin_hostkey.ecc \
410test_delay \
411template_cfg_peer1.conf\
412template_cfg_peer2.conf\
413test_transport_api_data.conf\
414test_transport_api_multi_peer1.conf\
415test_transport_api_multi_peer2.conf\
416test_transport_api_tcp_nat_peer1.conf\
417test_transport_api_tcp_nat_peer2.conf\
418test_transport_api_tcp_peer1.conf\
419test_transport_api_tcp_peer2.conf\
420test_transport_api2_tcp_peer1.conf\
421test_transport_api2_tcp_peer2.conf\
422test_transport_api_udp_nat_peer1.conf\
423test_transport_api_udp_nat_peer2.conf\
424test_transport_api_udp_peer1.conf\
425test_transport_api_udp_peer2.conf\
426test_transport_api_unix_peer1.conf\
427test_transport_api_unix_peer2.conf\
428test_transport_api_monitor_peers_peer1.conf\
429test_transport_api_monitor_peers_peer2.conf\
430test_transport_api_monitor_validation_peer1.conf\
431test_transport_api_monitor_validation_peer2.conf\
432test_transport_defaults.conf\
433test_communicator_unix_basic_peer1.conf \
434test_communicator_unix_basic_peer2.conf \
435test_communicator_tcp_basic_peer1.conf \
436test_communicator_tcp_basic_peer2.conf \
437test_communicator_udp_basic_peer1.conf \
438test_communicator_udp_basic_peer2.conf \
439test_communicator_tcp_rekey_peer1.conf \
440test_communicator_tcp_rekey_peer2.conf \
441test_communicator_udp_rekey_peer1.conf \
442test_communicator_udp_rekey_peer2.conf \
443test_communicator_udp_backchannel_peer1.conf \
444test_communicator_udp_backchannel_peer2.conf \
445test_communicator_tcp_bidirect_peer1.conf \
446test_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..5d9b9055f
--- /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 "platform.h"
31#include "gnunet_common.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..91ce801db
--- /dev/null
+++ b/src/service/transport/gnunet-service-transport.c
@@ -0,0 +1,12663 @@
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 return GNUNET_OK;
3662}
3663
3664
3665/**
3666 * Release memory used by @a neighbour.
3667 *
3668 * @param neighbour neighbour entry to free
3669 */
3670static void
3671free_neighbour (struct Neighbour *neighbour)
3672{
3673 struct DistanceVectorHop *dvh;
3674 struct VirtualLink *vl;
3675
3676 GNUNET_assert (NULL == neighbour->queue_head);
3677 GNUNET_assert (GNUNET_YES ==
3678 GNUNET_CONTAINER_multipeermap_remove (neighbours,
3679 &neighbour->pid,
3680 neighbour));
3681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3682 "Freeing neighbour\n");
3683 GNUNET_CONTAINER_multipeermap_iterate (neighbour->natted_addresses,
3684 &remove_global_addresses,
3685 NULL);
3686 GNUNET_CONTAINER_multipeermap_destroy (neighbour->natted_addresses);
3687 while (NULL != (dvh = neighbour->dv_head))
3688 {
3689 struct DistanceVector *dv = dvh->dv;
3690
3691 free_distance_vector_hop (dvh);
3692 if (NULL == dv->dv_head)
3693 free_dv_route (dv);
3694 }
3695 if (NULL != neighbour->get)
3696 {
3697 GNUNET_PEERSTORE_iteration_stop (neighbour->get);
3698 neighbour->get = NULL;
3699 }
3700 if (NULL != neighbour->sc)
3701 {
3702 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3703 "store cancel\n");
3704 GNUNET_PEERSTORE_store_cancel (neighbour->sc);
3705 neighbour->sc = NULL;
3706 }
3707 if (NULL != (vl = neighbour->vl))
3708 {
3709 GNUNET_assert (neighbour == vl->n);
3710 vl->n = NULL;
3711 if (NULL == vl->dv)
3712 {
3713 cores_send_disconnect_info (&vl->target);
3714 free_virtual_link (vl);
3715 }
3716 else
3717 {
3718 GNUNET_SCHEDULER_cancel (vl->visibility_task);
3719 vl->visibility_task = GNUNET_SCHEDULER_add_now (&check_link_down, vl);
3720 }
3721 neighbour->vl = NULL;
3722 }
3723 GNUNET_free (neighbour);
3724}
3725
3726
3727/**
3728 * Send message to CORE clients that we lost a connection.
3729 *
3730 * @param tc client to inform (must be CORE client)
3731 * @param pid peer the connection is for
3732 */
3733static void
3734core_send_connect_info (struct TransportClient *tc,
3735 const struct GNUNET_PeerIdentity *pid)
3736{
3737 struct GNUNET_MQ_Envelope *env;
3738 struct ConnectInfoMessage *cim;
3739
3740 GNUNET_assert (CT_CORE == tc->type);
3741 env = GNUNET_MQ_msg (cim, GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
3742 cim->id = *pid;
3743 GNUNET_MQ_send (tc->mq, env);
3744}
3745
3746
3747/**
3748 * Send message to CORE clients that we gained a connection
3749 *
3750 * @param pid peer the queue was for
3751 */
3752static void
3753cores_send_connect_info (const struct GNUNET_PeerIdentity *pid)
3754{
3755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3756 "Informing CORE clients about connection to %s\n",
3757 GNUNET_i2s (pid));
3758 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
3759 {
3760 if (CT_CORE != tc->type)
3761 continue;
3762 core_send_connect_info (tc, pid);
3763 }
3764}
3765
3766
3767/**
3768 * We believe we are ready to transmit a message on a queue. Gives the
3769 * message to the communicator for transmission (updating the tracker,
3770 * and re-scheduling itself if applicable).
3771 *
3772 * @param cls the `struct Queue` to process transmissions for
3773 */
3774static void
3775transmit_on_queue (void *cls);
3776
3777
3778/**
3779 * Check if the communicator has another queue with higher prio ready for sending.
3780 */
3781static unsigned int
3782check_for_queue_with_higher_prio (struct Queue *queue, struct Queue *queue_head)
3783{
3784 for (struct Queue *s = queue_head; NULL != s;
3785 s = s->next_client)
3786 {
3787 if (s->tc->details.communicator.address_prefix !=
3788 queue->tc->details.communicator.address_prefix)
3789 {
3790 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3791 "queue address %s qid %u compare with queue: address %s qid %u\n",
3792 queue->address,
3793 queue->qid,
3794 s->address,
3795 s->qid);
3796 if ((s->priority > queue->priority) && (0 < s->q_capacity) &&
3797 (QUEUE_LENGTH_LIMIT > s->queue_length) )
3798 return GNUNET_YES;
3799 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3800 "Lower prio\n");
3801 }
3802 }
3803 return GNUNET_NO;
3804}
3805
3806
3807/**
3808 * Called whenever something changed that might effect when we
3809 * try to do the next transmission on @a queue using #transmit_on_queue().
3810 *
3811 * @param queue the queue to do scheduling for
3812 * @param p task priority to use, if @a queue is scheduled
3813 */
3814static void
3815schedule_transmit_on_queue (struct GNUNET_TIME_Relative delay,
3816 struct Queue *queue,
3817 enum GNUNET_SCHEDULER_Priority p)
3818{
3819 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
3820
3821 if (queue->validated_until.abs_value_us < now.abs_value_us)
3822 return;
3823 if (check_for_queue_with_higher_prio (queue,
3824 queue->tc->details.communicator.
3825 queue_head))
3826 return;
3827
3828 if (queue->tc->details.communicator.total_queue_length >=
3829 COMMUNICATOR_TOTAL_QUEUE_LIMIT)
3830 {
3831 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3832 "Transmission on queue %s (QID %u) throttled due to communicator queue limit\n",
3833 queue->address,
3834 queue->qid);
3835 GNUNET_STATISTICS_update (
3836 GST_stats,
3837 "# Transmission throttled due to communicator queue limit",
3838 1,
3839 GNUNET_NO);
3840 queue->idle = GNUNET_NO;
3841 return;
3842 }
3843 if (queue->queue_length >= QUEUE_LENGTH_LIMIT)
3844 {
3845 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3846 "Transmission on queue %s (QID %u) throttled due to communicator queue length limit\n",
3847 queue->address,
3848 queue->qid);
3849 GNUNET_STATISTICS_update (GST_stats,
3850 "# Transmission throttled due to queue queue limit",
3851 1,
3852 GNUNET_NO);
3853 queue->idle = GNUNET_NO;
3854 return;
3855 }
3856 if (0 == queue->q_capacity)
3857 {
3858 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3859 "Transmission on queue %s (QID %u) throttled due to communicator message has capacity %"
3860 PRIu64 ".\n",
3861 queue->address,
3862 queue->qid,
3863 queue->q_capacity);
3864 GNUNET_STATISTICS_update (GST_stats,
3865 "# Transmission throttled due to message queue capacity",
3866 1,
3867 GNUNET_NO);
3868 queue->idle = GNUNET_NO;
3869 return;
3870 }
3871 /* queue might indeed be ready, schedule it */
3872 if (NULL != queue->transmit_task)
3873 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3874 queue->transmit_task =
3875 GNUNET_SCHEDULER_add_delayed_with_priority (delay, p, &transmit_on_queue,
3876 queue);
3877 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3878 "Considering transmission on queue `%s' QID %llu to %s\n",
3879 queue->address,
3880 (unsigned long long) queue->qid,
3881 GNUNET_i2s (&queue->neighbour->pid));
3882}
3883
3884
3885/**
3886 * Task run to check whether the hops of the @a cls still
3887 * are validated, or if we need to core about disconnection.
3888 *
3889 * @param cls a `struct VirtualLink`
3890 */
3891static void
3892check_link_down (void *cls)
3893{
3894 struct VirtualLink *vl = cls;
3895 struct DistanceVector *dv = vl->dv;
3896 struct Neighbour *n = vl->n;
3897 struct GNUNET_TIME_Absolute dvh_timeout;
3898 struct GNUNET_TIME_Absolute q_timeout;
3899
3900 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3901 "Checking if link is down\n");
3902 vl->visibility_task = NULL;
3903 dvh_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3904 if (NULL != dv)
3905 {
3906 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
3907 pos = pos->next_dv)
3908 dvh_timeout = GNUNET_TIME_absolute_max (dvh_timeout,
3909 pos->path_valid_until);
3910 if (0 == GNUNET_TIME_absolute_get_remaining (dvh_timeout).rel_value_us)
3911 {
3912 vl->dv->vl = NULL;
3913 vl->dv = NULL;
3914 }
3915 }
3916 q_timeout = GNUNET_TIME_UNIT_ZERO_ABS;
3917 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
3918 q_timeout = GNUNET_TIME_absolute_max (q_timeout, q->validated_until);
3919 if (0 == GNUNET_TIME_absolute_get_remaining (q_timeout).rel_value_us)
3920 {
3921 vl->n->vl = NULL;
3922 vl->n = NULL;
3923 }
3924 if ((NULL == vl->n) && (NULL == vl->dv))
3925 {
3926 cores_send_disconnect_info (&vl->target);
3927 free_virtual_link (vl);
3928 return;
3929 }
3930 vl->visibility_task =
3931 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_max (q_timeout, dvh_timeout),
3932 &check_link_down,
3933 vl);
3934}
3935
3936
3937/**
3938 * Free @a queue.
3939 *
3940 * @param queue the queue to free
3941 */
3942static void
3943free_queue (struct Queue *queue)
3944{
3945 struct Neighbour *neighbour = queue->neighbour;
3946 struct TransportClient *tc = queue->tc;
3947 struct MonitorEvent me = { .cs = GNUNET_TRANSPORT_CS_DOWN,
3948 .rtt = GNUNET_TIME_UNIT_FOREVER_REL };
3949 struct QueueEntry *qe;
3950 int maxxed;
3951 struct PendingAcknowledgement *pa;
3952 struct VirtualLink *vl;
3953
3954 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3955 "Cleaning up queue %u\n", queue->qid);
3956 if (NULL != queue->mo)
3957 {
3958 GNUNET_PEERSTORE_monitor_stop (queue->mo);
3959 queue->mo = NULL;
3960 }
3961 if (NULL != queue->transmit_task)
3962 {
3963 GNUNET_SCHEDULER_cancel (queue->transmit_task);
3964 queue->transmit_task = NULL;
3965 }
3966 while (NULL != (pa = queue->pa_head))
3967 {
3968 GNUNET_CONTAINER_MDLL_remove (queue, queue->pa_head, queue->pa_tail, pa);
3969 pa->queue = NULL;
3970 }
3971
3972 GNUNET_CONTAINER_MDLL_remove (neighbour,
3973 neighbour->queue_head,
3974 neighbour->queue_tail,
3975 queue);
3976 GNUNET_CONTAINER_MDLL_remove (client,
3977 tc->details.communicator.queue_head,
3978 tc->details.communicator.queue_tail,
3979 queue);
3980 maxxed = (COMMUNICATOR_TOTAL_QUEUE_LIMIT <=
3981 tc->details.communicator.total_queue_length);
3982 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
3983 "Cleaning up queue with length %u\n",
3984 queue->queue_length);
3985 while (NULL != (qe = queue->queue_head))
3986 {
3987 GNUNET_CONTAINER_DLL_remove (queue->queue_head, queue->queue_tail, qe);
3988 queue->queue_length--;
3989 tc->details.communicator.total_queue_length--;
3990 if (NULL != qe->pm)
3991 {
3992 GNUNET_assert (qe == qe->pm->qe);
3993 qe->pm->qe = NULL;
3994 }
3995 GNUNET_free (qe);
3996 }
3997 GNUNET_assert (0 == queue->queue_length);
3998 if ((maxxed) && (COMMUNICATOR_TOTAL_QUEUE_LIMIT >
3999 tc->details.communicator.total_queue_length))
4000 {
4001 /* Communicator dropped below threshold, resume all _other_ queues */
4002 GNUNET_STATISTICS_update (
4003 GST_stats,
4004 "# Transmission throttled due to communicator queue limit",
4005 -1,
4006 GNUNET_NO);
4007 for (struct Queue *s = tc->details.communicator.queue_head; NULL != s;
4008 s = s->next_client)
4009 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
4010 s,
4011 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
4012 }
4013 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
4014 GNUNET_free (queue);
4015
4016 vl = lookup_virtual_link (&neighbour->pid);
4017 if ((NULL != vl) && (neighbour == vl->n))
4018 {
4019 GNUNET_SCHEDULER_cancel (vl->visibility_task);
4020 check_link_down (vl);
4021 }
4022 if (NULL == neighbour->queue_head)
4023 {
4024 free_neighbour (neighbour);
4025 }
4026}
4027
4028
4029/**
4030 * Free @a ale
4031 *
4032 * @param ale address list entry to free
4033 */
4034static void
4035free_address_list_entry (struct AddressListEntry *ale)
4036{
4037 struct TransportClient *tc = ale->tc;
4038
4039 GNUNET_CONTAINER_DLL_remove (tc->details.communicator.addr_head,
4040 tc->details.communicator.addr_tail,
4041 ale);
4042 if (NULL != ale->sc)
4043 {
4044 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4045 "store cancel\n");
4046 GNUNET_PEERSTORE_store_cancel (ale->sc);
4047 ale->sc = NULL;
4048 }
4049 if (NULL != ale->st)
4050 {
4051 GNUNET_SCHEDULER_cancel (ale->st);
4052 ale->st = NULL;
4053 }
4054 if (NULL != ale->signed_address)
4055 GNUNET_free (ale->signed_address);
4056 GNUNET_free (ale);
4057}
4058
4059
4060/**
4061 * Stop the peer request in @a value.
4062 *
4063 * @param cls a `struct TransportClient` that no longer makes the request
4064 * @param pid the peer's identity
4065 * @param value a `struct PeerRequest`
4066 * @return #GNUNET_YES (always)
4067 */
4068static int
4069stop_peer_request (void *cls,
4070 const struct GNUNET_PeerIdentity *pid,
4071 void *value)
4072{
4073 struct TransportClient *tc = cls;
4074 struct PeerRequest *pr = value;
4075
4076 if (NULL != pr->nc)
4077 GNUNET_PEERSTORE_monitor_stop (pr->nc);
4078 pr->nc = NULL;
4079 GNUNET_assert (
4080 GNUNET_YES ==
4081 GNUNET_CONTAINER_multipeermap_remove (tc->details.application.requests,
4082 pid,
4083 pr));
4084 GNUNET_free (pr);
4085
4086 return GNUNET_OK;
4087}
4088
4089
4090static void
4091do_shutdown (void *cls);
4092
4093/**
4094 * Called whenever a client is disconnected. Frees our
4095 * resources associated with that client.
4096 *
4097 * @param cls closure, NULL
4098 * @param client identification of the client
4099 * @param app_ctx our `struct TransportClient`
4100 */
4101static void
4102client_disconnect_cb (void *cls,
4103 struct GNUNET_SERVICE_Client *client,
4104 void *app_ctx)
4105{
4106 struct TransportClient *tc = app_ctx;
4107
4108 (void) cls;
4109 (void) client;
4110 GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
4111 switch (tc->type)
4112 {
4113 case CT_NONE:
4114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4115 "Unknown Client %p disconnected, cleaning up.\n",
4116 tc);
4117 break;
4118
4119 case CT_CORE: {
4120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4121 "CORE Client %p disconnected, cleaning up.\n",
4122 tc);
4123
4124 struct PendingMessage *pm;
4125
4126 while (NULL != (pm = tc->details.core.pending_msg_head))
4127 {
4128 GNUNET_CONTAINER_MDLL_remove (client,
4129 tc->details.core.pending_msg_head,
4130 tc->details.core.pending_msg_tail,
4131 pm);
4132 pm->client = NULL;
4133 }
4134 }
4135 break;
4136
4137 case CT_MONITOR:
4138 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4139 "MONITOR Client %p disconnected, cleaning up.\n",
4140 tc);
4141
4142 break;
4143
4144 case CT_COMMUNICATOR: {
4145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4146 "COMMUNICATOR Client %p disconnected, cleaning up.\n",
4147 tc);
4148
4149 struct Queue *q;
4150 struct AddressListEntry *ale;
4151
4152 if (NULL != tc->details.communicator.free_queue_entry_task)
4153 GNUNET_SCHEDULER_cancel (
4154 tc->details.communicator.free_queue_entry_task);
4155 while (NULL != (q = tc->details.communicator.queue_head))
4156 free_queue (q);
4157 while (NULL != (ale = tc->details.communicator.addr_head))
4158 free_address_list_entry (ale);
4159 GNUNET_free (tc->details.communicator.address_prefix);
4160 }
4161 break;
4162
4163 case CT_APPLICATION:
4164 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4165 "APPLICATION Client %p disconnected, cleaning up.\n",
4166 tc);
4167
4168 GNUNET_CONTAINER_multipeermap_iterate (tc->details.application.requests,
4169 &stop_peer_request,
4170 tc);
4171 GNUNET_CONTAINER_multipeermap_destroy (tc->details.application.requests);
4172 break;
4173 }
4174 GNUNET_free (tc);
4175 if ((GNUNET_YES == in_shutdown) && (NULL == clients_head))
4176 {
4177 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
4178 "Our last client disconnected\n");
4179 do_shutdown (cls);
4180 }
4181}
4182
4183
4184/**
4185 * Iterator telling new CORE client about all existing
4186 * connections to peers.
4187 *
4188 * @param cls the new `struct TransportClient`
4189 * @param pid a connected peer
4190 * @param value the `struct Neighbour` with more information
4191 * @return #GNUNET_OK (continue to iterate)
4192 */
4193static int
4194notify_client_connect_info (void *cls,
4195 const struct GNUNET_PeerIdentity *pid,
4196 void *value)
4197{
4198 struct TransportClient *tc = cls;
4199 struct VirtualLink *vl = value;
4200
4201 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4202 return GNUNET_OK;
4203
4204 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4205 "Telling new CORE client about existing connection to %s\n",
4206 GNUNET_i2s (pid));
4207 core_send_connect_info (tc, pid);
4208 return GNUNET_OK;
4209}
4210
4211
4212/**
4213 * Send ACK to communicator (if requested) and free @a cmc.
4214 *
4215 * @param cmc context for which we are done handling the message
4216 */
4217static void
4218finish_cmc_handling_with_continue (struct CommunicatorMessageContext *cmc,
4219 unsigned
4220 int free_cmc);
4221
4222static enum GNUNET_GenericReturnValue
4223resume_communicators (void *cls,
4224 const struct GNUNET_PeerIdentity *pid,
4225 void *value)
4226{
4227 struct VirtualLink *vl = value;
4228 struct CommunicatorMessageContext *cmc;
4229
4230 /* resume communicators */
4231 while (NULL != (cmc = vl->cmc_tail))
4232 {
4233 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4234 if (GNUNET_NO == cmc->continue_send)
4235 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
4236 }
4237 return GNUNET_OK;
4238}
4239
4240
4241/**
4242 * Initialize a "CORE" client. We got a start message from this
4243 * client, so add it to the list of clients for broadcasting of
4244 * inbound messages.
4245 *
4246 * @param cls the client
4247 * @param start the start message that was sent
4248 */
4249static void
4250handle_client_start (void *cls, const struct StartMessage *start)
4251{
4252 struct TransportClient *tc = cls;
4253 uint32_t options;
4254
4255 options = ntohl (start->options);
4256 if ((0 != (1 & options)) &&
4257 (0 != GNUNET_memcmp (&start->self, &GST_my_identity)))
4258 {
4259 /* client thinks this is a different peer, reject */
4260 GNUNET_break (0);
4261 GNUNET_SERVICE_client_drop (tc->client);
4262 return;
4263 }
4264 if (CT_NONE != tc->type)
4265 {
4266 GNUNET_break (0);
4267 GNUNET_SERVICE_client_drop (tc->client);
4268 return;
4269 }
4270 tc->type = CT_CORE;
4271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4272 "New CORE client with PID %s registered\n",
4273 GNUNET_i2s (&start->self));
4274 GNUNET_CONTAINER_multipeermap_iterate (links,
4275 &notify_client_connect_info,
4276 tc);
4277 GNUNET_CONTAINER_multipeermap_iterate (links,
4278 &resume_communicators,
4279 NULL);
4280 GNUNET_SERVICE_client_continue (tc->client);
4281}
4282
4283
4284/**
4285 * Client asked for transmission to a peer. Process the request.
4286 *
4287 * @param cls the client
4288 * @param obm the send message that was sent
4289 */
4290static int
4291check_client_send (void *cls, const struct OutboundMessage *obm)
4292{
4293 struct TransportClient *tc = cls;
4294 uint16_t size;
4295 const struct GNUNET_MessageHeader *obmm;
4296
4297 if (CT_CORE != tc->type)
4298 {
4299 GNUNET_break (0);
4300 return GNUNET_SYSERR;
4301 }
4302 size = ntohs (obm->header.size) - sizeof(struct OutboundMessage);
4303 if (size < sizeof(struct GNUNET_MessageHeader))
4304 {
4305 GNUNET_break (0);
4306 return GNUNET_SYSERR;
4307 }
4308 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
4309 if (size != ntohs (obmm->size))
4310 {
4311 GNUNET_break (0);
4312 return GNUNET_SYSERR;
4313 }
4314 return GNUNET_OK;
4315}
4316
4317
4318/**
4319 * Send a response to the @a pm that we have processed a "send"
4320 * request. Sends a confirmation to the "core" client responsible for
4321 * the original request and free's @a pm.
4322 *
4323 * @param pm handle to the original pending message
4324 */
4325static void
4326client_send_response (struct PendingMessage *pm)
4327{
4328 struct TransportClient *tc = pm->client;
4329 struct VirtualLink *vl = pm->vl;
4330
4331 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4332 "client send response\n");
4333 if (NULL != tc)
4334 {
4335 struct GNUNET_MQ_Envelope *env;
4336 struct SendOkMessage *so_msg;
4337
4338 env = GNUNET_MQ_msg (so_msg, GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
4339 so_msg->peer = vl->target;
4340 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4341 "Confirming transmission of <%" PRIu64 "> to %s\n",
4342 pm->logging_uuid,
4343 GNUNET_i2s (&vl->target));
4344 GNUNET_MQ_send (tc->mq, env);
4345 }
4346 free_pending_message (pm);
4347}
4348
4349
4350/**
4351 * Pick @a hops_array_length random DV paths satisfying @a options
4352 *
4353 * @param dv data structure to pick paths from
4354 * @param options constraints to satisfy
4355 * @param[out] hops_array set to the result
4356 * @param hops_array_length length of the @a hops_array
4357 * @return number of entries set in @a hops_array
4358 */
4359static unsigned int
4360pick_random_dv_hops (const struct DistanceVector *dv,
4361 enum RouteMessageOptions options,
4362 struct DistanceVectorHop **hops_array,
4363 unsigned int hops_array_length)
4364{
4365 uint64_t choices[hops_array_length];
4366 uint64_t num_dv;
4367 unsigned int dv_count;
4368
4369 /* Pick random vectors, but weighted by distance, giving more weight
4370 to shorter vectors */
4371 num_dv = 0;
4372 dv_count = 0;
4373 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4374 pos = pos->next_dv)
4375 {
4376 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4377 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4378 .rel_value_us == 0))
4379 continue; /* pos unconfirmed and confirmed required */
4380 num_dv += MAX_DV_HOPS_ALLOWED - pos->distance;
4381 dv_count++;
4382 }
4383 if (0 == dv_count)
4384 return 0;
4385 if (dv_count <= hops_array_length)
4386 {
4387 dv_count = 0;
4388 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4389 pos = pos->next_dv)
4390 hops_array[dv_count++] = pos;
4391 return dv_count;
4392 }
4393 for (unsigned int i = 0; i < hops_array_length; i++)
4394 {
4395 int ok = GNUNET_NO;
4396 while (GNUNET_NO == ok)
4397 {
4398 choices[i] =
4399 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, num_dv);
4400 ok = GNUNET_YES;
4401 for (unsigned int j = 0; j < i; j++)
4402 if (choices[i] == choices[j])
4403 {
4404 ok = GNUNET_NO;
4405 break;
4406 }
4407 }
4408 }
4409 dv_count = 0;
4410 num_dv = 0;
4411 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
4412 pos = pos->next_dv)
4413 {
4414 uint32_t delta = MAX_DV_HOPS_ALLOWED - pos->distance;
4415
4416 if ((0 == (options & RMO_UNCONFIRMED_ALLOWED)) &&
4417 (GNUNET_TIME_absolute_get_remaining (pos->path_valid_until)
4418 .rel_value_us == 0))
4419 continue; /* pos unconfirmed and confirmed required */
4420 for (unsigned int i = 0; i < hops_array_length; i++)
4421 if ((num_dv <= choices[i]) && (num_dv + delta > choices[i]))
4422 hops_array[dv_count++] = pos;
4423 num_dv += delta;
4424 }
4425 return dv_count;
4426}
4427
4428
4429/**
4430 * Communicator started. Test message is well-formed.
4431 *
4432 * @param cls the client
4433 * @param cam the send message that was sent
4434 */
4435static int
4436check_communicator_available (
4437 void *cls,
4438 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4439{
4440 struct TransportClient *tc = cls;
4441 uint16_t size;
4442
4443 if (CT_NONE != tc->type)
4444 {
4445 GNUNET_break (0);
4446 return GNUNET_SYSERR;
4447 }
4448 tc->type = CT_COMMUNICATOR;
4449 size = ntohs (cam->header.size) - sizeof(*cam);
4450 if (0 == size)
4451 return GNUNET_OK; /* receive-only communicator */
4452 GNUNET_MQ_check_zero_termination (cam);
4453 return GNUNET_OK;
4454}
4455
4456
4457/**
4458 * Send ACK to communicator (if requested) and free @a cmc.
4459 *
4460 * @param cmc context for which we are done handling the message
4461 */
4462static void
4463finish_cmc_handling_with_continue (struct CommunicatorMessageContext *cmc,
4464 unsigned
4465 int free_cmc)
4466{
4467 if (0 != ntohl (cmc->im.fc_on))
4468 {
4469 /* send ACK when done to communicator for flow control! */
4470 struct GNUNET_MQ_Envelope *env;
4471 struct GNUNET_TRANSPORT_IncomingMessageAck *ack;
4472
4473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4474 "Acknowledge message with flow control id %" PRIu64 "\n",
4475 cmc->im.fc_id);
4476 env = GNUNET_MQ_msg (ack, GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG_ACK);
4477 ack->reserved = htonl (0);
4478 ack->fc_id = cmc->im.fc_id;
4479 ack->sender = cmc->im.neighbour_sender;
4480 GNUNET_MQ_send (cmc->tc->mq, env);
4481 }
4482
4483 GNUNET_SERVICE_client_continue (cmc->tc->client);
4484
4485 if (GNUNET_YES == free_cmc)
4486 {
4487 GNUNET_free (cmc);
4488 }
4489}
4490
4491
4492static void
4493finish_cmc_handling (struct CommunicatorMessageContext *cmc)
4494{
4495 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
4496}
4497
4498
4499/**
4500 * Client confirms that it is done handling message(s) to a particular
4501 * peer. We may now provide more messages to CORE for this peer.
4502 *
4503 * Notifies the respective queues that more messages can now be received.
4504 *
4505 * @param cls the client
4506 * @param rom the message that was sent
4507 */
4508static void
4509handle_client_recv_ok (void *cls, const struct RecvOkMessage *rom)
4510{
4511 struct TransportClient *tc = cls;
4512 struct VirtualLink *vl;
4513 uint32_t delta;
4514 struct CommunicatorMessageContext *cmc;
4515
4516 if (CT_CORE != tc->type)
4517 {
4518 GNUNET_break (0);
4519 GNUNET_SERVICE_client_drop (tc->client);
4520 return;
4521 }
4522 vl = lookup_virtual_link (&rom->peer);
4523 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
4524 {
4525 GNUNET_STATISTICS_update (GST_stats,
4526 "# RECV_OK dropped: virtual link unknown",
4527 1,
4528 GNUNET_NO);
4529 GNUNET_SERVICE_client_continue (tc->client);
4530 return;
4531 }
4532 delta = ntohl (rom->increase_window_delta);
4533 vl->core_recv_window += delta;
4534 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4535 "CORE ack receiving message, increased CORE recv window to %d\n",
4536 vl->core_recv_window);
4537 GNUNET_SERVICE_client_continue (tc->client);
4538 if (vl->core_recv_window <= 0)
4539 return;
4540 /* resume communicators */
4541 while (NULL != (cmc = vl->cmc_tail))
4542 {
4543 GNUNET_CONTAINER_DLL_remove (vl->cmc_head, vl->cmc_tail, cmc);
4544 if (GNUNET_NO == cmc->continue_send)
4545 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
4546 }
4547}
4548
4549
4550/**
4551 * Communicator started. Process the request.
4552 *
4553 * @param cls the client
4554 * @param cam the send message that was sent
4555 */
4556static void
4557handle_communicator_available (
4558 void *cls,
4559 const struct GNUNET_TRANSPORT_CommunicatorAvailableMessage *cam)
4560{
4561 struct TransportClient *tc = cls;
4562 uint16_t size;
4563
4564 size = ntohs (cam->header.size) - sizeof(*cam);
4565 if (0 == size)
4566 {
4567 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4568 "Receive-only communicator connected\n");
4569 return; /* receive-only communicator */
4570 }
4571 tc->details.communicator.address_prefix =
4572 GNUNET_strdup ((const char *) &cam[1]);
4573 tc->details.communicator.cc =
4574 (enum GNUNET_TRANSPORT_CommunicatorCharacteristics) ntohl (cam->cc);
4575 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4576 "Communicator with prefix `%s' connected\n",
4577 tc->details.communicator.address_prefix);
4578 GNUNET_SERVICE_client_continue (tc->client);
4579}
4580
4581
4582/**
4583 * Communicator requests backchannel transmission. Check the request.
4584 *
4585 * @param cls the client
4586 * @param cb the send message that was sent
4587 * @return #GNUNET_OK if message is well-formed
4588 */
4589static int
4590check_communicator_backchannel (
4591 void *cls,
4592 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
4593{
4594 const struct GNUNET_MessageHeader *inbox;
4595 const char *is;
4596 uint16_t msize;
4597 uint16_t isize;
4598
4599 (void) cls;
4600 msize = ntohs (cb->header.size) - sizeof(*cb);
4601 inbox = (const struct GNUNET_MessageHeader *) &cb[1];
4602 isize = ntohs (inbox->size);
4603 if (isize >= msize)
4604 {
4605 GNUNET_break (0);
4606 return GNUNET_SYSERR;
4607 }
4608 is = (const char *) inbox;
4609 is += isize;
4610 msize -= isize;
4611 GNUNET_assert (0 < msize);
4612 if ('\0' != is[msize - 1])
4613 {
4614 GNUNET_break (0);
4615 return GNUNET_SYSERR;
4616 }
4617 return GNUNET_OK;
4618}
4619
4620
4621/**
4622 * Sign ephemeral keys in our @a dv are current.
4623 *
4624 * @param[in,out] dv virtual link to update ephemeral for
4625 */
4626static void
4627sign_ephemeral (struct DistanceVector *dv)
4628{
4629 struct EphemeralConfirmationPS ec;
4630
4631 dv->monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
4632 dv->ephemeral_validity =
4633 GNUNET_TIME_absolute_add (dv->monotime, EPHEMERAL_VALIDITY);
4634 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
4635 ec.target = dv->target;
4636 ec.ephemeral_key = dv->ephemeral_key;
4637 ec.sender_monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
4638 ec.purpose.size = htonl (sizeof(ec));
4639 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
4640 &ec,
4641 &dv->sender_sig);
4642}
4643
4644
4645static void
4646free_queue_entry (struct QueueEntry *qe,
4647 struct TransportClient *tc);
4648
4649
4650static void
4651free_timedout_queue_entry (void *cls)
4652{
4653 struct TransportClient *tc = cls;
4654 struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
4655
4656 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4657 "freeing timedout queue entries\n");
4658
4659 tc->details.communicator.free_queue_entry_task = NULL;
4660 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
4661 queue = queue->next_client)
4662 {
4663 struct QueueEntry *qep = queue->queue_head;
4664
4665 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4666 "checking QID %u for timedout queue entries\n",
4667 queue->qid);
4668 while (NULL != qep)
4669 {
4670 struct QueueEntry *pos = qep;
4671
4672 qep = qep->next;
4673 struct GNUNET_TIME_Relative diff = GNUNET_TIME_absolute_get_difference (
4674 pos->creation_timestamp, now);
4675
4676 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4677 "diff to now %s \n",
4678 GNUNET_TIME_relative2s (diff, GNUNET_NO));
4679 if (GNUNET_TIME_relative_cmp (QUEUE_ENTRY_TIMEOUT, <, diff))
4680 {
4681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4682 "Freeing timed out QueueEntry with MID %" PRIu64
4683 " and QID %u\n",
4684 pos->mid,
4685 queue->qid);
4686 free_queue_entry (pos, tc);
4687 }
4688 }
4689 }
4690}
4691
4692
4693/**
4694 * Send the message @a payload on @a queue.
4695 *
4696 * @param queue the queue to use for transmission
4697 * @param pm pending message to update once transmission is done, may be NULL!
4698 * @param payload the payload to send (encapsulated in a
4699 * #GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG).
4700 * @param payload_size number of bytes in @a payload
4701 */
4702static void
4703queue_send_msg (struct Queue *queue,
4704 struct PendingMessage *pm,
4705 const void *payload,
4706 size_t payload_size)
4707{
4708 struct Neighbour *n = queue->neighbour;
4709 struct GNUNET_TRANSPORT_SendMessageTo *smt;
4710 struct GNUNET_MQ_Envelope *env;
4711 struct PendingAcknowledgement *pa;
4712
4713 GNUNET_log (
4714 GNUNET_ERROR_TYPE_DEBUG,
4715 "Queueing %u bytes of payload for transmission <%" PRIu64
4716 "> on queue %llu to %s\n",
4717 (unsigned int) payload_size,
4718 (NULL == pm) ? 0 : pm->logging_uuid,
4719 (unsigned long long) queue->qid,
4720 GNUNET_i2s (&queue->neighbour->pid));
4721 env = GNUNET_MQ_msg_extra (smt,
4722 payload_size,
4723 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG);
4724 smt->qid = htonl (queue->qid);
4725 smt->mid = GNUNET_htonll (queue->mid_gen);
4726 smt->receiver = n->pid;
4727 memcpy (&smt[1], payload, payload_size);
4728 {
4729 /* Pass the env to the communicator of queue for transmission. */
4730 struct QueueEntry *qe;
4731
4732 qe = GNUNET_new (struct QueueEntry);
4733 qe->creation_timestamp = GNUNET_TIME_absolute_get ();
4734 qe->mid = queue->mid_gen;
4735 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4736 "Create QueueEntry with MID %" PRIu64
4737 " and QID %u and prefix %s\n",
4738 qe->mid,
4739 queue->qid,
4740 queue->tc->details.communicator.address_prefix);
4741 queue->mid_gen++;
4742 qe->queue = queue;
4743 if (NULL != pm)
4744 {
4745 qe->pm = pm;
4746 // TODO Why do we have a retransmission. When we know, make decision if we still want this.
4747 // GNUNET_assert (NULL == pm->qe);
4748 if (NULL != pm->qe)
4749 {
4750 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4751 "Retransmitting message <%" PRIu64
4752 "> remove pm from qe with MID: %llu \n",
4753 pm->logging_uuid,
4754 (unsigned long long) pm->qe->mid);
4755 pm->qe->pm = NULL;
4756 }
4757 pm->qe = qe;
4758 }
4759 GNUNET_assert (CT_COMMUNICATOR == queue->tc->type);
4760 if (0 == queue->q_capacity)
4761 {
4762 // Messages without FC or fragments can get here.
4763 if (NULL != pm)
4764 {
4765 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4766 "Message %" PRIu64
4767 " (pm type %u) was not send because queue has no capacity.\n",
4768 pm->logging_uuid,
4769 pm->pmt);
4770 pm->qe = NULL;
4771 }
4772 GNUNET_free (env);
4773 GNUNET_free (qe);
4774 return;
4775 }
4776 GNUNET_CONTAINER_DLL_insert (queue->queue_head, queue->queue_tail, qe);
4777 queue->queue_length++;
4778 queue->tc->details.communicator.total_queue_length++;
4779 if (GNUNET_NO == queue->unlimited_length)
4780 queue->q_capacity--;
4781 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4782 "Queue %s with qid %u has capacity %" PRIu64 "\n",
4783 queue->address,
4784 queue->qid,
4785 queue->q_capacity);
4786 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT ==
4787 queue->tc->details.communicator.total_queue_length)
4788 queue->idle = GNUNET_NO;
4789 if (QUEUE_LENGTH_LIMIT == queue->queue_length)
4790 queue->idle = GNUNET_NO;
4791 if (0 == queue->q_capacity)
4792 queue->idle = GNUNET_NO;
4793
4794 if (GNUNET_NO == queue->idle)
4795 {
4796 struct TransportClient *tc = queue->tc;
4797
4798 if (NULL == tc->details.communicator.free_queue_entry_task)
4799 tc->details.communicator.free_queue_entry_task =
4800 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
4801 &
4802 free_timedout_queue_entry,
4803 tc);
4804 }
4805 if (NULL != pm && NULL != (pa = pm->pa_head))
4806 {
4807 while (pm != pa->pm)
4808 pa = pa->next_pa;
4809 pa->num_send++;
4810 }
4811 // GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
4812 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4813 "Sending message MID %" PRIu64
4814 " of type %u (%u) and size %lu with MQ %p queue %s (QID %u) pending %"
4815 PRIu64 "\n",
4816 GNUNET_ntohll (smt->mid),
4817 ntohs (((const struct GNUNET_MessageHeader *) payload)->type),
4818 ntohs (smt->header.size),
4819 (unsigned long) payload_size,
4820 queue->tc->mq,
4821 queue->address,
4822 queue->qid,
4823 (NULL == pm) ? 0 : pm->logging_uuid);
4824 GNUNET_MQ_send (queue->tc->mq, env);
4825 }
4826}
4827
4828
4829/**
4830 * Pick a queue of @a n under constraints @a options and schedule
4831 * transmission of @a hdr.
4832 *
4833 * @param n neighbour to send to
4834 * @param hdr message to send as payload
4835 * @param options whether queues must be confirmed or not,
4836 * and whether we may pick multiple (2) queues
4837 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
4838 */
4839static struct GNUNET_TIME_Relative
4840route_via_neighbour (const struct Neighbour *n,
4841 const struct GNUNET_MessageHeader *hdr,
4842 enum RouteMessageOptions options)
4843{
4844 struct GNUNET_TIME_Absolute now;
4845 unsigned int candidates;
4846 unsigned int sel1;
4847 unsigned int sel2;
4848 struct GNUNET_TIME_Relative rtt;
4849
4850 /* Pick one or two 'random' queues from n (under constraints of options) */
4851 now = GNUNET_TIME_absolute_get ();
4852 /* FIXME-OPTIMIZE: give queues 'weights' and pick proportional to
4853 weight in the future; weight could be assigned by observed
4854 bandwidth (note: not sure if we should do this for this type
4855 of control traffic though). */
4856 candidates = 0;
4857 for (struct Queue *pos = n->queue_head; NULL != pos;
4858 pos = pos->next_neighbour)
4859 {
4860 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4861 (pos->validated_until.abs_value_us > now.abs_value_us))
4862 candidates++;
4863 }
4864 if (0 == candidates)
4865 {
4866 /* This can happen rarely if the last confirmed queue timed
4867 out just as we were beginning to process this message. */
4868 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
4869 "Could not route message of type %u to %s: no valid queue\n",
4870 ntohs (hdr->type),
4871 GNUNET_i2s (&n->pid));
4872 GNUNET_STATISTICS_update (GST_stats,
4873 "# route selection failed (all no valid queue)",
4874 1,
4875 GNUNET_NO);
4876 return GNUNET_TIME_UNIT_FOREVER_REL;
4877 }
4878
4879 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
4880 sel1 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4881 if (0 == (options & RMO_REDUNDANT))
4882 sel2 = candidates; /* picks none! */
4883 else
4884 sel2 = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, candidates);
4885 candidates = 0;
4886 for (struct Queue *pos = n->queue_head; NULL != pos;
4887 pos = pos->next_neighbour)
4888 {
4889 if ((0 != (options & RMO_UNCONFIRMED_ALLOWED)) ||
4890 (pos->validated_until.abs_value_us > now.abs_value_us))
4891 {
4892 if ((sel1 == candidates) || (sel2 == candidates))
4893 {
4894 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4895 "Routing message of type %u to %s using %s (#%u)\n",
4896 ntohs (hdr->type),
4897 GNUNET_i2s (&n->pid),
4898 pos->address,
4899 (sel1 == candidates) ? 1 : 2);
4900 rtt = GNUNET_TIME_relative_min (rtt, pos->pd.aged_rtt);
4901 queue_send_msg (pos, NULL, hdr, ntohs (hdr->size));
4902 }
4903 candidates++;
4904 }
4905 }
4906 return rtt;
4907}
4908
4909
4910/**
4911 * Structure of the key material used to encrypt backchannel messages.
4912 */
4913struct DVKeyState
4914{
4915 /**
4916 * State of our block cipher.
4917 */
4918 gcry_cipher_hd_t cipher;
4919
4920 /**
4921 * Actual key material.
4922 */
4923 struct
4924 {
4925 /**
4926 * Key used for HMAC calculations (via #GNUNET_CRYPTO_hmac()).
4927 */
4928 struct GNUNET_CRYPTO_AuthKey hmac_key;
4929
4930 /**
4931 * Symmetric key to use for encryption.
4932 */
4933 char aes_key[256 / 8];
4934
4935 /**
4936 * Counter value to use during setup.
4937 */
4938 char aes_ctr[128 / 8];
4939 } material;
4940};
4941
4942
4943/**
4944 * Given the key material in @a km and the initialization vector
4945 * @a iv, setup the key material for the backchannel in @a key.
4946 *
4947 * @param km raw master secret
4948 * @param iv initialization vector
4949 * @param[out] key symmetric cipher and HMAC state to generate
4950 */
4951static void
4952dv_setup_key_state_from_km (const struct GNUNET_HashCode *km,
4953 const struct GNUNET_ShortHashCode *iv,
4954 struct DVKeyState *key)
4955{
4956 /* must match what we defive from decapsulated key */
4957 GNUNET_assert (GNUNET_YES ==
4958 GNUNET_CRYPTO_kdf (&key->material,
4959 sizeof(key->material),
4960 "transport-backchannel-key",
4961 strlen ("transport-backchannel-key"),
4962 km,
4963 sizeof(*km),
4964 iv,
4965 sizeof(*iv),
4966 NULL));
4967 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
4968 "Deriving backchannel key based on KM %s and IV %s\n",
4969 GNUNET_h2s (km),
4970 GNUNET_sh2s (iv));
4971 GNUNET_assert (0 == gcry_cipher_open (&key->cipher,
4972 GCRY_CIPHER_AES256 /* low level: go for speed */,
4973 GCRY_CIPHER_MODE_CTR,
4974 0 /* flags */));
4975 GNUNET_assert (0 == gcry_cipher_setkey (key->cipher,
4976 &key->material.aes_key,
4977 sizeof(key->material.aes_key)));
4978 gcry_cipher_setctr (key->cipher,
4979 &key->material.aes_ctr,
4980 sizeof(key->material.aes_ctr));
4981}
4982
4983
4984/**
4985 * Do HMAC calculation for backchannel messages over @a data using key
4986 * material from @a key.
4987 *
4988 * @param key key material (from DH)
4989 * @param[out] hmac set to the HMAC
4990 * @param data data to perform HMAC calculation over
4991 * @param data_size number of bytes in @a data
4992 */
4993static void
4994dv_hmac (const struct DVKeyState *key,
4995 struct GNUNET_HashCode *hmac,
4996 const void *data,
4997 size_t data_size)
4998{
4999 GNUNET_CRYPTO_hmac (&key->material.hmac_key, data, data_size, hmac);
5000}
5001
5002
5003/**
5004 * Perform backchannel encryption using symmetric secret in @a key
5005 * to encrypt data from @a in to @a dst.
5006 *
5007 * @param[in,out] key key material to use
5008 * @param dst where to write the result
5009 * @param in input data to encrypt (plaintext)
5010 * @param in_size number of bytes of input in @a in and available at @a dst
5011 */
5012static void
5013dv_encrypt (struct DVKeyState *key, const void *in, void *dst, size_t in_size)
5014{
5015 GNUNET_assert (0 ==
5016 gcry_cipher_encrypt (key->cipher, dst, in_size, in, in_size));
5017}
5018
5019
5020/**
5021 * Perform backchannel encryption using symmetric secret in @a key
5022 * to encrypt data from @a in to @a dst.
5023 *
5024 * @param[in,out] key key material to use
5025 * @param ciph cipher text to decrypt
5026 * @param[out] out output data to generate (plaintext)
5027 * @param out_size number of bytes of input in @a ciph and available in @a out
5028 * @return GNUNET_OK on success
5029 */
5030static enum GNUNET_GenericReturnValue
5031dv_decrypt (struct DVKeyState *key,
5032 void *out,
5033 const void *ciph,
5034 size_t out_size)
5035{
5036 return (0 ==
5037 gcry_cipher_decrypt (key->cipher,
5038 out, out_size,
5039 ciph, out_size)) ? GNUNET_OK : GNUNET_SYSERR;
5040}
5041
5042
5043/**
5044 * Clean up key material in @a key.
5045 *
5046 * @param key key material to clean up (memory must not be free'd!)
5047 */
5048static void
5049dv_key_clean (struct DVKeyState *key)
5050{
5051 gcry_cipher_close (key->cipher);
5052 GNUNET_CRYPTO_zero_keys (&key->material, sizeof(key->material));
5053}
5054
5055
5056/**
5057 * Function to call to further operate on the now DV encapsulated
5058 * message @a hdr, forwarding it via @a next_hop under respect of
5059 * @a options.
5060 *
5061 * @param cls closure
5062 * @param next_hop next hop of the DV path
5063 * @param hdr encapsulated message, technically a `struct TransportDFBoxMessage`
5064 * @param options options of the original message
5065 */
5066typedef void (*DVMessageHandler) (void *cls,
5067 struct Neighbour *next_hop,
5068 const struct GNUNET_MessageHeader *hdr,
5069 enum RouteMessageOptions options);
5070
5071/**
5072 * Pick a path of @a dv under constraints @a options and schedule
5073 * transmission of @a hdr.
5074 *
5075 * @param target neighbour to ultimately send to
5076 * @param num_dvhs length of the @a dvhs array
5077 * @param dvhs array of hops to send the message to
5078 * @param hdr message to send as payload
5079 * @param use function to call with the encapsulated message
5080 * @param use_cls closure for @a use
5081 * @param options whether path must be confirmed or not, to be passed to @a use
5082 * @param without_fc shall this TransportDVBoxMessage be forwarded without flow control.
5083 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
5084 */
5085static struct GNUNET_TIME_Relative
5086encapsulate_for_dv (struct DistanceVector *dv,
5087 unsigned int num_dvhs,
5088 struct DistanceVectorHop **dvhs,
5089 const struct GNUNET_MessageHeader *hdr,
5090 DVMessageHandler use,
5091 void *use_cls,
5092 enum RouteMessageOptions options,
5093 enum GNUNET_GenericReturnValue without_fc)
5094{
5095 struct TransportDVBoxMessage box_hdr;
5096 struct TransportDVBoxPayloadP payload_hdr;
5097 uint16_t enc_body_size = ntohs (hdr->size);
5098 char enc[sizeof(struct TransportDVBoxPayloadP) + enc_body_size] GNUNET_ALIGN;
5099 struct DVKeyState *key;
5100 struct GNUNET_TIME_Relative rtt;
5101 struct GNUNET_HashCode km;
5102
5103 key = GNUNET_new (struct DVKeyState);
5104 /* Encrypt payload */
5105 box_hdr.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX);
5106 box_hdr.total_hops = htons (0);
5107 box_hdr.without_fc = htons (without_fc);
5108 // update_ephemeral (dv);
5109 if (0 ==
5110 GNUNET_TIME_absolute_get_remaining (dv->ephemeral_validity).rel_value_us)
5111 {
5112 GNUNET_CRYPTO_eddsa_kem_encaps (&dv->target.public_key,
5113 &dv->ephemeral_key,
5114 &km);
5115 dv->km = GNUNET_new (struct GNUNET_HashCode);
5116 GNUNET_memcpy (dv->km, &km, sizeof(struct GNUNET_HashCode));
5117 sign_ephemeral (dv);
5118 }
5119 box_hdr.ephemeral_key = dv->ephemeral_key;
5120 payload_hdr.sender_sig = dv->sender_sig;
5121
5122 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
5123 &box_hdr.iv,
5124 sizeof(box_hdr.iv));
5125 // We are creating this key, so this must work.
5126 // FIXME: Possibly also add return values here. We are processing
5127 // Input from other peers...
5128 dv_setup_key_state_from_km (dv->km, &box_hdr.iv, key);
5129 payload_hdr.sender = GST_my_identity;
5130 payload_hdr.monotonic_time = GNUNET_TIME_absolute_hton (dv->monotime);
5131 dv_encrypt (key, &payload_hdr, enc, sizeof(payload_hdr));
5132 dv_encrypt (key,
5133 hdr,
5134 &enc[sizeof(struct TransportDVBoxPayloadP)],
5135 enc_body_size);
5136 dv_hmac (key, &box_hdr.hmac, enc, sizeof(enc));
5137 dv_key_clean (key);
5138 rtt = GNUNET_TIME_UNIT_FOREVER_REL;
5139 /* For each selected path, take the pre-computed header and body
5140 and add the path in the middle of the message; then send it. */
5141 for (unsigned int i = 0; i < num_dvhs; i++)
5142 {
5143 struct DistanceVectorHop *dvh = dvhs[i];
5144 unsigned int num_hops = dvh->distance + 1;
5145 char buf[sizeof(struct TransportDVBoxMessage)
5146 + sizeof(struct GNUNET_PeerIdentity) * num_hops
5147 + sizeof(struct TransportDVBoxPayloadP)
5148 + enc_body_size] GNUNET_ALIGN;
5149 struct GNUNET_PeerIdentity *dhops;
5150
5151 box_hdr.header.size = htons (sizeof(buf));
5152 box_hdr.orig_size = htons (sizeof(buf));
5153 box_hdr.num_hops = htons (num_hops);
5154 memcpy (buf, &box_hdr, sizeof(box_hdr));
5155 dhops = (struct GNUNET_PeerIdentity *) &buf[sizeof(box_hdr)];
5156 memcpy (dhops,
5157 dvh->path,
5158 dvh->distance * sizeof(struct GNUNET_PeerIdentity));
5159 dhops[dvh->distance] = dv->target;
5160 if (GNUNET_EXTRA_LOGGING > 0)
5161 {
5162 char *path;
5163
5164 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
5165 for (unsigned int j = 0; j < num_hops; j++)
5166 {
5167 char *tmp;
5168
5169 GNUNET_asprintf (&tmp, "%s-%s", path, GNUNET_i2s (&dhops[j]));
5170 GNUNET_free (path);
5171 path = tmp;
5172 }
5173 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5174 "Routing message of type %u to %s using DV (#%u/%u) via %s\n",
5175 ntohs (hdr->type),
5176 GNUNET_i2s (&dv->target),
5177 i + 1,
5178 num_dvhs,
5179 path);
5180 GNUNET_free (path);
5181 }
5182 rtt = GNUNET_TIME_relative_min (rtt, dvh->pd.aged_rtt);
5183 memcpy (&dhops[num_hops], enc, sizeof(enc));
5184 use (use_cls,
5185 dvh->next_hop,
5186 (const struct GNUNET_MessageHeader *) buf,
5187 options);
5188 GNUNET_free (key);
5189 }
5190 return rtt;
5191}
5192
5193
5194/**
5195 * Wrapper around #route_via_neighbour() that matches the
5196 * #DVMessageHandler structure.
5197 *
5198 * @param cls unused
5199 * @param next_hop where to send next
5200 * @param hdr header of the message to send
5201 * @param options message options for queue selection
5202 */
5203static void
5204send_dv_to_neighbour (void *cls,
5205 struct Neighbour *next_hop,
5206 const struct GNUNET_MessageHeader *hdr,
5207 enum RouteMessageOptions options)
5208{
5209 (void) cls;
5210 (void) route_via_neighbour (next_hop, hdr, RMO_UNCONFIRMED_ALLOWED);
5211}
5212
5213
5214/**
5215 * We need to transmit @a hdr to @a target. If necessary, this may
5216 * involve DV routing. This function routes without applying flow
5217 * control or congestion control and should only be used for control
5218 * traffic.
5219 *
5220 * @param target peer to receive @a hdr
5221 * @param hdr header of the message to route and #GNUNET_free()
5222 * @param options which transmission channels are allowed
5223 * @return expected RTT for transmission, #GNUNET_TIME_UNIT_FOREVER_REL if sending failed
5224 */
5225static struct GNUNET_TIME_Relative
5226route_control_message_without_fc (struct VirtualLink *vl,
5227// route_control_message_without_fc (const struct GNUNET_PeerIdentity *target,
5228 const struct GNUNET_MessageHeader *hdr,
5229 enum RouteMessageOptions options)
5230{
5231 // struct VirtualLink *vl;
5232 struct Neighbour *n;
5233 struct DistanceVector *dv;
5234 struct GNUNET_TIME_Relative rtt1;
5235 struct GNUNET_TIME_Relative rtt2;
5236 const struct GNUNET_PeerIdentity *target = &vl->target;
5237
5238 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5239 "Trying to route message of type %u to %s without fc\n",
5240 ntohs (hdr->type),
5241 GNUNET_i2s (target));
5242
5243 // TODO Do this elsewhere. vl should be given as parameter to method.
5244 // vl = lookup_virtual_link (target);
5245 GNUNET_assert (NULL != vl && GNUNET_YES == vl->confirmed);
5246 if (NULL == vl)
5247 return GNUNET_TIME_UNIT_FOREVER_REL;
5248 n = vl->n;
5249 dv = (0 != (options & RMO_DV_ALLOWED)) ? vl->dv : NULL;
5250 if (0 == (options & RMO_UNCONFIRMED_ALLOWED))
5251 {
5252 /* if confirmed is required, and we do not have anything
5253 confirmed, drop respective options */
5254 if (NULL == n)
5255 n = lookup_neighbour (target);
5256 if ((NULL == dv) && (0 != (options & RMO_DV_ALLOWED)))
5257 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, target);
5258 }
5259 if ((NULL == n) && (NULL == dv))
5260 {
5261 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5262 "Cannot route message of type %u to %s: no route\n",
5263 ntohs (hdr->type),
5264 GNUNET_i2s (target));
5265 GNUNET_STATISTICS_update (GST_stats,
5266 "# Messages dropped in routing: no acceptable method",
5267 1,
5268 GNUNET_NO);
5269 return GNUNET_TIME_UNIT_FOREVER_REL;
5270 }
5271 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5272 "Routing message of type %u to %s with options %X\n",
5273 ntohs (hdr->type),
5274 GNUNET_i2s (target),
5275 (unsigned int) options);
5276 /* If both dv and n are possible and we must choose:
5277 flip a coin for the choice between the two; for now 50/50 */
5278 if ((NULL != n) && (NULL != dv) && (0 == (options & RMO_REDUNDANT)))
5279 {
5280 if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 2))
5281 n = NULL;
5282 else
5283 dv = NULL;
5284 }
5285 if ((NULL != n) && (NULL != dv))
5286 options &= ~RMO_REDUNDANT; /* We will do one DV and one direct, that's
5287 enough for redundancy, so clear the flag. */
5288 rtt1 = GNUNET_TIME_UNIT_FOREVER_REL;
5289 rtt2 = GNUNET_TIME_UNIT_FOREVER_REL;
5290 if (NULL != n)
5291 {
5292 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5293 "Try to route message of type %u to %s without fc via neighbour\n",
5294 ntohs (hdr->type),
5295 GNUNET_i2s (target));
5296 rtt1 = route_via_neighbour (n, hdr, options);
5297 }
5298 if (NULL != dv)
5299 {
5300 struct DistanceVectorHop *hops[2];
5301 unsigned int res;
5302
5303 res = pick_random_dv_hops (dv,
5304 options,
5305 hops,
5306 (0 == (options & RMO_REDUNDANT)) ? 1 : 2);
5307 if (0 == res)
5308 {
5309 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
5310 "Failed to route message, could not determine DV path\n");
5311 return rtt1;
5312 }
5313 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5314 "encapsulate_for_dv 1\n");
5315 rtt2 = encapsulate_for_dv (dv,
5316 res,
5317 hops,
5318 hdr,
5319 &send_dv_to_neighbour,
5320 NULL,
5321 options & (~RMO_REDUNDANT),
5322 GNUNET_YES);
5323 }
5324 return GNUNET_TIME_relative_min (rtt1, rtt2);
5325}
5326
5327
5328static void
5329consider_sending_fc (void *cls);
5330
5331/**
5332 * Something changed on the virtual link with respect to flow
5333 * control. Consider retransmitting the FC window size.
5334 *
5335 * @param cls a `struct VirtualLink` to work with
5336 */
5337static void
5338task_consider_sending_fc (void *cls)
5339{
5340 struct VirtualLink *vl = cls;
5341 vl->fc_retransmit_task = NULL;
5342 consider_sending_fc (cls);
5343}
5344
5345
5346static char *
5347get_address_without_port (const char *address);
5348
5349
5350struct AddGlobalAddressesContext
5351{
5352 size_t off;
5353 char *tgnas;
5354};
5355
5356
5357static enum GNUNET_GenericReturnValue
5358add_global_addresses (void *cls,
5359 const struct GNUNET_PeerIdentity *pid,
5360 void *value)
5361{
5362 struct AddGlobalAddressesContext *ctx = cls;
5363 struct TransportGlobalNattedAddress *tgna = value;
5364 char *addr = (char *) &tgna[1];
5365 size_t address_len = strlen (addr);
5366
5367 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5368 "sending address %s length %lu\n",
5369 addr,
5370 address_len);
5371 tgna = GNUNET_malloc (sizeof (struct TransportGlobalNattedAddress) + address_len);
5372 tgna->address_length = htonl (address_len);
5373 GNUNET_memcpy (&tgna[1], addr, address_len);
5374 GNUNET_memcpy (&(ctx->tgnas[ctx->off]), tgna, sizeof (struct TransportGlobalNattedAddress) + address_len);
5375 GNUNET_free (tgna);
5376 ctx->off += sizeof(struct TransportGlobalNattedAddress) + address_len;
5377
5378 return GNUNET_OK;
5379}
5380
5381
5382/**
5383 * Something changed on the virtual link with respect to flow
5384 * control. Consider retransmitting the FC window size.
5385 *
5386 * @param cls a `struct VirtualLink` to work with
5387 */
5388static void
5389consider_sending_fc (void *cls)
5390{
5391 struct VirtualLink *vl = cls;
5392 struct GNUNET_TIME_Absolute monotime;
5393 struct TransportFlowControlMessage *fc;
5394 struct GNUNET_TIME_Relative duration;
5395 struct GNUNET_TIME_Relative rtt;
5396 struct Neighbour *n = vl->n;
5397
5398 if (0 < n->number_of_addresses)
5399 {
5400 size_t addresses_size =
5401 n->number_of_addresses * sizeof (struct TransportGlobalNattedAddress) + n->size_of_global_addresses;
5402 char *tgnas = GNUNET_malloc (addresses_size);
5403 struct AddGlobalAddressesContext ctx;
5404 ctx.off = 0;
5405 ctx.tgnas = tgnas;
5406
5407 fc = GNUNET_malloc (sizeof (struct TransportFlowControlMessage) + addresses_size);
5408 fc->header.size = htons (sizeof(struct TransportFlowControlMessage) + addresses_size);
5409 fc->size_of_addresses = htonl (n->size_of_global_addresses);
5410 fc->number_of_addresses = htonl (n->number_of_addresses);
5411 GNUNET_CONTAINER_multipeermap_iterate (n->natted_addresses,
5412 &add_global_addresses,
5413 &ctx);
5414 GNUNET_memcpy (&fc[1], tgnas, addresses_size);
5415 GNUNET_free (tgnas);
5416 }
5417 else
5418 {
5419 fc = GNUNET_malloc (sizeof (struct TransportFlowControlMessage));
5420 fc->header.size = htons (sizeof(struct TransportFlowControlMessage));
5421 }
5422
5423 duration = GNUNET_TIME_absolute_get_duration (vl->last_fc_transmission);
5424 /* OPTIMIZE-FC-BDP: decide sane criteria on when to do this, instead of doing
5425 it always! */
5426 /* For example, we should probably ONLY do this if a bit more than
5427 an RTT has passed, or if the window changed "significantly" since
5428 then. See vl->last_fc_rtt! NOTE: to do this properly, we also
5429 need an estimate for the bandwidth-delay-product for the entire
5430 VL, as that determines "significantly". We have the delay, but
5431 the bandwidth statistics need to be added for the VL!*/(void) duration;
5432
5433 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5434 "Sending FC seq %u to %s with new window %llu\n",
5435 (unsigned int) vl->fc_seq_gen,
5436 GNUNET_i2s (&vl->target),
5437 (unsigned long long) vl->incoming_fc_window_size);
5438 monotime = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
5439 vl->last_fc_transmission = monotime;
5440 fc->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL);
5441 fc->seq = htonl (vl->fc_seq_gen++);
5442 fc->inbound_window_size = GNUNET_htonll (vl->incoming_fc_window_size
5443 + vl->incoming_fc_window_size_used
5444 + vl->incoming_fc_window_size_loss);
5445 fc->outbound_sent = GNUNET_htonll (vl->outbound_fc_window_size_used);
5446 fc->outbound_window_size = GNUNET_htonll (vl->outbound_fc_window_size);
5447 fc->sender_time = GNUNET_TIME_absolute_hton (monotime);
5448 rtt = route_control_message_without_fc (vl, &fc->header, RMO_DV_ALLOWED);
5449 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us == rtt.rel_value_us)
5450 {
5451 rtt = GNUNET_TIME_UNIT_SECONDS;
5452 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5453 "FC retransmission to %s failed, will retry in %s\n",
5454 GNUNET_i2s (&vl->target),
5455 GNUNET_STRINGS_relative_time_to_string (rtt, GNUNET_YES));
5456 vl->last_fc_rtt = GNUNET_TIME_UNIT_ZERO;
5457 }
5458 else
5459 {
5460 /* OPTIMIZE-FC-BDP: rtt is not ideal, we can do better! */
5461 vl->last_fc_rtt = rtt;
5462 }
5463 if (NULL != vl->fc_retransmit_task)
5464 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
5465 if (MAX_FC_RETRANSMIT_COUNT == vl->fc_retransmit_count)
5466 {
5467 rtt = GNUNET_TIME_UNIT_MINUTES;
5468 vl->fc_retransmit_count = 0;
5469 }
5470 vl->fc_retransmit_task =
5471 GNUNET_SCHEDULER_add_delayed (rtt, &task_consider_sending_fc, vl);
5472 vl->fc_retransmit_count++;
5473 GNUNET_free (fc);
5474}
5475
5476
5477/**
5478 * There is a message at the head of the pending messages for @a vl
5479 * which may be ready for transmission. Check if a queue is ready to
5480 * take it.
5481 *
5482 * This function must (1) check for flow control to ensure that we can
5483 * right now send to @a vl, (2) check that the pending message in the
5484 * queue is actually eligible, (3) determine if any applicable queue
5485 * (direct neighbour or DVH path) is ready to accept messages, and
5486 * (4) prioritize based on the preferences associated with the
5487 * pending message.
5488 *
5489 * So yeah, easy.
5490 *
5491 * @param vl virtual link where we should check for transmission
5492 */
5493static void
5494check_vl_transmission (struct VirtualLink *vl)
5495{
5496 struct Neighbour *n = vl->n;
5497 struct DistanceVector *dv = vl->dv;
5498 struct GNUNET_TIME_Absolute now;
5499 struct VirtualLink *vl_next_hop;
5500 int elig;
5501
5502 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5503 "check_vl_transmission to target %s\n",
5504 GNUNET_i2s (&vl->target));
5505 /* Check that we have an eligible pending message!
5506 (cheaper than having #transmit_on_queue() find out!) */
5507 elig = GNUNET_NO;
5508 for (struct PendingMessage *pm = vl->pending_msg_head; NULL != pm;
5509 pm = pm->next_vl)
5510 {
5511 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5512 "check_vl_transmission loop\n");
5513 if (NULL != pm->qe)
5514 continue; /* not eligible, is in a queue! */
5515 if (pm->bytes_msg + vl->outbound_fc_window_size_used >
5516 vl->outbound_fc_window_size)
5517 {
5518 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5519 "Stalled message %" PRIu64
5520 " transmission on VL %s due to flow control: %llu < %llu\n",
5521 pm->logging_uuid,
5522 GNUNET_i2s (&vl->target),
5523 (unsigned long long) vl->outbound_fc_window_size,
5524 (unsigned long long) (pm->bytes_msg
5525 + vl->outbound_fc_window_size_used));
5526 consider_sending_fc (vl);
5527 return; /* We have a message, but flow control says "nope" */
5528 }
5529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5530 "Target window on VL %s not stalled. Scheduling transmission on queue\n",
5531 GNUNET_i2s (&vl->target));
5532 /* Notify queues at direct neighbours that we are interested */
5533 now = GNUNET_TIME_absolute_get ();
5534 if (NULL != n)
5535 {
5536 for (struct Queue *queue = n->queue_head; NULL != queue;
5537 queue = queue->next_neighbour)
5538 {
5539 if ((GNUNET_YES == queue->idle) &&
5540 (queue->validated_until.abs_value_us > now.abs_value_us))
5541 {
5542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5543 "Direct neighbour %s not stalled\n",
5544 GNUNET_i2s (&n->pid));
5545 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5546 queue,
5547 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
5548 elig = GNUNET_YES;
5549 }
5550 else
5551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5552 "Neighbour Queue QID: %u (%u) busy or invalid\n",
5553 queue->qid,
5554 queue->idle);
5555 }
5556 }
5557 /* Notify queues via DV that we are interested */
5558 if (NULL != dv)
5559 {
5560 /* Do DV with lower scheduler priority, which effectively means that
5561 IF a neighbour exists and is available, we prefer it. */
5562 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
5563 pos = pos->next_dv)
5564 {
5565 struct Neighbour *nh = pos->next_hop;
5566
5567
5568 if (pos->path_valid_until.abs_value_us <= now.abs_value_us)
5569 continue; /* skip this one: path not validated */
5570 else
5571 {
5572 vl_next_hop = lookup_virtual_link (&nh->pid);
5573 GNUNET_assert (NULL != vl_next_hop);
5574 if (pm->bytes_msg + vl_next_hop->outbound_fc_window_size_used >
5575 vl_next_hop->outbound_fc_window_size)
5576 {
5577 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5578 "Stalled message %" PRIu64
5579 " transmission on next hop %s due to flow control: %llu < %llu\n",
5580 pm->logging_uuid,
5581 GNUNET_i2s (&vl_next_hop->target),
5582 (unsigned long
5583 long) vl_next_hop->outbound_fc_window_size,
5584 (unsigned long long) (pm->bytes_msg
5585 + vl_next_hop->
5586 outbound_fc_window_size_used));
5587 consider_sending_fc (vl_next_hop);
5588 continue; /* We have a message, but flow control says "nope" for the first hop of this path */
5589 }
5590 for (struct Queue *queue = nh->queue_head; NULL != queue;
5591 queue = queue->next_neighbour)
5592 if ((GNUNET_YES == queue->idle) &&
5593 (queue->validated_until.abs_value_us > now.abs_value_us))
5594 {
5595 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5596 "Next hop neighbour %s not stalled\n",
5597 GNUNET_i2s (&nh->pid));
5598 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
5599 queue,
5600 GNUNET_SCHEDULER_PRIORITY_BACKGROUND);
5601 elig = GNUNET_YES;
5602 }
5603 else
5604 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5605 "DV Queue QID: %u (%u) busy or invalid\n",
5606 queue->qid,
5607 queue->idle);
5608 }
5609 }
5610 }
5611 if (GNUNET_YES == elig)
5612 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5613 "Eligible message %" PRIu64 " of size %u to %s: %llu/%llu\n",
5614 pm->logging_uuid,
5615 pm->bytes_msg,
5616 GNUNET_i2s (&vl->target),
5617 (unsigned long long) vl->outbound_fc_window_size,
5618 (unsigned long long) (pm->bytes_msg
5619 + vl->outbound_fc_window_size_used));
5620 break;
5621 }
5622}
5623
5624
5625/**
5626 * Client asked for transmission to a peer. Process the request.
5627 *
5628 * @param cls the client
5629 * @param obm the send message that was sent
5630 */
5631static void
5632handle_client_send (void *cls, const struct OutboundMessage *obm)
5633{
5634 struct TransportClient *tc = cls;
5635 struct PendingMessage *pm;
5636 const struct GNUNET_MessageHeader *obmm;
5637 uint32_t bytes_msg;
5638 struct VirtualLink *vl;
5639 enum GNUNET_MQ_PriorityPreferences pp;
5640
5641 GNUNET_assert (CT_CORE == tc->type);
5642 obmm = (const struct GNUNET_MessageHeader *) &obm[1];
5643 bytes_msg = ntohs (obmm->size);
5644 pp = (enum GNUNET_MQ_PriorityPreferences) ntohl (obm->priority);
5645 vl = lookup_virtual_link (&obm->peer);
5646 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
5647 {
5648 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5649 "Don't have %s as a neighbour (anymore).\n",
5650 GNUNET_i2s (&obm->peer));
5651 /* Failure: don't have this peer as a neighbour (anymore).
5652 Might have gone down asynchronously, so this is NOT
5653 a protocol violation by CORE. Still count the event,
5654 as this should be rare. */
5655 GNUNET_SERVICE_client_continue (tc->client);
5656 GNUNET_STATISTICS_update (GST_stats,
5657 "# messages dropped (neighbour unknown)",
5658 1,
5659 GNUNET_NO);
5660 return;
5661 }
5662
5663 pm = GNUNET_malloc (sizeof(struct PendingMessage) + bytes_msg);
5664 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5665 "1 created pm %p storing vl %p\n",
5666 pm,
5667 vl);
5668 pm->logging_uuid = logging_uuid_gen++;
5669 pm->prefs = pp;
5670 pm->client = tc;
5671 pm->vl = vl;
5672 pm->bytes_msg = bytes_msg;
5673 memcpy (&pm[1], obmm, bytes_msg);
5674 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5675 "Sending message of type %u with %u bytes as <%" PRIu64
5676 "> to %s\n",
5677 ntohs (obmm->type),
5678 bytes_msg,
5679 pm->logging_uuid,
5680 GNUNET_i2s (&obm->peer));
5681 GNUNET_CONTAINER_MDLL_insert (client,
5682 tc->details.core.pending_msg_head,
5683 tc->details.core.pending_msg_tail,
5684 pm);
5685 GNUNET_CONTAINER_MDLL_insert (vl,
5686 vl->pending_msg_head,
5687 vl->pending_msg_tail,
5688 pm);
5689 check_vl_transmission (vl);
5690 GNUNET_SERVICE_client_continue (tc->client);
5691}
5692
5693
5694/**
5695 * Communicator requests backchannel transmission. Process the request.
5696 * Just repacks it into our `struct TransportBackchannelEncapsulationMessage *`
5697 * (which for now has exactly the same format, only a different message type)
5698 * and passes it on for routing.
5699 *
5700 * @param cls the client
5701 * @param cb the send message that was sent
5702 */
5703static void
5704handle_communicator_backchannel (
5705 void *cls,
5706 const struct GNUNET_TRANSPORT_CommunicatorBackchannel *cb)
5707{
5708 struct Neighbour *n;
5709 struct VirtualLink *vl;
5710 struct TransportClient *tc = cls;
5711 const struct GNUNET_MessageHeader *inbox =
5712 (const struct GNUNET_MessageHeader *) &cb[1];
5713 uint16_t isize = ntohs (inbox->size);
5714 const char *is = ((const char *) &cb[1]) + isize;
5715 size_t slen = strlen (is) + 1;
5716 char
5717 mbuf[slen + isize
5718 + sizeof(struct
5719 TransportBackchannelEncapsulationMessage)] GNUNET_ALIGN;
5720 struct TransportBackchannelEncapsulationMessage *be =
5721 (struct TransportBackchannelEncapsulationMessage *) mbuf;
5722
5723 /* 0-termination of 'is' was checked already in
5724 #check_communicator_backchannel() */
5725 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5726 "Preparing backchannel transmission to %s:%s of type %u and size %u\n",
5727 GNUNET_i2s (&cb->pid),
5728 is,
5729 ntohs (inbox->type),
5730 ntohs (inbox->size));
5731 /* encapsulate and encrypt message */
5732 be->header.type =
5733 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION);
5734 be->header.size = htons (sizeof(mbuf));
5735 memcpy (&be[1], inbox, isize);
5736 memcpy (&mbuf[sizeof(struct TransportBackchannelEncapsulationMessage)
5737 + isize],
5738 is,
5739 strlen (is) + 1);
5740 // route_control_message_without_fc (&cb->pid, &be->header, RMO_DV_ALLOWED);
5741 vl = lookup_virtual_link (&cb->pid);
5742 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
5743 {
5744 route_control_message_without_fc (vl, &be->header, RMO_DV_ALLOWED);
5745 }
5746 else
5747 {
5748 /* Use route via neighbour */
5749 n = lookup_neighbour (&cb->pid);
5750 if (NULL != n)
5751 route_via_neighbour (
5752 n,
5753 &be->header,
5754 RMO_NONE);
5755 }
5756 GNUNET_SERVICE_client_continue (tc->client);
5757}
5758
5759
5760/**
5761 * Address of our peer added. Test message is well-formed.
5762 *
5763 * @param cls the client
5764 * @param aam the send message that was sent
5765 * @return #GNUNET_OK if message is well-formed
5766 */
5767static int
5768check_add_address (void *cls,
5769 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5770{
5771 struct TransportClient *tc = cls;
5772
5773 if (CT_COMMUNICATOR != tc->type)
5774 {
5775 GNUNET_break (0);
5776 return GNUNET_SYSERR;
5777 }
5778 GNUNET_MQ_check_zero_termination (aam);
5779 return GNUNET_OK;
5780}
5781
5782
5783/**
5784 * Ask peerstore to store our address.
5785 *
5786 * @param cls an `struct AddressListEntry *`
5787 */
5788static void
5789store_pi (void *cls);
5790
5791
5792/**
5793 * Function called when peerstore is done storing our address.
5794 *
5795 * @param cls a `struct AddressListEntry`
5796 * @param success #GNUNET_YES if peerstore was successful
5797 */
5798static void
5799peerstore_store_own_cb (void *cls, int success)
5800{
5801 struct AddressListEntry *ale = cls;
5802
5803 ale->sc = NULL;
5804 if (GNUNET_YES != success)
5805 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
5806 "Failed to store our own address `%s' in peerstore!\n",
5807 ale->address);
5808 else
5809 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5810 "Successfully stored our own address `%s' in peerstore!\n",
5811 ale->address);
5812 /* refresh period is 1/4 of expiration time, that should be plenty
5813 without being excessive. */
5814 ale->st =
5815 GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (ale->expiration,
5816 4ULL),
5817 &store_pi,
5818 ale);
5819}
5820
5821
5822static void
5823shc_cont (void *cls, int success)
5824{
5825 struct AddressListEntry *ale = cls;
5826 struct GNUNET_TIME_Absolute expiration;
5827
5828 expiration = GNUNET_TIME_relative_to_absolute (ale->expiration);
5829 ale->sc = GNUNET_PEERSTORE_store (peerstore,
5830 "transport",
5831 &GST_my_identity,
5832 GNUNET_PEERSTORE_TRANSPORT_HELLO_KEY,
5833 ale->signed_address,
5834 ale->signed_address_len,
5835 expiration,
5836 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
5837 &peerstore_store_own_cb,
5838 ale);
5839 if (NULL == ale->sc)
5840 {
5841 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5842 "Failed to store our address `%s' with peerstore\n",
5843 ale->address);
5844 ale->st = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS,
5845 &store_pi,
5846 ale);
5847 }
5848}
5849
5850
5851/**
5852 * Ask peerstore to store our address.
5853 *
5854 * @param cls an `struct AddressListEntry *`
5855 */
5856static void
5857store_pi (void *cls)
5858{
5859 struct AddressListEntry *ale = cls;
5860 struct GNUNET_MQ_Envelope *env;
5861 const struct GNUNET_MessageHeader *msg;
5862 const char *dash;
5863 char *address_uri;
5864 char *prefix = GNUNET_HELLO_address_to_prefix (ale->address);
5865 unsigned int add_success;
5866
5867 dash = strchr (ale->address, '-');
5868 GNUNET_assert (NULL != dash);
5869 dash++;
5870 GNUNET_asprintf (&address_uri,
5871 "%s://%s",
5872 prefix,
5873 dash);
5874 GNUNET_free (prefix);
5875 ale->st = NULL;
5876 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5877 "Storing our address `%s' in peerstore until %s!\n",
5878 ale->address,
5879 GNUNET_STRINGS_absolute_time_to_string (hello_mono_time));
5880 add_success = GNUNET_HELLO_builder_add_address (GST_my_hello,
5881 address_uri);
5882 if (GNUNET_OK != add_success)
5883 {
5884 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5885 "Storing our address `%s' %s\n",
5886 address_uri,
5887 GNUNET_NO == add_success ? "not done" : "failed");
5888 GNUNET_free (address_uri);
5889 return;
5890 }
5891 else
5892 {
5893
5894 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
5895 "Storing our address `%s'\n",
5896 address_uri);
5897 }
5898 // FIXME hello_mono_time used here?? What about expiration in ale?
5899 GNUNET_HELLO_sign_address (ale->address,
5900 ale->nt,
5901 hello_mono_time,
5902 GST_my_private_key,
5903 &ale->signed_address,
5904 &ale->signed_address_len);
5905 GNUNET_free (address_uri);
5906 env = GNUNET_HELLO_builder_to_env (GST_my_hello,
5907 GST_my_private_key,
5908 GNUNET_TIME_UNIT_ZERO);
5909 msg = GNUNET_MQ_env_get_msg (env);
5910 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5911 "store_pi 1\n");
5912 ale->shc = GNUNET_PEERSTORE_hello_add (peerstore,
5913 msg,
5914 shc_cont,
5915 ale);
5916 GNUNET_free (env);
5917}
5918
5919
5920static struct AddressListEntry *
5921create_address_entry (struct TransportClient *tc,
5922 struct GNUNET_TIME_Relative expiration,
5923 enum GNUNET_NetworkType nt,
5924 const char *address,
5925 uint32_t aid,
5926 size_t slen)
5927{
5928 struct AddressListEntry *ale;
5929
5930 ale = GNUNET_malloc (sizeof(struct AddressListEntry) + slen);
5931 ale->tc = tc;
5932 ale->address = (const char *) &ale[1];
5933 ale->expiration = expiration;
5934 ale->aid = aid;
5935 ale->nt = nt;
5936 memcpy (&ale[1], address, slen);
5937 ale->st = GNUNET_SCHEDULER_add_now (&store_pi, ale);
5938
5939 return ale;
5940}
5941
5942
5943/**
5944 * Address of our peer added. Process the request.
5945 *
5946 * @param cls the client
5947 * @param aam the send message that was sent
5948 */
5949static void
5950handle_add_address (void *cls,
5951 const struct GNUNET_TRANSPORT_AddAddressMessage *aam)
5952{
5953 struct TransportClient *tc = cls;
5954 struct AddressListEntry *ale;
5955 size_t slen;
5956
5957 /* 0-termination of &aam[1] was checked in #check_add_address */
5958 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
5959 "Communicator added address `%s'!\n",
5960 (const char *) &aam[1]);
5961 slen = ntohs (aam->header.size) - sizeof(*aam);
5962 ale = create_address_entry (tc,
5963 GNUNET_TIME_relative_ntoh (aam->expiration),
5964 (enum GNUNET_NetworkType) ntohl (aam->nt),
5965 (const char *) &aam[1],
5966 aam->aid,
5967 slen);
5968 GNUNET_CONTAINER_DLL_insert (tc->details.communicator.addr_head,
5969 tc->details.communicator.addr_tail,
5970 ale);
5971 GNUNET_SERVICE_client_continue (tc->client);
5972}
5973
5974
5975/**
5976 * Address of our peer deleted. Process the request.
5977 *
5978 * @param cls the client
5979 * @param dam the send message that was sent
5980 */
5981static void
5982handle_del_address (void *cls,
5983 const struct GNUNET_TRANSPORT_DelAddressMessage *dam)
5984{
5985 struct TransportClient *tc = cls;
5986 struct AddressListEntry *alen;
5987
5988 if (CT_COMMUNICATOR != tc->type)
5989 {
5990 GNUNET_break (0);
5991 GNUNET_SERVICE_client_drop (tc->client);
5992 return;
5993 }
5994 for (struct AddressListEntry *ale = tc->details.communicator.addr_head;
5995 NULL != ale;
5996 ale = alen)
5997 {
5998 alen = ale->next;
5999 if (dam->aid != ale->aid)
6000 continue;
6001 GNUNET_assert (ale->tc == tc);
6002 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6003 "Communicator deleted address `%s'!\n",
6004 ale->address);
6005 free_address_list_entry (ale);
6006 GNUNET_SERVICE_client_continue (tc->client);
6007 return;
6008 }
6009 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
6010 "Communicator removed address we did not even have.\n");
6011 GNUNET_SERVICE_client_continue (tc->client);
6012 // GNUNET_SERVICE_client_drop (tc->client);
6013}
6014
6015
6016/**
6017 * Given an inbound message @a msg from a communicator @a cmc,
6018 * demultiplex it based on the type calling the right handler.
6019 *
6020 * @param cmc context for demultiplexing
6021 * @param msg message to demultiplex
6022 */
6023static void
6024demultiplex_with_cmc (struct CommunicatorMessageContext *cmc);
6025
6026
6027/**
6028 * Function called when we are done giving a message of a certain
6029 * size to CORE and should thus decrement the number of bytes of
6030 * RAM reserved for that peer's MQ.
6031 *
6032 * @param cls a `struct CoreSentContext`
6033 */
6034static void
6035core_env_sent_cb (void *cls)
6036{
6037 struct CoreSentContext *ctx = cls;
6038 struct VirtualLink *vl = ctx->vl;
6039
6040 if (NULL == vl)
6041 {
6042 /* lost the link in the meantime, ignore */
6043 GNUNET_free (ctx);
6044 return;
6045 }
6046 GNUNET_CONTAINER_DLL_remove (vl->csc_head, vl->csc_tail, ctx);
6047 GNUNET_assert (vl->incoming_fc_window_size_ram >= ctx->size);
6048 vl->incoming_fc_window_size_ram -= ctx->size;
6049 vl->incoming_fc_window_size_used += ctx->isize;
6050 consider_sending_fc (vl);
6051 GNUNET_free (ctx);
6052}
6053
6054
6055static void
6056finish_handling_raw_message (struct VirtualLink *vl,
6057 const struct GNUNET_MessageHeader *mh,
6058 struct CommunicatorMessageContext *cmc,
6059 unsigned int free_cmc)
6060{
6061 uint16_t size = ntohs (mh->size);
6062 int have_core;
6063
6064 if (vl->incoming_fc_window_size_ram > UINT_MAX - size)
6065 {
6066 GNUNET_STATISTICS_update (GST_stats,
6067 "# CORE messages dropped (FC arithmetic overflow)",
6068 1,
6069 GNUNET_NO);
6070 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6071 "CORE messages of type %u with %u bytes dropped (FC arithmetic overflow)\n",
6072 (unsigned int) ntohs (mh->type),
6073 (unsigned int) ntohs (mh->size));
6074 if (GNUNET_YES == free_cmc)
6075 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
6076 return;
6077 }
6078 if (vl->incoming_fc_window_size_ram + size > vl->available_fc_window_size)
6079 {
6080 GNUNET_STATISTICS_update (GST_stats,
6081 "# CORE messages dropped (FC window overflow)",
6082 1,
6083 GNUNET_NO);
6084 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6085 "CORE messages of type %u with %u bytes dropped (FC window overflow)\n",
6086 (unsigned int) ntohs (mh->type),
6087 (unsigned int) ntohs (mh->size));
6088 if (GNUNET_YES == free_cmc)
6089 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
6090 return;
6091 }
6092
6093 /* Forward to all CORE clients */
6094 have_core = GNUNET_NO;
6095 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
6096 {
6097 struct GNUNET_MQ_Envelope *env;
6098 struct InboundMessage *im;
6099 struct CoreSentContext *ctx;
6100
6101 if (CT_CORE != tc->type)
6102 continue;
6103 vl->incoming_fc_window_size_ram += size;
6104 env = GNUNET_MQ_msg_extra (im, size, GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
6105 ctx = GNUNET_new (struct CoreSentContext);
6106 ctx->vl = vl;
6107 ctx->size = size;
6108 ctx->isize = (GNUNET_NO == have_core) ? size : 0;
6109 have_core = GNUNET_YES;
6110 GNUNET_CONTAINER_DLL_insert (vl->csc_head, vl->csc_tail, ctx);
6111 GNUNET_MQ_notify_sent (env, &core_env_sent_cb, ctx);
6112 im->peer = cmc->im.sender;
6113 memcpy (&im[1], mh, size);
6114 GNUNET_MQ_send (tc->mq, env);
6115 vl->core_recv_window--;
6116 }
6117 if (GNUNET_NO == have_core)
6118 {
6119 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
6120 "Dropped message to CORE: no CORE client connected!\n");
6121 /* Nevertheless, count window as used, as it is from the
6122 perspective of the other peer! */
6123 vl->incoming_fc_window_size_used += size;
6124 /* TODO-M1 */
6125 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6126 "Dropped message of type %u with %u bytes to CORE: no CORE client connected!\n",
6127 (unsigned int) ntohs (mh->type),
6128 (unsigned int) ntohs (mh->size));
6129 if (GNUNET_YES == free_cmc)
6130 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
6131 return;
6132 }
6133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6134 "Delivered message from %s of type %u to CORE recv window %d\n",
6135 GNUNET_i2s (&cmc->im.sender),
6136 ntohs (mh->type),
6137 vl->core_recv_window);
6138 if (vl->core_recv_window > 0)
6139 {
6140 if (GNUNET_YES == free_cmc)
6141 finish_cmc_handling_with_continue (cmc, GNUNET_YES);
6142 return;
6143 }
6144 /* Wait with calling #finish_cmc_handling(cmc) until the message
6145 was processed by CORE MQs (for CORE flow control)! */
6146 if (GNUNET_YES == free_cmc)
6147 GNUNET_CONTAINER_DLL_insert (vl->cmc_head, vl->cmc_tail, cmc);
6148}
6149
6150
6151/**
6152 * Communicator gave us an unencapsulated message to pass as-is to
6153 * CORE. Process the request.
6154 *
6155 * @param cls a `struct CommunicatorMessageContext` (must call
6156 * #finish_cmc_handling() when done)
6157 * @param mh the message that was received
6158 */
6159static void
6160handle_raw_message (void *cls, const struct GNUNET_MessageHeader *mh)
6161{
6162 struct CommunicatorMessageContext *cmc = cls;
6163 // struct CommunicatorMessageContext *cmc_copy =
6164 // GNUNET_new (struct CommunicatorMessageContext);
6165 struct GNUNET_MessageHeader *mh_copy;
6166 struct RingBufferEntry *rbe;
6167 struct VirtualLink *vl;
6168 uint16_t size = ntohs (mh->size);
6169
6170 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6171 "Handling raw message of type %u with %u bytes\n",
6172 (unsigned int) ntohs (mh->type),
6173 (unsigned int) ntohs (mh->size));
6174
6175 if ((size > UINT16_MAX - sizeof(struct InboundMessage)) ||
6176 (size < sizeof(struct GNUNET_MessageHeader)))
6177 {
6178 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
6179
6180 GNUNET_break (0);
6181 finish_cmc_handling (cmc);
6182 GNUNET_SERVICE_client_drop (client);
6183 return;
6184 }
6185 vl = lookup_virtual_link (&cmc->im.sender);
6186 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6187 {
6188 /* FIXME: sender is giving us messages for CORE but we don't have
6189 the link up yet! I *suspect* this can happen right now (i.e.
6190 sender has verified us, but we didn't verify sender), but if
6191 we pass this on, CORE would be confused (link down, messages
6192 arrive). We should investigate more if this happens often,
6193 or in a persistent manner, and possibly do "something" about
6194 it. Thus logging as error for now. */
6195
6196 mh_copy = GNUNET_malloc (size);
6197 rbe = GNUNET_new (struct RingBufferEntry);
6198 rbe->cmc = cmc;
6199 /*cmc_copy->tc = cmc->tc;
6200 cmc_copy->im = cmc->im;*/
6201 GNUNET_memcpy (mh_copy, mh, size);
6202
6203 rbe->mh = mh_copy;
6204
6205 if (GNUNET_YES == is_ring_buffer_full)
6206 {
6207 struct RingBufferEntry *rbe_old = ring_buffer[ring_buffer_head];
6208 GNUNET_free (rbe_old->cmc);
6209 GNUNET_free (rbe_old->mh);
6210 GNUNET_free (rbe_old);
6211 }
6212 ring_buffer[ring_buffer_head] = rbe;// cmc_copy;
6213 // cmc_copy->mh = (const struct GNUNET_MessageHeader *) mh_copy;
6214 cmc->mh = (const struct GNUNET_MessageHeader *) mh_copy;
6215 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6216 "Storing message for %s and type %u (%u) in ring buffer head %u is full %u\n",
6217 GNUNET_i2s (&cmc->im.sender),
6218 (unsigned int) ntohs (mh->type),
6219 (unsigned int) ntohs (mh_copy->type),
6220 ring_buffer_head,
6221 is_ring_buffer_full);
6222 if (RING_BUFFER_SIZE - 1 == ring_buffer_head)
6223 {
6224 ring_buffer_head = 0;
6225 is_ring_buffer_full = GNUNET_YES;
6226 }
6227 else
6228 ring_buffer_head++;
6229
6230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6231 "%u items stored in ring buffer\n",
6232 GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
6233 ring_buffer_head);
6234
6235 /*GNUNET_break_op (0);
6236 GNUNET_STATISTICS_update (GST_stats,
6237 "# CORE messages dropped (virtual link still down)",
6238 1,
6239 GNUNET_NO);
6240
6241 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6242 "CORE messages of type %u with %u bytes dropped (virtual link still down)\n",
6243 (unsigned int) ntohs (mh->type),
6244 (unsigned int) ntohs (mh->size));
6245 finish_cmc_handling (cmc);*/
6246 finish_cmc_handling_with_continue (cmc, GNUNET_NO);
6247 cmc->continue_send = GNUNET_YES;
6248 // GNUNET_free (cmc);
6249 return;
6250 }
6251 finish_handling_raw_message (vl, mh, cmc, GNUNET_YES);
6252}
6253
6254
6255/**
6256 * Communicator gave us a fragment box. Check the message.
6257 *
6258 * @param cls a `struct CommunicatorMessageContext`
6259 * @param fb the send message that was sent
6260 * @return #GNUNET_YES if message is well-formed
6261 */
6262static int
6263check_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
6264{
6265 uint16_t size = ntohs (fb->header.size);
6266 uint16_t bsize = size - sizeof(*fb);
6267
6268 (void) cls;
6269 if (0 == bsize)
6270 {
6271 GNUNET_break_op (0);
6272 return GNUNET_SYSERR;
6273 }
6274 if (bsize + ntohs (fb->frag_off) > ntohs (fb->msg_size))
6275 {
6276 GNUNET_break_op (0);
6277 return GNUNET_SYSERR;
6278 }
6279 if (ntohs (fb->frag_off) >= ntohs (fb->msg_size))
6280 {
6281 GNUNET_break_op (0);
6282 return GNUNET_SYSERR;
6283 }
6284 return GNUNET_YES;
6285}
6286
6287
6288/**
6289 * Clean up an idle cumulative acknowledgement data structure.
6290 *
6291 * @param cls a `struct AcknowledgementCummulator *`
6292 */
6293static void
6294destroy_ack_cummulator (void *cls)
6295{
6296 struct AcknowledgementCummulator *ac = cls;
6297
6298 ac->task = NULL;
6299 GNUNET_assert (0 == ac->num_acks);
6300 GNUNET_assert (
6301 GNUNET_YES ==
6302 GNUNET_CONTAINER_multipeermap_remove (ack_cummulators, &ac->target, ac));
6303 GNUNET_free (ac);
6304}
6305
6306
6307/**
6308 * Do the transmission of a cumulative acknowledgement now.
6309 *
6310 * @param cls a `struct AcknowledgementCummulator *`
6311 */
6312static void
6313transmit_cummulative_ack_cb (void *cls)
6314{
6315 struct Neighbour *n;
6316 struct VirtualLink *vl;
6317 struct AcknowledgementCummulator *ac = cls;
6318 char buf[sizeof(struct TransportReliabilityAckMessage)
6319 + ac->num_acks
6320 * sizeof(struct TransportCummulativeAckPayloadP)] GNUNET_ALIGN;
6321 struct TransportReliabilityAckMessage *ack =
6322 (struct TransportReliabilityAckMessage *) buf;
6323 struct TransportCummulativeAckPayloadP *ap;
6324
6325 ac->task = NULL;
6326 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6327 "Sending ACK with %u components to %s\n",
6328 ac->num_acks,
6329 GNUNET_i2s (&ac->target));
6330 GNUNET_assert (0 < ac->num_acks);
6331 ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK);
6332 ack->header.size =
6333 htons (sizeof(*ack)
6334 + ac->num_acks * sizeof(struct TransportCummulativeAckPayloadP));
6335 ack->ack_counter = htonl (ac->ack_counter += ac->num_acks);
6336 ap = (struct TransportCummulativeAckPayloadP *) &ack[1];
6337 for (unsigned int i = 0; i < ac->num_acks; i++)
6338 {
6339 ap[i].ack_uuid = ac->ack_uuids[i].ack_uuid;
6340 ap[i].ack_delay = GNUNET_TIME_relative_hton (
6341 GNUNET_TIME_absolute_get_duration (ac->ack_uuids[i].receive_time));
6342 }
6343 /*route_control_message_without_fc (
6344 &ac->target,
6345 &ack->header,
6346 RMO_DV_ALLOWED);*/
6347 vl = lookup_virtual_link (&ac->target);
6348 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
6349 {
6350 route_control_message_without_fc (
6351 vl,
6352 &ack->header,
6353 RMO_DV_ALLOWED);
6354 }
6355 else
6356 {
6357 /* Use route via neighbour */
6358 n = lookup_neighbour (&ac->target);
6359 if (NULL != n)
6360 route_via_neighbour (
6361 n,
6362 &ack->header,
6363 RMO_NONE);
6364 }
6365 ac->num_acks = 0;
6366 ac->task = GNUNET_SCHEDULER_add_delayed (ACK_CUMMULATOR_TIMEOUT,
6367 &destroy_ack_cummulator,
6368 ac);
6369}
6370
6371
6372/**
6373 * Transmit an acknowledgement for @a ack_uuid to @a pid delaying
6374 * transmission by at most @a ack_delay.
6375 *
6376 * @param pid target peer
6377 * @param ack_uuid UUID to ack
6378 * @param max_delay how long can the ACK wait
6379 */
6380static void
6381cummulative_ack (const struct GNUNET_PeerIdentity *pid,
6382 const struct AcknowledgementUUIDP *ack_uuid,
6383 struct GNUNET_TIME_Absolute max_delay)
6384{
6385 struct AcknowledgementCummulator *ac;
6386
6387 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6388 "Scheduling ACK %s for transmission to %s\n",
6389 GNUNET_uuid2s (&ack_uuid->value),
6390 GNUNET_i2s (pid));
6391 ac = GNUNET_CONTAINER_multipeermap_get (ack_cummulators, pid);
6392 if (NULL == ac)
6393 {
6394 ac = GNUNET_new (struct AcknowledgementCummulator);
6395 ac->target = *pid;
6396 ac->min_transmission_time = max_delay;
6397 GNUNET_assert (GNUNET_YES ==
6398 GNUNET_CONTAINER_multipeermap_put (
6399 ack_cummulators,
6400 &ac->target,
6401 ac,
6402 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
6403 }
6404 else
6405 {
6406 if (MAX_CUMMULATIVE_ACKS == ac->num_acks)
6407 {
6408 /* must run immediately, ack buffer full! */
6409 transmit_cummulative_ack_cb (ac);
6410 }
6411 GNUNET_SCHEDULER_cancel (ac->task);
6412 ac->min_transmission_time =
6413 GNUNET_TIME_absolute_min (ac->min_transmission_time, max_delay);
6414 }
6415 GNUNET_assert (ac->num_acks < MAX_CUMMULATIVE_ACKS);
6416 ac->ack_uuids[ac->num_acks].receive_time = GNUNET_TIME_absolute_get ();
6417 ac->ack_uuids[ac->num_acks].ack_uuid = *ack_uuid;
6418 ac->num_acks++;
6419 ac->task = GNUNET_SCHEDULER_add_at (ac->min_transmission_time,
6420 &transmit_cummulative_ack_cb,
6421 ac);
6422}
6423
6424
6425/**
6426 * Closure for #find_by_message_uuid.
6427 */
6428struct FindByMessageUuidContext
6429{
6430 /**
6431 * UUID to look for.
6432 */
6433 struct MessageUUIDP message_uuid;
6434
6435 /**
6436 * Set to the reassembly context if found.
6437 */
6438 struct ReassemblyContext *rc;
6439};
6440
6441
6442/**
6443 * Iterator called to find a reassembly context by the message UUID in the
6444 * multihashmap32.
6445 *
6446 * @param cls a `struct FindByMessageUuidContext`
6447 * @param key a key (unused)
6448 * @param value a `struct ReassemblyContext`
6449 * @return #GNUNET_YES if not found, #GNUNET_NO if found
6450 */
6451static int
6452find_by_message_uuid (void *cls, uint32_t key, void *value)
6453{
6454 struct FindByMessageUuidContext *fc = cls;
6455 struct ReassemblyContext *rc = value;
6456
6457 (void) key;
6458 if (0 == GNUNET_memcmp (&fc->message_uuid, &rc->msg_uuid))
6459 {
6460 fc->rc = rc;
6461 return GNUNET_NO;
6462 }
6463 return GNUNET_YES;
6464}
6465
6466
6467/**
6468 * Communicator gave us a fragment. Process the request.
6469 *
6470 * @param cls a `struct CommunicatorMessageContext` (must call
6471 * #finish_cmc_handling() when done)
6472 * @param fb the message that was received
6473 */
6474static void
6475handle_fragment_box (void *cls, const struct TransportFragmentBoxMessage *fb)
6476{
6477 struct CommunicatorMessageContext *cmc = cls;
6478 struct VirtualLink *vl;
6479 struct ReassemblyContext *rc;
6480 const struct GNUNET_MessageHeader *msg;
6481 uint16_t msize;
6482 uint16_t fsize;
6483 uint16_t frag_off;
6484 char *target;
6485 struct GNUNET_TIME_Relative cdelay;
6486 struct FindByMessageUuidContext fc;
6487
6488 vl = lookup_virtual_link (&cmc->im.sender);
6489 if ((NULL == vl) || (GNUNET_NO == vl->confirmed))
6490 {
6491 struct GNUNET_SERVICE_Client *client = cmc->tc->client;
6492
6493 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6494 "No virtual link for %s to handle fragment\n",
6495 GNUNET_i2s (&cmc->im.sender));
6496 GNUNET_break (0);
6497 finish_cmc_handling (cmc);
6498 GNUNET_SERVICE_client_drop (client);
6499 return;
6500 }
6501 if (NULL == vl->reassembly_map)
6502 {
6503 vl->reassembly_map = GNUNET_CONTAINER_multihashmap32_create (8);
6504 vl->reassembly_heap =
6505 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
6506 vl->reassembly_timeout_task =
6507 GNUNET_SCHEDULER_add_delayed (REASSEMBLY_EXPIRATION,
6508 &reassembly_cleanup_task,
6509 vl);
6510 }
6511 msize = ntohs (fb->msg_size);
6512 fc.message_uuid = fb->msg_uuid;
6513 fc.rc = NULL;
6514 (void) GNUNET_CONTAINER_multihashmap32_get_multiple (vl->reassembly_map,
6515 fb->msg_uuid.uuid,
6516 &find_by_message_uuid,
6517 &fc);
6518 fsize = ntohs (fb->header.size) - sizeof(*fb);
6519 if (NULL == (rc = fc.rc))
6520 {
6521 rc = GNUNET_malloc (sizeof(*rc) + msize /* reassembly payload buffer */
6522 + (msize + 7) / 8 * sizeof(uint8_t) /* bitfield */);
6523 rc->msg_uuid = fb->msg_uuid;
6524 rc->virtual_link = vl;
6525 rc->msg_size = msize;
6526 rc->reassembly_timeout =
6527 GNUNET_TIME_relative_to_absolute (REASSEMBLY_EXPIRATION);
6528 rc->last_frag = GNUNET_TIME_absolute_get ();
6529 rc->hn = GNUNET_CONTAINER_heap_insert (vl->reassembly_heap,
6530 rc,
6531 rc->reassembly_timeout.abs_value_us);
6532 GNUNET_assert (GNUNET_OK ==
6533 GNUNET_CONTAINER_multihashmap32_put (
6534 vl->reassembly_map,
6535 rc->msg_uuid.uuid,
6536 rc,
6537 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
6538 target = (char *) &rc[1];
6539 rc->bitfield = (uint8_t *) (target + rc->msg_size);
6540 if (fsize != rc->msg_size)
6541 rc->msg_missing = rc->msg_size;
6542 else
6543 rc->msg_missing = 0;
6544 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6545 "Received fragment with size %u at offset %u/%u %u bytes missing from %s for NEW message %"
6546 PRIu64 "\n",
6547 fsize,
6548 ntohs (fb->frag_off),
6549 msize,
6550 rc->msg_missing,
6551 GNUNET_i2s (&cmc->im.sender),
6552 fb->msg_uuid.uuid);
6553 }
6554 else
6555 {
6556 target = (char *) &rc[1];
6557 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6558 "Received fragment at offset %u/%u from %s for message %u\n",
6559 ntohs (fb->frag_off),
6560 msize,
6561 GNUNET_i2s (&cmc->im.sender),
6562 (unsigned int) fb->msg_uuid.uuid);
6563 }
6564 if (msize != rc->msg_size)
6565 {
6566 GNUNET_break (0);
6567 finish_cmc_handling (cmc);
6568 return;
6569 }
6570
6571 /* reassemble */
6572 if (0 == fsize)
6573 {
6574 GNUNET_break (0);
6575 finish_cmc_handling (cmc);
6576 return;
6577 }
6578 frag_off = ntohs (fb->frag_off);
6579 if (frag_off + fsize > msize)
6580 {
6581 /* Fragment (plus fragment size) exceeds message size! */
6582 GNUNET_break_op (0);
6583 finish_cmc_handling (cmc);
6584 return;
6585 }
6586 memcpy (&target[frag_off], &fb[1], fsize);
6587 /* update bitfield and msg_missing */
6588 for (unsigned int i = frag_off; i < frag_off + fsize; i++)
6589 {
6590 if (0 == (rc->bitfield[i / 8] & (1 << (i % 8))))
6591 {
6592 rc->bitfield[i / 8] |= (1 << (i % 8));
6593 rc->msg_missing--;
6594 }
6595 }
6596
6597 /* Compute cumulative ACK */
6598 cdelay = GNUNET_TIME_absolute_get_duration (rc->last_frag);
6599 cdelay = GNUNET_TIME_relative_multiply (cdelay, rc->msg_missing / fsize);
6600 if (0 == rc->msg_missing)
6601 cdelay = GNUNET_TIME_UNIT_ZERO;
6602 cummulative_ack (&cmc->im.sender,
6603 &fb->ack_uuid,
6604 GNUNET_TIME_relative_to_absolute (cdelay));
6605 rc->last_frag = GNUNET_TIME_absolute_get ();
6606 /* is reassembly complete? */
6607 if (0 != rc->msg_missing)
6608 {
6609 finish_cmc_handling (cmc);
6610 return;
6611 }
6612 /* reassembly is complete, verify result */
6613 msg = (const struct GNUNET_MessageHeader *) &rc[1];
6614 if (ntohs (msg->size) != rc->msg_size)
6615 {
6616 GNUNET_break (0);
6617 free_reassembly_context (rc);
6618 finish_cmc_handling (cmc);
6619 return;
6620 }
6621 /* successful reassembly */
6622 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6623 "Fragment reassembly complete for message %u\n",
6624 (unsigned int) fb->msg_uuid.uuid);
6625 /* FIXME: check that the resulting msg is NOT a
6626 DV Box or Reliability Box, as that is NOT allowed! */
6627 cmc->mh = msg;
6628 demultiplex_with_cmc (cmc);
6629 /* FIXME-OPTIMIZE: really free here? Might be bad if fragments are still
6630 en-route and we forget that we finished this reassembly immediately!
6631 -> keep around until timeout?
6632 -> shorten timeout based on ACK? */
6633 free_reassembly_context (rc);
6634}
6635
6636
6637/**
6638 * Communicator gave us a reliability box. Check the message.
6639 *
6640 * @param cls a `struct CommunicatorMessageContext`
6641 * @param rb the send message that was sent
6642 * @return #GNUNET_YES if message is well-formed
6643 */
6644static int
6645check_reliability_box (void *cls,
6646 const struct TransportReliabilityBoxMessage *rb)
6647{
6648 (void) cls;
6649 const struct GNUNET_MessageHeader *inbox = (const struct
6650 GNUNET_MessageHeader *) &rb[1];
6651
6652 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6653 "check_send_msg with size %u: inner msg type %u and size %u (%lu %lu)\n",
6654 ntohs (rb->header.size),
6655 ntohs (inbox->type),
6656 ntohs (inbox->size),
6657 sizeof (struct TransportReliabilityBoxMessage),
6658 sizeof (struct GNUNET_MessageHeader));
6659 GNUNET_MQ_check_boxed_message (rb);
6660 return GNUNET_YES;
6661}
6662
6663
6664/**
6665 * Communicator gave us a reliability box. Process the request.
6666 *
6667 * @param cls a `struct CommunicatorMessageContext` (must call
6668 * #finish_cmc_handling() when done)
6669 * @param rb the message that was received
6670 */
6671static void
6672handle_reliability_box (void *cls,
6673 const struct TransportReliabilityBoxMessage *rb)
6674{
6675 struct CommunicatorMessageContext *cmc = cls;
6676 const struct GNUNET_MessageHeader *inbox =
6677 (const struct GNUNET_MessageHeader *) &rb[1];
6678 struct GNUNET_TIME_Relative rtt;
6679
6680 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6681 "Received reliability box from %s with UUID %s of type %u\n",
6682 GNUNET_i2s (&cmc->im.sender),
6683 GNUNET_uuid2s (&rb->ack_uuid.value),
6684 (unsigned int) ntohs (inbox->type));
6685 rtt = GNUNET_TIME_UNIT_SECONDS; /* FIXME: should base this on "RTT", but we
6686 do not really have an RTT for the
6687 * incoming* queue (should we have
6688 the sender add it to the rb message?) */
6689 cummulative_ack (
6690 &cmc->im.sender,
6691 &rb->ack_uuid,
6692 (0 == ntohl (rb->ack_countdown))
6693 ? GNUNET_TIME_UNIT_ZERO_ABS
6694 : GNUNET_TIME_relative_to_absolute (
6695 GNUNET_TIME_relative_divide (rtt, 8 /* FIXME: magic constant */)));
6696 /* continue with inner message */
6697 /* FIXME: check that inbox is NOT a DV Box, fragment or another
6698 reliability box (not allowed!) */
6699 cmc->mh = inbox;
6700 demultiplex_with_cmc (cmc);
6701}
6702
6703
6704/**
6705 * Check if we have advanced to another age since the last time. If
6706 * so, purge ancient statistics (more than GOODPUT_AGING_SLOTS before
6707 * the current age)
6708 *
6709 * @param[in,out] pd data to update
6710 * @param age current age
6711 */
6712static void
6713update_pd_age (struct PerformanceData *pd, unsigned int age)
6714{
6715 unsigned int sage;
6716
6717 if (age == pd->last_age)
6718 return; /* nothing to do */
6719 sage = GNUNET_MAX (pd->last_age, age - 2 * GOODPUT_AGING_SLOTS);
6720 for (unsigned int i = sage; i <= age - GOODPUT_AGING_SLOTS; i++)
6721 {
6722 struct TransmissionHistoryEntry *the = &pd->the[i % GOODPUT_AGING_SLOTS];
6723
6724 the->bytes_sent = 0;
6725 the->bytes_received = 0;
6726 }
6727 pd->last_age = age;
6728}
6729
6730
6731/**
6732 * Update @a pd based on the latest @a rtt and the number of bytes
6733 * that were confirmed to be successfully transmitted.
6734 *
6735 * @param[in,out] pd data to update
6736 * @param rtt latest round-trip time
6737 * @param bytes_transmitted_ok number of bytes receiver confirmed as received
6738 */
6739static void
6740update_performance_data (struct PerformanceData *pd,
6741 struct GNUNET_TIME_Relative rtt,
6742 uint16_t bytes_transmitted_ok)
6743{
6744 uint64_t nval = rtt.rel_value_us;
6745 uint64_t oval = pd->aged_rtt.rel_value_us;
6746 unsigned int age = get_age ();
6747 struct TransmissionHistoryEntry *the = &pd->the[age % GOODPUT_AGING_SLOTS];
6748
6749 if (oval == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us)
6750 pd->aged_rtt = rtt;
6751 else
6752 pd->aged_rtt.rel_value_us = (nval + 7 * oval) / 8;
6753 update_pd_age (pd, age);
6754 the->bytes_received += bytes_transmitted_ok;
6755}
6756
6757
6758/**
6759 * We have successfully transmitted data via @a q, update metrics.
6760 *
6761 * @param q queue to update
6762 * @param rtt round trip time observed
6763 * @param bytes_transmitted_ok number of bytes successfully transmitted
6764 */
6765static void
6766update_queue_performance (struct Queue *q,
6767 struct GNUNET_TIME_Relative rtt,
6768 uint16_t bytes_transmitted_ok)
6769{
6770 update_performance_data (&q->pd, rtt, bytes_transmitted_ok);
6771}
6772
6773
6774/**
6775 * We have successfully transmitted data via @a dvh, update metrics.
6776 *
6777 * @param dvh distance vector path data to update
6778 * @param rtt round trip time observed
6779 * @param bytes_transmitted_ok number of bytes successfully transmitted
6780 */
6781static void
6782update_dvh_performance (struct DistanceVectorHop *dvh,
6783 struct GNUNET_TIME_Relative rtt,
6784 uint16_t bytes_transmitted_ok)
6785{
6786 update_performance_data (&dvh->pd, rtt, bytes_transmitted_ok);
6787}
6788
6789
6790/**
6791 * We have completed transmission of @a pm, remove it from
6792 * the transmission queues (and if it is a fragment, continue
6793 * up the tree as necessary).
6794 *
6795 * @param pm pending message that was transmitted
6796 */
6797static void
6798completed_pending_message (struct PendingMessage *pm)
6799{
6800 struct PendingMessage *pos;
6801
6802 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6803 "Complete transmission of message %" PRIu64 " %u\n",
6804 pm->logging_uuid,
6805 pm->pmt);
6806 switch (pm->pmt)
6807 {
6808 case PMT_CORE:
6809 case PMT_RELIABILITY_BOX:
6810 /* Full message sent, we are done */
6811 client_send_response (pm);
6812 return;
6813
6814 case PMT_FRAGMENT_BOX:
6815 /* Fragment sent over reliable channel */
6816 pos = pm->frag_parent;
6817 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6818 free_pending_message (pm);
6819 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6820 "pos frag_off %lu pos bytes_msg %lu pmt %u parent %u\n",
6821 (unsigned long) pos->frag_off,
6822 (unsigned long) pos->bytes_msg,
6823 pos->pmt,
6824 NULL == pos->frag_parent ? 1 : 0);
6825 /* check if subtree is done */
6826 while ((NULL == pos->head_frag) && (pos->frag_off == (pos->bytes_msg
6827 - sizeof(struct
6828 TransportFragmentBoxMessage)))
6829 &&
6830 (NULL != pos->frag_parent))
6831 {
6832 pm = pos;
6833 pos = pm->frag_parent;
6834 if ((NULL == pos) && (PMT_DV_BOX == pm->pmt))
6835 {
6836 client_send_response (pm);
6837 return;
6838 }
6839 else if (PMT_DV_BOX == pm->pmt)
6840 {
6841 client_send_response (pos);
6842 return;
6843 }
6844 GNUNET_CONTAINER_MDLL_remove (frag, pos->head_frag, pos->tail_frag, pm);
6845 free_pending_message (pm);
6846 }
6847
6848 /* Was this the last applicable fragment? */
6849 if ((NULL == pos->head_frag) && (NULL == pos->frag_parent || PMT_DV_BOX ==
6850 pos->pmt) &&
6851 (pos->frag_off == pos->bytes_msg))
6852 client_send_response (pos);
6853 return;
6854
6855 case PMT_DV_BOX:
6856 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6857 "Completed transmission of message %" PRIu64 " (DV Box)\n",
6858 pm->logging_uuid);
6859 if (NULL != pm->frag_parent)
6860 {
6861 pos = pm->frag_parent;
6862 free_pending_message (pm);
6863 pos->bpm = NULL;
6864 client_send_response (pos);
6865 }
6866 else
6867 client_send_response (pm);
6868 return;
6869 }
6870}
6871
6872
6873/**
6874 * The @a pa was acknowledged, process the acknowledgement.
6875 *
6876 * @param pa the pending acknowledgement that was satisfied
6877 * @param ack_delay artificial delay from cumulative acks created by the
6878 * other peer
6879 */
6880static void
6881handle_acknowledged (struct PendingAcknowledgement *pa,
6882 struct GNUNET_TIME_Relative ack_delay)
6883{
6884 struct GNUNET_TIME_Relative delay;
6885
6886 delay = GNUNET_TIME_absolute_get_duration (pa->transmission_time);
6887 delay = GNUNET_TIME_relative_subtract (delay, ack_delay);
6888 if (NULL != pa->queue && 1 == pa->num_send)
6889 update_queue_performance (pa->queue, delay, pa->message_size);
6890 if (NULL != pa->dvh && 1 == pa->num_send)
6891 update_dvh_performance (pa->dvh, delay, pa->message_size);
6892 if (NULL != pa->pm)
6893 completed_pending_message (pa->pm);
6894 free_pending_acknowledgement (pa);
6895}
6896
6897
6898/**
6899 * Communicator gave us a reliability ack. Check it is well-formed.
6900 *
6901 * @param cls a `struct CommunicatorMessageContext` (unused)
6902 * @param ra the message that was received
6903 * @return #GNUNET_Ok if @a ra is well-formed
6904 */
6905static int
6906check_reliability_ack (void *cls,
6907 const struct TransportReliabilityAckMessage *ra)
6908{
6909 unsigned int n_acks;
6910
6911 (void) cls;
6912 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6913 / sizeof(struct TransportCummulativeAckPayloadP);
6914 if (0 == n_acks)
6915 {
6916 GNUNET_break_op (0);
6917 return GNUNET_SYSERR;
6918 }
6919 if ((ntohs (ra->header.size) - sizeof(*ra)) !=
6920 n_acks * sizeof(struct TransportCummulativeAckPayloadP))
6921 {
6922 GNUNET_break_op (0);
6923 return GNUNET_SYSERR;
6924 }
6925 return GNUNET_OK;
6926}
6927
6928
6929/**
6930 * Communicator gave us a reliability ack. Process the request.
6931 *
6932 * @param cls a `struct CommunicatorMessageContext` (must call
6933 * #finish_cmc_handling() when done)
6934 * @param ra the message that was received
6935 */
6936static void
6937handle_reliability_ack (void *cls,
6938 const struct TransportReliabilityAckMessage *ra)
6939{
6940 struct CommunicatorMessageContext *cmc = cls;
6941 const struct TransportCummulativeAckPayloadP *ack;
6942 unsigned int n_acks;
6943 uint32_t ack_counter;
6944
6945 n_acks = (ntohs (ra->header.size) - sizeof(*ra))
6946 / sizeof(struct TransportCummulativeAckPayloadP);
6947 ack = (const struct TransportCummulativeAckPayloadP *) &ra[1];
6948 for (unsigned int i = 0; i < n_acks; i++)
6949 {
6950 struct PendingAcknowledgement *pa =
6951 GNUNET_CONTAINER_multiuuidmap_get (pending_acks, &ack[i].ack_uuid.value);
6952 if (NULL == pa)
6953 {
6954 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
6955 "Received ACK from %s with UUID %s which is unknown to us!\n",
6956 GNUNET_i2s (&cmc->im.sender),
6957 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6958 GNUNET_STATISTICS_update (
6959 GST_stats,
6960 "# FRAGMENT_ACKS dropped, no matching pending message",
6961 1,
6962 GNUNET_NO);
6963 continue;
6964 }
6965 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
6966 "Received ACK from %s with UUID %s\n",
6967 GNUNET_i2s (&cmc->im.sender),
6968 GNUNET_uuid2s (&ack[i].ack_uuid.value));
6969 handle_acknowledged (pa, GNUNET_TIME_relative_ntoh (ack[i].ack_delay));
6970 }
6971
6972 ack_counter = htonl (ra->ack_counter);
6973 (void) ack_counter; /* silence compiler warning for now */
6974 // FIXME-OPTIMIZE: track ACK losses based on ack_counter somewhere!
6975 // (DV and/or Neighbour?)
6976 finish_cmc_handling (cmc);
6977}
6978
6979
6980/**
6981 * Communicator gave us a backchannel encapsulation. Check the message.
6982 *
6983 * @param cls a `struct CommunicatorMessageContext`
6984 * @param be the send message that was sent
6985 * @return #GNUNET_YES if message is well-formed
6986 */
6987static int
6988check_backchannel_encapsulation (
6989 void *cls,
6990 const struct TransportBackchannelEncapsulationMessage *be)
6991{
6992 uint16_t size = ntohs (be->header.size) - sizeof(*be);
6993 const struct GNUNET_MessageHeader *inbox =
6994 (const struct GNUNET_MessageHeader *) &be[1];
6995 const char *is;
6996 uint16_t isize;
6997
6998 (void) cls;
6999 if (ntohs (inbox->size) >= size)
7000 {
7001 GNUNET_break_op (0);
7002 return GNUNET_SYSERR;
7003 }
7004 isize = ntohs (inbox->size);
7005 is = ((const char *) inbox) + isize;
7006 size -= isize;
7007 if ('\0' != is[size - 1])
7008 {
7009 GNUNET_break_op (0);
7010 return GNUNET_SYSERR;
7011 }
7012 return GNUNET_YES;
7013}
7014
7015
7016/**
7017 * Communicator gave us a backchannel encapsulation. Process the request.
7018 * (We are the destination of the backchannel here.)
7019 *
7020 * @param cls a `struct CommunicatorMessageContext` (must call
7021 * #finish_cmc_handling() when done)
7022 * @param be the message that was received
7023 */
7024static void
7025handle_backchannel_encapsulation (
7026 void *cls,
7027 const struct TransportBackchannelEncapsulationMessage *be)
7028{
7029 struct CommunicatorMessageContext *cmc = cls;
7030 struct GNUNET_TRANSPORT_CommunicatorBackchannelIncoming *cbi;
7031 struct GNUNET_MQ_Envelope *env;
7032 struct TransportClient *tc;
7033 const struct GNUNET_MessageHeader *inbox =
7034 (const struct GNUNET_MessageHeader *) &be[1];
7035 uint16_t isize = ntohs (inbox->size);
7036 const char *target_communicator = ((const char *) inbox) + isize;
7037 char *sender;
7038 char *self;
7039
7040 GNUNET_asprintf (&sender,
7041 "%s",
7042 GNUNET_i2s (&cmc->im.sender));
7043 GNUNET_asprintf (&self,
7044 "%s",
7045 GNUNET_i2s (&GST_my_identity));
7046
7047 /* Find client providing this communicator */
7048 for (tc = clients_head; NULL != tc; tc = tc->next)
7049 if ((CT_COMMUNICATOR == tc->type) &&
7050 (0 ==
7051 strcmp (tc->details.communicator.address_prefix, target_communicator)))
7052 break;
7053 if (NULL == tc)
7054 {
7055 char *stastr;
7056
7057 GNUNET_asprintf (
7058 &stastr,
7059 "# Backchannel message dropped: target communicator `%s' unknown",
7060 target_communicator);
7061 GNUNET_STATISTICS_update (GST_stats, stastr, 1, GNUNET_NO);
7062 GNUNET_free (stastr);
7063 finish_cmc_handling (cmc);
7064 return;
7065 }
7066 /* Finally, deliver backchannel message to communicator */
7067 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7068 "Delivering backchannel message from %s to %s of type %u to %s\n",
7069 sender,
7070 self,
7071 ntohs (inbox->type),
7072 target_communicator);
7073 env = GNUNET_MQ_msg_extra (
7074 cbi,
7075 isize,
7076 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL_INCOMING);
7077 cbi->pid = cmc->im.sender;
7078 memcpy (&cbi[1], inbox, isize);
7079 GNUNET_MQ_send (tc->mq, env);
7080 finish_cmc_handling (cmc);
7081}
7082
7083
7084/**
7085 * Task called when we should check if any of the DV paths
7086 * we have learned to a target are due for garbage collection.
7087 *
7088 * Collects stale paths, and possibly frees the entire DV
7089 * entry if no paths are left. Otherwise re-schedules itself.
7090 *
7091 * @param cls a `struct DistanceVector`
7092 */
7093static void
7094path_cleanup_cb (void *cls)
7095{
7096 struct DistanceVector *dv = cls;
7097 struct DistanceVectorHop *pos;
7098
7099 dv->timeout_task = NULL;
7100 while (NULL != (pos = dv->dv_head))
7101 {
7102 GNUNET_assert (dv == pos->dv);
7103 if (GNUNET_TIME_absolute_get_remaining (pos->timeout).rel_value_us > 0)
7104 break;
7105 free_distance_vector_hop (pos);
7106 }
7107 if (NULL == pos)
7108 {
7109 free_dv_route (dv);
7110 return;
7111 }
7112 dv->timeout_task =
7113 GNUNET_SCHEDULER_add_at (pos->timeout, &path_cleanup_cb, dv);
7114}
7115
7116
7117static void
7118send_msg_from_cache (struct VirtualLink *vl)
7119{
7120
7121 const struct GNUNET_PeerIdentity target = vl->target;
7122
7123
7124 if ((GNUNET_YES == is_ring_buffer_full) || (0 < ring_buffer_head))
7125 {
7126 struct RingBufferEntry *ring_buffer_copy[RING_BUFFER_SIZE];
7127 unsigned int tail = GNUNET_YES == is_ring_buffer_full ? ring_buffer_head :
7128 0;
7129 unsigned int head = GNUNET_YES == is_ring_buffer_full ? RING_BUFFER_SIZE :
7130 ring_buffer_head;
7131 struct GNUNET_TRANSPORT_IncomingMessage im;
7132 struct CommunicatorMessageContext *cmc;
7133 struct RingBufferEntry *rbe;
7134 struct GNUNET_MessageHeader *mh;
7135
7136 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7137 "Sending from ring buffer, which has %u items\n",
7138 head);
7139
7140 ring_buffer_head = 0;
7141 for (unsigned int i = 0; i < head; i++)
7142 {
7143 rbe = ring_buffer[(i + tail) % RING_BUFFER_SIZE];
7144 cmc = rbe->cmc;
7145 mh = rbe->mh;
7146
7147 im = cmc->im;
7148 // mh = cmc->mh;
7149 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7150 "Sending message of type %u to ring buffer target %s using vl target %s index %u\n",
7151 mh->type,
7152 GNUNET_i2s (&im.sender),
7153 GNUNET_i2s2 (&target),
7154 (i + tail) % RING_BUFFER_SIZE);
7155 if (0 == GNUNET_memcmp (&target, &im.sender))
7156 {
7157 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7158 "Finish handling message of type %u and size %u\n",
7159 (unsigned int) ntohs (mh->type),
7160 (unsigned int) ntohs (mh->size));
7161 finish_handling_raw_message (vl, mh, cmc, GNUNET_NO);
7162 GNUNET_free (mh);
7163 GNUNET_free (rbe->cmc);
7164 GNUNET_free (rbe);
7165 }
7166 else
7167 {
7168 ring_buffer_copy[ring_buffer_head] = rbe;
7169 ring_buffer_head++;
7170 }
7171 }
7172
7173 if ((GNUNET_YES == is_ring_buffer_full) && (RING_BUFFER_SIZE - 1 >
7174 ring_buffer_head))
7175 {
7176 is_ring_buffer_full = GNUNET_NO;
7177 }
7178
7179 for (unsigned int i = 0; i < ring_buffer_head; i++)
7180 {
7181 ring_buffer[i] = ring_buffer_copy[i];
7182 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7183 "ring_buffer_copy[i]->mh->type for i %u %u\n",
7184 i,
7185 ring_buffer_copy[i]->mh->type);
7186 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7187 "ring_buffer[i]->mh->type for i %u %u\n",
7188 i,
7189 ring_buffer[i]->mh->type);
7190 }
7191
7192 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7193 "%u items still in ring buffer\n",
7194 ring_buffer_head);
7195 }
7196
7197 if ((GNUNET_YES == is_ring_buffer_dv_full) || (0 < ring_buffer_dv_head))
7198 {
7199 struct PendingMessage *ring_buffer_dv_copy[RING_BUFFER_SIZE];
7200 struct PendingMessage *pm;
7201 unsigned int tail = GNUNET_YES == is_ring_buffer_dv_full ?
7202 ring_buffer_dv_head :
7203 0;
7204 unsigned int head = GNUNET_YES == is_ring_buffer_dv_full ?
7205 RING_BUFFER_SIZE :
7206 ring_buffer_dv_head;
7207
7208 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7209 "Sending from ring buffer dv, which has %u items\n",
7210 head);
7211
7212 ring_buffer_dv_head = 0;
7213 for (unsigned int i = 0; i < head; i++)
7214 {
7215 pm = ring_buffer_dv[(i + tail) % RING_BUFFER_SIZE];
7216
7217 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7218 "Sending to ring buffer target %s using vl target %s\n",
7219 GNUNET_i2s (&pm->target),
7220 GNUNET_i2s2 (&target));
7221 if (0 == GNUNET_memcmp (&target, &pm->target))
7222 {
7223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7224 "Adding PendingMessage to vl, checking transmission.\n");
7225 pm->vl = vl;
7226 GNUNET_CONTAINER_MDLL_insert (vl,
7227 vl->pending_msg_head,
7228 vl->pending_msg_tail,
7229 pm);
7230
7231 check_vl_transmission (vl);
7232 }
7233 else
7234 {
7235 ring_buffer_dv_copy[ring_buffer_dv_head] = pm;
7236 ring_buffer_dv_head++;
7237 }
7238 }
7239
7240 if (is_ring_buffer_dv_full && (RING_BUFFER_SIZE - 1 > ring_buffer_dv_head))
7241 {
7242 is_ring_buffer_dv_full = GNUNET_NO;
7243 }
7244
7245 for (unsigned int i = 0; i < ring_buffer_dv_head; i++)
7246 ring_buffer_dv[i] = ring_buffer_dv_copy[i];
7247
7248 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7249 "%u items still in ring buffer dv.\n",
7250 ring_buffer_dv_head);
7251
7252 }
7253}
7254
7255
7256/**
7257 * The @a hop is a validated path to the respective target
7258 * peer and we should tell core about it -- and schedule
7259 * a job to revoke the state.
7260 *
7261 * @param hop a path to some peer that is the reason for activation
7262 */
7263static void
7264activate_core_visible_dv_path (struct DistanceVectorHop *hop)
7265{
7266 struct DistanceVector *dv = hop->dv;
7267 struct VirtualLink *vl;
7268
7269 vl = lookup_virtual_link (&dv->target);
7270 if (NULL == vl)
7271 {
7272
7273 vl = GNUNET_new (struct VirtualLink);
7274 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7275 "Creating new virtual link %p to %s using DV!\n",
7276 vl,
7277 GNUNET_i2s (&dv->target));
7278 vl->confirmed = GNUNET_YES;
7279 vl->message_uuid_ctr =
7280 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
7281 vl->target = dv->target;
7282 vl->core_recv_window = RECV_WINDOW_SIZE;
7283 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
7284 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
7285 GNUNET_break (GNUNET_YES ==
7286 GNUNET_CONTAINER_multipeermap_put (
7287 links,
7288 &vl->target,
7289 vl,
7290 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7291 vl->dv = dv;
7292 dv->vl = vl;
7293 vl->visibility_task =
7294 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
7295 consider_sending_fc (vl);
7296 /* We lacked a confirmed connection to the target
7297 before, so tell CORE about it (finally!) */
7298 cores_send_connect_info (&dv->target);
7299 send_msg_from_cache (vl);
7300 }
7301 else
7302 {
7303 /* Link was already up, remember dv is also now available and we are done */
7304 vl->dv = dv;
7305 dv->vl = vl;
7306 if (GNUNET_NO == vl->confirmed)
7307 {
7308 vl->confirmed = GNUNET_YES;
7309 vl->visibility_task =
7310 GNUNET_SCHEDULER_add_at (hop->path_valid_until, &check_link_down, vl);
7311 consider_sending_fc (vl);
7312 /* We lacked a confirmed connection to the target
7313 before, so tell CORE about it (finally!) */
7314 cores_send_connect_info (&dv->target);
7315 send_msg_from_cache (vl);
7316 }
7317 else
7318 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7319 "Virtual link to %s could now also use DV!\n",
7320 GNUNET_i2s (&dv->target));
7321 }
7322}
7323
7324
7325/**
7326 * We have learned a @a path through the network to some other peer, add it to
7327 * our DV data structure (returning #GNUNET_YES on success).
7328 *
7329 * We do not add paths if we have a sufficient number of shorter
7330 * paths to this target already (returning #GNUNET_NO).
7331 *
7332 * We also do not add problematic paths, like those where we lack the first
7333 * hop in our neighbour list (i.e. due to a topology change) or where some
7334 * non-first hop is in our neighbour list (returning #GNUNET_SYSERR).
7335 *
7336 * @param path the path we learned, path[0] should be us,
7337 * and then path contains a valid path from us to
7338 * `path[path_len-1]` path[1] should be a direct neighbour (we should check!)
7339 * @param path_len number of entries on the @a path, at least three!
7340 * @param network_latency how long does the message take from us to
7341 * `path[path_len-1]`? set to "forever" if unknown
7342 * @param path_valid_until how long is this path considered validated? Maybe
7343 * be zero.
7344 * @return #GNUNET_YES on success,
7345 * #GNUNET_NO if we have better path(s) to the target
7346 * #GNUNET_SYSERR if the path is useless and/or invalid
7347 * (i.e. path[1] not a direct neighbour
7348 * or path[i+1] is a direct neighbour for i>0)
7349 */
7350static int
7351learn_dv_path (const struct GNUNET_PeerIdentity *path,
7352 unsigned int path_len,
7353 struct GNUNET_TIME_Relative network_latency,
7354 struct GNUNET_TIME_Absolute path_valid_until)
7355{
7356 struct DistanceVectorHop *hop;
7357 struct DistanceVector *dv;
7358 struct Neighbour *next_hop;
7359 unsigned int shorter_distance;
7360
7361 if (path_len < 3)
7362 {
7363 /* what a boring path! not allowed! */
7364 GNUNET_break (0);
7365 return GNUNET_SYSERR;
7366 }
7367 GNUNET_assert (0 == GNUNET_memcmp (&GST_my_identity, &path[0]));
7368 next_hop = lookup_neighbour (&path[1]);
7369 if (NULL == next_hop)
7370 {
7371 /* next hop must be a neighbour, otherwise this whole thing is useless! */
7372 GNUNET_break (0);
7373 return GNUNET_SYSERR;
7374 }
7375 for (unsigned int i = 2; i < path_len; i++)
7376 if (NULL != lookup_neighbour (&path[i]))
7377 {
7378 /* Useless path: we have a direct connection to some hop
7379 in the middle of the path, so this one is not even
7380 terribly useful for redundancy */
7381 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7382 "Path of %u hops useless: directly link to hop %u (%s)\n",
7383 path_len,
7384 i,
7385 GNUNET_i2s (&path[i]));
7386 GNUNET_STATISTICS_update (GST_stats,
7387 "# Useless DV path ignored: hop is neighbour",
7388 1,
7389 GNUNET_NO);
7390 return GNUNET_SYSERR;
7391 }
7392 dv = GNUNET_CONTAINER_multipeermap_get (dv_routes, &path[path_len - 1]);
7393 if (NULL == dv)
7394 {
7395 dv = GNUNET_new (struct DistanceVector);
7396 dv->target = path[path_len - 1];
7397 dv->timeout_task = GNUNET_SCHEDULER_add_delayed (DV_PATH_VALIDITY_TIMEOUT,
7398 &path_cleanup_cb,
7399 dv);
7400 GNUNET_assert (GNUNET_OK ==
7401 GNUNET_CONTAINER_multipeermap_put (
7402 dv_routes,
7403 &dv->target,
7404 dv,
7405 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
7406 }
7407 /* Check if we have this path already! */
7408 shorter_distance = 0;
7409 for (struct DistanceVectorHop *pos = dv->dv_head; NULL != pos;
7410 pos = pos->next_dv)
7411 {
7412 if (pos->distance < path_len - 3)
7413 shorter_distance++;
7414 /* Note that the distances in 'pos' excludes us (path[0]),
7415 the next_hop (path[1]) and the target so we need to subtract three
7416 and check next_hop explicitly */
7417 if ((pos->distance == path_len - 3) && (pos->next_hop == next_hop))
7418 {
7419 int match = GNUNET_YES;
7420
7421 for (unsigned int i = 0; i < pos->distance; i++)
7422 {
7423 if (0 != GNUNET_memcmp (&pos->path[i], &path[i + 2]))
7424 {
7425 match = GNUNET_NO;
7426 break;
7427 }
7428 }
7429 if (GNUNET_YES == match)
7430 {
7431 struct GNUNET_TIME_Relative last_timeout;
7432
7433 /* Re-discovered known path, update timeout */
7434 GNUNET_STATISTICS_update (GST_stats,
7435 "# Known DV path refreshed",
7436 1,
7437 GNUNET_NO);
7438 last_timeout = GNUNET_TIME_absolute_get_remaining (pos->timeout);
7439 pos->timeout =
7440 GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
7441 pos->path_valid_until =
7442 GNUNET_TIME_absolute_max (pos->path_valid_until, path_valid_until);
7443 GNUNET_CONTAINER_MDLL_remove (dv, dv->dv_head, dv->dv_tail, pos);
7444 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, pos);
7445 if (0 <
7446 GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
7447 activate_core_visible_dv_path (pos);
7448 if (last_timeout.rel_value_us <
7449 GNUNET_TIME_relative_subtract (DV_PATH_VALIDITY_TIMEOUT,
7450 DV_PATH_DISCOVERY_FREQUENCY)
7451 .rel_value_us)
7452 {
7453 /* Some peer send DV learn messages too often, we are learning
7454 the same path faster than it would be useful; do not forward! */
7455 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
7456 "Rediscovered path too quickly, not forwarding further\n");
7457 return GNUNET_NO;
7458 }
7459 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7460 "Refreshed known path to %s valid until %s, forwarding further\n",
7461 GNUNET_i2s (&dv->target),
7462 GNUNET_STRINGS_absolute_time_to_string (
7463 pos->path_valid_until));
7464 return GNUNET_YES;
7465 }
7466 }
7467 }
7468 /* Count how many shorter paths we have (incl. direct
7469 neighbours) before simply giving up on this one! */
7470 if (shorter_distance >= MAX_DV_PATHS_TO_TARGET)
7471 {
7472 /* We have a shorter path already! */
7473 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7474 "Have many shorter DV paths %s, not forwarding further\n",
7475 GNUNET_i2s (&dv->target));
7476 return GNUNET_NO;
7477 }
7478 /* create new DV path entry */
7479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7480 "Discovered new DV path to %s valid until %s\n",
7481 GNUNET_i2s (&dv->target),
7482 GNUNET_STRINGS_absolute_time_to_string (path_valid_until));
7483 hop = GNUNET_malloc (sizeof(struct DistanceVectorHop)
7484 + sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
7485 hop->next_hop = next_hop;
7486 hop->dv = dv;
7487 hop->path = (const struct GNUNET_PeerIdentity *) &hop[1];
7488 memcpy (&hop[1],
7489 &path[2],
7490 sizeof(struct GNUNET_PeerIdentity) * (path_len - 3));
7491 hop->timeout = GNUNET_TIME_relative_to_absolute (DV_PATH_VALIDITY_TIMEOUT);
7492 hop->path_valid_until = path_valid_until;
7493 hop->distance = path_len - 3;
7494 hop->pd.aged_rtt = network_latency;
7495 GNUNET_CONTAINER_MDLL_insert (dv, dv->dv_head, dv->dv_tail, hop);
7496 GNUNET_CONTAINER_MDLL_insert (neighbour,
7497 next_hop->dv_head,
7498 next_hop->dv_tail,
7499 hop);
7500 if (0 < GNUNET_TIME_absolute_get_remaining (path_valid_until).rel_value_us)
7501 activate_core_visible_dv_path (hop);
7502 return GNUNET_YES;
7503}
7504
7505
7506/**
7507 * Communicator gave us a DV learn message. Check the message.
7508 *
7509 * @param cls a `struct CommunicatorMessageContext`
7510 * @param dvl the send message that was sent
7511 * @return #GNUNET_YES if message is well-formed
7512 */
7513static int
7514check_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
7515{
7516 uint16_t size = ntohs (dvl->header.size);
7517 uint16_t num_hops = ntohs (dvl->num_hops);
7518 const struct DVPathEntryP *hops = (const struct DVPathEntryP *) &dvl[1];
7519
7520 (void) cls;
7521 if (size != sizeof(*dvl) + num_hops * sizeof(struct DVPathEntryP))
7522 {
7523 GNUNET_break_op (0);
7524 return GNUNET_SYSERR;
7525 }
7526 if (num_hops > MAX_DV_HOPS_ALLOWED)
7527 {
7528 GNUNET_break_op (0);
7529 return GNUNET_SYSERR;
7530 }
7531 for (unsigned int i = 0; i < num_hops; i++)
7532 {
7533 if (0 == GNUNET_memcmp (&dvl->initiator, &hops[i].hop))
7534 {
7535 GNUNET_break_op (0);
7536 return GNUNET_SYSERR;
7537 }
7538 if (0 == GNUNET_memcmp (&GST_my_identity, &hops[i].hop))
7539 {
7540 GNUNET_break_op (0);
7541 return GNUNET_SYSERR;
7542 }
7543 }
7544 return GNUNET_YES;
7545}
7546
7547
7548/**
7549 * Build and forward a DV learn message to @a next_hop.
7550 *
7551 * @param next_hop peer to send the message to
7552 * @param msg message received
7553 * @param bi_history bitmask specifying hops on path that were bidirectional
7554 * @param nhops length of the @a hops array
7555 * @param hops path the message traversed so far
7556 * @param in_time when did we receive the message, used to calculate network
7557 * delay
7558 */
7559static void
7560forward_dv_learn (const struct GNUNET_PeerIdentity *next_hop,
7561 const struct TransportDVLearnMessage *msg,
7562 uint16_t bi_history,
7563 uint16_t nhops,
7564 const struct DVPathEntryP *hops,
7565 struct GNUNET_TIME_Absolute in_time)
7566{
7567 struct Neighbour *n;
7568 struct VirtualLink *vl;
7569 struct DVPathEntryP *dhops;
7570 char buf[sizeof(struct TransportDVLearnMessage)
7571 + (nhops + 1) * sizeof(struct DVPathEntryP)] GNUNET_ALIGN;
7572 struct TransportDVLearnMessage *fwd = (struct TransportDVLearnMessage *) buf;
7573 struct GNUNET_TIME_Relative nnd;
7574
7575 /* compute message for forwarding */
7576 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7577 "Forwarding DV learn message originating from %s to %s\n",
7578 GNUNET_i2s (&msg->initiator),
7579 GNUNET_i2s2 (next_hop));
7580 GNUNET_assert (nhops < MAX_DV_HOPS_ALLOWED);
7581 fwd->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
7582 fwd->header.size = htons (sizeof(struct TransportDVLearnMessage)
7583 + (nhops + 1) * sizeof(struct DVPathEntryP));
7584 fwd->num_hops = htons (nhops + 1);
7585 fwd->bidirectional = htons (bi_history);
7586 nnd = GNUNET_TIME_relative_add (GNUNET_TIME_absolute_get_duration (in_time),
7587 GNUNET_TIME_relative_ntoh (
7588 msg->non_network_delay));
7589 fwd->non_network_delay = GNUNET_TIME_relative_hton (nnd);
7590 fwd->init_sig = msg->init_sig;
7591 fwd->initiator = msg->initiator;
7592 fwd->challenge = msg->challenge;
7593 fwd->monotonic_time = msg->monotonic_time;
7594 dhops = (struct DVPathEntryP *) &fwd[1];
7595 GNUNET_memcpy (dhops, hops, sizeof(struct DVPathEntryP) * nhops);
7596 dhops[nhops].hop = GST_my_identity;
7597 {
7598 struct DvHopPS dhp = {
7599 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
7600 .purpose.size = htonl (sizeof(dhp)),
7601 .pred = (0 == nhops) ? msg->initiator : dhops[nhops - 1].hop,
7602 .succ = *next_hop,
7603 .challenge = msg->challenge
7604 };
7605 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
7606 &dhp,
7607 &dhops[nhops].hop_sig);
7608 }
7609 /*route_control_message_without_fc (next_hop,
7610 &fwd->header,
7611 RMO_UNCONFIRMED_ALLOWED);*/
7612 vl = lookup_virtual_link (next_hop);
7613 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
7614 {
7615 route_control_message_without_fc (vl,
7616 &fwd->header,
7617 RMO_UNCONFIRMED_ALLOWED);
7618 }
7619 else
7620 {
7621 /* Use route via neighbour */
7622 n = lookup_neighbour (next_hop);
7623 if (NULL != n)
7624 route_via_neighbour (
7625 n,
7626 &fwd->header,
7627 RMO_UNCONFIRMED_ALLOWED);
7628 }
7629}
7630
7631
7632/**
7633 * Check signature of type #GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR
7634 *
7635 * @param sender_monotonic_time monotonic time of the initiator
7636 * @param init the signer
7637 * @param challenge the challenge that was signed
7638 * @param init_sig signature presumably by @a init
7639 * @return #GNUNET_OK if the signature is valid
7640 */
7641static int
7642validate_dv_initiator_signature (
7643 struct GNUNET_TIME_AbsoluteNBO sender_monotonic_time,
7644 const struct GNUNET_PeerIdentity *init,
7645 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge,
7646 const struct GNUNET_CRYPTO_EddsaSignature *init_sig)
7647{
7648 struct DvInitPS ip = { .purpose.purpose = htonl (
7649 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
7650 .purpose.size = htonl (sizeof(ip)),
7651 .monotonic_time = sender_monotonic_time,
7652 .challenge = *challenge };
7653
7654 if (
7655 GNUNET_OK !=
7656 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR,
7657 &ip,
7658 init_sig,
7659 &init->public_key))
7660 {
7661 GNUNET_break_op (0);
7662 return GNUNET_SYSERR;
7663 }
7664 return GNUNET_OK;
7665}
7666
7667
7668/**
7669 * Closure for #dv_neighbour_selection and #dv_neighbour_transmission.
7670 */
7671struct NeighbourSelectionContext
7672{
7673 /**
7674 * Original message we received.
7675 */
7676 const struct TransportDVLearnMessage *dvl;
7677
7678 /**
7679 * The hops taken.
7680 */
7681 const struct DVPathEntryP *hops;
7682
7683 /**
7684 * Time we received the message.
7685 */
7686 struct GNUNET_TIME_Absolute in_time;
7687
7688 /**
7689 * Offsets of the selected peers.
7690 */
7691 uint32_t selections[MAX_DV_DISCOVERY_SELECTION];
7692
7693 /**
7694 * Number of peers eligible for selection.
7695 */
7696 unsigned int num_eligible;
7697
7698 /**
7699 * Number of peers that were selected for forwarding.
7700 */
7701 unsigned int num_selections;
7702
7703 /**
7704 * Number of hops in @e hops
7705 */
7706 uint16_t nhops;
7707
7708 /**
7709 * Bitmap of bidirectional connections encountered.
7710 */
7711 uint16_t bi_history;
7712};
7713
7714
7715/**
7716 * Function called for each neighbour during #handle_dv_learn.
7717 *
7718 * @param cls a `struct NeighbourSelectionContext *`
7719 * @param pid identity of the peer
7720 * @param value a `struct Neighbour`
7721 * @return #GNUNET_YES (always)
7722 */
7723static int
7724dv_neighbour_selection (void *cls,
7725 const struct GNUNET_PeerIdentity *pid,
7726 void *value)
7727{
7728 struct NeighbourSelectionContext *nsc = cls;
7729
7730 (void) value;
7731 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7732 return GNUNET_YES; /* skip initiator */
7733 for (unsigned int i = 0; i < nsc->nhops; i++)
7734 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7735 return GNUNET_YES;
7736 /* skip peers on path */
7737 nsc->num_eligible++;
7738 return GNUNET_YES;
7739}
7740
7741
7742/**
7743 * Function called for each neighbour during #handle_dv_learn.
7744 * We call #forward_dv_learn() on the neighbour(s) selected
7745 * during #dv_neighbour_selection().
7746 *
7747 * @param cls a `struct NeighbourSelectionContext *`
7748 * @param pid identity of the peer
7749 * @param value a `struct Neighbour`
7750 * @return #GNUNET_YES (always)
7751 */
7752static int
7753dv_neighbour_transmission (void *cls,
7754 const struct GNUNET_PeerIdentity *pid,
7755 void *value)
7756{
7757 struct NeighbourSelectionContext *nsc = cls;
7758
7759 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7760 "transmission %s\n",
7761 GNUNET_i2s (pid));
7762 (void) value;
7763 if (0 == GNUNET_memcmp (pid, &nsc->dvl->initiator))
7764 return GNUNET_YES; /* skip initiator */
7765 for (unsigned int i = 0; i < nsc->nhops; i++)
7766 if (0 == GNUNET_memcmp (pid, &nsc->hops[i].hop))
7767 return GNUNET_YES;
7768 /* skip peers on path */
7769 for (unsigned int i = 0; i < nsc->num_selections; i++)
7770 {
7771 if (nsc->selections[i] == nsc->num_eligible)
7772 {
7773 forward_dv_learn (pid,
7774 nsc->dvl,
7775 nsc->bi_history,
7776 nsc->nhops,
7777 nsc->hops,
7778 nsc->in_time);
7779 break;
7780 }
7781 }
7782 nsc->num_eligible++;
7783 return GNUNET_YES;
7784}
7785
7786
7787/**
7788 * Computes the number of neighbours we should forward a DVInit
7789 * message to given that it has so far taken @a hops_taken hops
7790 * though the network and that the number of neighbours we have
7791 * in total is @a neighbour_count, out of which @a eligible_count
7792 * are not yet on the path.
7793 *
7794 * NOTE: technically we might want to include NSE in the formula to
7795 * get a better grip on the overall network size. However, for now
7796 * using NSE here would create a dependency issue in the build system.
7797 * => Left for later, hardcoded to 50 for now.
7798 *
7799 * The goal of the fomula is that we want to reach a total of LOG(NSE)
7800 * peers via DV (`target_total`). We want the reach to be spread out
7801 * over various distances to the origin, with a bias towards shorter
7802 * distances.
7803 *
7804 * We make the strong assumption that the network topology looks
7805 * "similar" at other hops, in particular the @a neighbour_count
7806 * should be comparable at other hops.
7807 *
7808 * If the local neighbourhood is densely connected, we expect that @a
7809 * eligible_count is close to @a neighbour_count minus @a hops_taken
7810 * as a lot of the path is already known. In that case, we should
7811 * forward to few(er) peers to try to find a path out of the
7812 * neighbourhood. OTOH, if @a eligible_count is close to @a
7813 * neighbour_count, we should forward to many peers as we are either
7814 * still close to the origin (i.e. @a hops_taken is small) or because
7815 * we managed to get beyond a local cluster. We express this as
7816 * the `boost_factor` using the square of the fraction of eligible
7817 * neighbours (so if only 50% are eligible, we boost by 1/4, but if
7818 * 99% are eligible, the 'boost' will be almost 1).
7819 *
7820 * Second, the more hops we have taken, the larger the problem of an
7821 * exponential traffic explosion gets. So we take the `target_total`,
7822 * and compute our degree such that at each distance d 2^{-d} peers
7823 * are selected (corrected by the `boost_factor`).
7824 *
7825 * @param hops_taken number of hops DVInit has travelled so far
7826 * @param neighbour_count number of neighbours we have in total
7827 * @param eligible_count number of neighbours we could in
7828 * theory forward to
7829 */
7830static unsigned int
7831calculate_fork_degree (unsigned int hops_taken,
7832 unsigned int neighbour_count,
7833 unsigned int eligible_count)
7834{
7835 double target_total = 50.0; /* FIXME: use LOG(NSE)? */
7836 double eligible_ratio =
7837 ((double) eligible_count) / ((double) neighbour_count);
7838 double boost_factor = eligible_ratio * eligible_ratio;
7839 unsigned int rnd;
7840 double left;
7841
7842 if (hops_taken >= 64)
7843 {
7844 GNUNET_break (0);
7845 return 0; /* precaution given bitshift below */
7846 }
7847 for (unsigned int i = 1; i < hops_taken; i++)
7848 {
7849 /* For each hop, subtract the expected number of targets
7850 reached at distance d (so what remains divided by 2^d) */
7851 target_total -= (target_total * boost_factor / (1LLU << i));
7852 }
7853 rnd =
7854 (unsigned int) floor (target_total * boost_factor / (1LLU << hops_taken));
7855 /* round up or down probabilistically depending on how close we were
7856 when floor()ing to rnd */
7857 left = target_total - (double) rnd;
7858 if (UINT32_MAX * left >
7859 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT32_MAX))
7860 rnd++; /* round up */
7861 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7862 "Forwarding DV learn message of %u hops %u(/%u/%u) times\n",
7863 hops_taken,
7864 rnd,
7865 eligible_count,
7866 neighbour_count);
7867 return rnd;
7868}
7869
7870
7871/**
7872 * Function called when peerstore is done storing a DV monotonic time.
7873 *
7874 * @param cls a `struct Neighbour`
7875 * @param success #GNUNET_YES if peerstore was successful
7876 */
7877static void
7878neighbour_store_dvmono_cb (void *cls, int success)
7879{
7880 struct Neighbour *n = cls;
7881
7882 n->sc = NULL;
7883 if (GNUNET_YES != success)
7884 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
7885 "Failed to store other peer's monotonic time in peerstore!\n");
7886}
7887
7888
7889/**
7890 * Communicator gave us a DV learn message. Process the request.
7891 *
7892 * @param cls a `struct CommunicatorMessageContext` (must call
7893 * #finish_cmc_handling() when done)
7894 * @param dvl the message that was received
7895 */
7896static void
7897handle_dv_learn (void *cls, const struct TransportDVLearnMessage *dvl)
7898{
7899 struct CommunicatorMessageContext *cmc = cls;
7900 enum GNUNET_TRANSPORT_CommunicatorCharacteristics cc;
7901 int bi_hop;
7902 uint16_t nhops;
7903 uint16_t bi_history;
7904 const struct DVPathEntryP *hops;
7905 int do_fwd;
7906 int did_initiator;
7907 struct GNUNET_TIME_Absolute in_time;
7908 struct Neighbour *n;
7909
7910 nhops = ntohs (dvl->num_hops); /* 0 = sender is initiator */
7911 bi_history = ntohs (dvl->bidirectional);
7912 hops = (const struct DVPathEntryP *) &dvl[1];
7913 if (0 == nhops)
7914 {
7915 /* sanity check */
7916 if (0 != GNUNET_memcmp (&dvl->initiator, &cmc->im.sender))
7917 {
7918 GNUNET_break (0);
7919 finish_cmc_handling (cmc);
7920 return;
7921 }
7922 }
7923 else
7924 {
7925 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7926 "handle dv learn message last hop %s\n",
7927 GNUNET_i2s (&hops[nhops - 1].hop));
7928 /* sanity check */
7929 if (0 != GNUNET_memcmp (&hops[nhops - 1].hop, &cmc->im.sender))
7930 {
7931 GNUNET_break (0);
7932 finish_cmc_handling (cmc);
7933 return;
7934 }
7935 }
7936
7937 GNUNET_assert (CT_COMMUNICATOR == cmc->tc->type);
7938 cc = cmc->tc->details.communicator.cc;
7939 bi_hop = (GNUNET_TRANSPORT_CC_RELIABLE ==
7940 cc); // FIXME: add bi-directional flag to cc?
7941 in_time = GNUNET_TIME_absolute_get ();
7942
7943 /* continue communicator here, everything else can happen asynchronous! */
7944 finish_cmc_handling (cmc);
7945
7946 n = lookup_neighbour (&dvl->initiator);
7947 if (NULL != n)
7948 {
7949 if ((n->dv_monotime_available == GNUNET_YES) &&
7950 (GNUNET_TIME_absolute_ntoh (dvl->monotonic_time).abs_value_us <
7951 n->last_dv_learn_monotime.abs_value_us))
7952 {
7953 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7954 "DV learn from %s discarded due to time travel",
7955 GNUNET_i2s (&dvl->initiator));
7956 GNUNET_STATISTICS_update (GST_stats,
7957 "# DV learn discarded due to time travel",
7958 1,
7959 GNUNET_NO);
7960 return;
7961 }
7962 if (GNUNET_OK != validate_dv_initiator_signature (dvl->monotonic_time,
7963 &dvl->initiator,
7964 &dvl->challenge,
7965 &dvl->init_sig))
7966 {
7967 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7968 "DV learn signature from %s invalid\n",
7969 GNUNET_i2s (&dvl->initiator));
7970 GNUNET_break_op (0);
7971 return;
7972 }
7973 n->last_dv_learn_monotime = GNUNET_TIME_absolute_ntoh (dvl->monotonic_time);
7974 if (GNUNET_YES == n->dv_monotime_available)
7975 {
7976 if (NULL != n->sc)
7977 {
7978 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
7979 "store cancel\n");
7980 GNUNET_PEERSTORE_store_cancel (n->sc);
7981 }
7982 n->sc =
7983 GNUNET_PEERSTORE_store (peerstore,
7984 "transport",
7985 &dvl->initiator,
7986 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
7987 &dvl->monotonic_time,
7988 sizeof(dvl->monotonic_time),
7989 GNUNET_TIME_UNIT_FOREVER_ABS,
7990 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
7991 &neighbour_store_dvmono_cb,
7992 n);
7993 }
7994 }
7995 /* OPTIMIZE-FIXME: asynchronously (!) verify signatures!,
7996 If signature verification load too high, implement random drop strategy */
7997 for (unsigned int i = 0; i < nhops; i++)
7998 {
7999 struct DvHopPS dhp = { .purpose.purpose =
8000 htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP),
8001 .purpose.size = htonl (sizeof(dhp)),
8002 .pred = (0 == i) ? dvl->initiator : hops[i - 1].hop,
8003 .succ = (nhops == i + 1) ? GST_my_identity
8004 : hops[i + 1].hop,
8005 .challenge = dvl->challenge };
8006
8007 if (GNUNET_OK !=
8008 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_HOP,
8009 &dhp,
8010 &hops[i].hop_sig,
8011 &hops[i].hop.public_key))
8012 {
8013 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8014 "DV learn from %s signature of hop %u invalid\n",
8015 GNUNET_i2s (&dvl->initiator),
8016 i);
8017 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8018 "signature of hop %s invalid\n",
8019 GNUNET_i2s (&hops[i].hop));
8020 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8021 "pred %s\n",
8022 GNUNET_i2s (&dhp.pred));
8023 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8024 "succ %s\n",
8025 GNUNET_i2s (&dhp.succ));
8026 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8027 "hash %s\n",
8028 GNUNET_sh2s (&dhp.challenge.value));
8029 GNUNET_break_op (0);
8030 return;
8031 }
8032 }
8033 if (GNUNET_EXTRA_LOGGING > 0)
8034 {
8035 char *path;
8036
8037 path = GNUNET_strdup (GNUNET_i2s (&dvl->initiator));
8038 for (unsigned int i = 0; i < nhops; i++)
8039 {
8040 char *tmp;
8041
8042 GNUNET_asprintf (&tmp,
8043 "%s%s%s",
8044 path,
8045 (bi_history & (1 << (nhops - i))) ? "<->" : "-->",
8046 GNUNET_i2s (&hops[i].hop));
8047 GNUNET_free (path);
8048 path = tmp;
8049 }
8050 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8051 "Received DVInit via %s%s%s\n",
8052 path,
8053 bi_hop ? "<->" : "-->",
8054 GNUNET_i2s (&GST_my_identity));
8055 GNUNET_free (path);
8056 }
8057 do_fwd = GNUNET_YES;
8058 if (0 == GNUNET_memcmp (&GST_my_identity, &dvl->initiator))
8059 {
8060 struct GNUNET_PeerIdentity path[nhops + 1];
8061 struct GNUNET_TIME_Relative host_latency_sum;
8062 struct GNUNET_TIME_Relative latency;
8063 struct GNUNET_TIME_Relative network_latency;
8064
8065 /* We initiated this, learn the forward path! */
8066 path[0] = GST_my_identity;
8067 path[1] = hops[0].hop;
8068 host_latency_sum = GNUNET_TIME_relative_ntoh (dvl->non_network_delay);
8069
8070 // Need also something to lookup initiation time
8071 // to compute RTT! -> add RTT argument here?
8072 latency = GNUNET_TIME_absolute_get_duration (GNUNET_TIME_absolute_ntoh (
8073 dvl->monotonic_time));
8074 GNUNET_assert (latency.rel_value_us >= host_latency_sum.rel_value_us);
8075 // latency = GNUNET_TIME_UNIT_FOREVER_REL; // FIXME: initialize properly
8076 // (based on dvl->challenge, we can identify time of origin!)
8077
8078 network_latency = GNUNET_TIME_relative_subtract (latency, host_latency_sum);
8079 /* assumption: latency on all links is the same */
8080 network_latency = GNUNET_TIME_relative_divide (network_latency, nhops);
8081
8082 for (unsigned int i = 2; i <= nhops; i++)
8083 {
8084 struct GNUNET_TIME_Relative ilat;
8085
8086 /* assumption: linear latency increase per hop */
8087 ilat = GNUNET_TIME_relative_multiply (network_latency, i);
8088 path[i] = hops[i - 1].hop;
8089 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8090 "Learned path with %u hops to %s with latency %s\n",
8091 i,
8092 GNUNET_i2s (&path[i]),
8093 GNUNET_STRINGS_relative_time_to_string (ilat, GNUNET_YES));
8094 learn_dv_path (path,
8095 i + 1,
8096 ilat,
8097 GNUNET_TIME_relative_to_absolute (
8098 ADDRESS_VALIDATION_LIFETIME));
8099 }
8100 /* as we initiated, do not forward again (would be circular!) */
8101 do_fwd = GNUNET_NO;
8102 return;
8103 }
8104 if (bi_hop)
8105 {
8106 /* last hop was bi-directional, we could learn something here! */
8107 struct GNUNET_PeerIdentity path[nhops + 2];
8108
8109 path[0] = GST_my_identity;
8110 path[1] = hops[nhops - 1].hop; /* direct neighbour == predecessor! */
8111 for (unsigned int i = 0; i < nhops; i++)
8112 {
8113 int iret;
8114
8115 if (0 == (bi_history & (1 << i)))
8116 break; /* i-th hop not bi-directional, stop learning! */
8117 if (i == nhops - 1)
8118 {
8119 path[i + 2] = dvl->initiator;
8120 }
8121 else
8122 {
8123 path[i + 2] = hops[nhops - i - 2].hop;
8124 }
8125
8126 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8127 "Learned inverse path with %u hops to %s\n",
8128 i + 2,
8129 GNUNET_i2s (&path[i + 2]));
8130 iret = learn_dv_path (path,
8131 i + 3,
8132 GNUNET_TIME_UNIT_FOREVER_REL,
8133 GNUNET_TIME_relative_to_absolute (
8134 ADDRESS_VALIDATION_LIFETIME));
8135 if (GNUNET_SYSERR == iret)
8136 {
8137 /* path invalid or too long to be interesting for US, thus should also
8138 not be interesting to our neighbours, cut path when forwarding to
8139 'i' hops, except of course for the one that goes back to the
8140 initiator */
8141 GNUNET_STATISTICS_update (GST_stats,
8142 "# DV learn not forwarded due invalidity of path",
8143 1,
8144 GNUNET_NO);
8145 do_fwd = GNUNET_NO;
8146 break;
8147 }
8148 if ((GNUNET_NO == iret) && (nhops == i + 1))
8149 {
8150 /* we have better paths, and this is the longest target,
8151 so there cannot be anything interesting later */
8152 GNUNET_STATISTICS_update (GST_stats,
8153 "# DV learn not forwarded, got better paths",
8154 1,
8155 GNUNET_NO);
8156 do_fwd = GNUNET_NO;
8157 break;
8158 }
8159 }
8160 }
8161 if (MAX_DV_HOPS_ALLOWED == nhops)
8162 {
8163 /* At limit, we're out of here! */
8164 return;
8165 }
8166
8167 /* Forward to initiator, if path non-trivial and possible */
8168 bi_history = (bi_history << 1) | (bi_hop ? 1 : 0);
8169 did_initiator = GNUNET_NO;
8170 if ((1 <= nhops) &&
8171 (GNUNET_YES ==
8172 GNUNET_CONTAINER_multipeermap_contains (neighbours, &dvl->initiator)))
8173 {
8174 /* send back to origin! */
8175 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8176 "Sending DVL back to initiator %s\n",
8177 GNUNET_i2s (&dvl->initiator));
8178 forward_dv_learn (&dvl->initiator, dvl, bi_history, nhops, hops, in_time);
8179 did_initiator = GNUNET_YES;
8180 }
8181 /* We forward under two conditions: either we still learned something
8182 ourselves (do_fwd), or the path was darn short and thus the initiator is
8183 likely to still be very interested in this (and we did NOT already
8184 send it back to the initiator) */
8185 if ((do_fwd) || ((nhops < MIN_DV_PATH_LENGTH_FOR_INITIATOR) &&
8186 (GNUNET_NO == did_initiator)))
8187 {
8188 /* Pick random neighbours that are not yet on the path */
8189 struct NeighbourSelectionContext nsc;
8190 unsigned int n_cnt;
8191
8192 n_cnt = GNUNET_CONTAINER_multipeermap_size (neighbours);
8193 nsc.nhops = nhops;
8194 nsc.dvl = dvl;
8195 nsc.bi_history = bi_history;
8196 nsc.hops = hops;
8197 nsc.in_time = in_time;
8198 nsc.num_eligible = 0;
8199 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8200 &dv_neighbour_selection,
8201 &nsc);
8202 if (0 == nsc.num_eligible)
8203 return; /* done here, cannot forward to anyone else */
8204 nsc.num_selections = calculate_fork_degree (nhops, n_cnt, nsc.num_eligible);
8205 nsc.num_selections =
8206 GNUNET_MIN (MAX_DV_DISCOVERY_SELECTION, nsc.num_selections);
8207 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8208 "Forwarding DVL to %u other peers\n",
8209 nsc.num_selections);
8210 for (unsigned int i = 0; i < nsc.num_selections; i++)
8211 nsc.selections[i] =
8212 (nsc.num_selections == n_cnt)
8213 ? i /* all were selected, avoid collisions by chance */
8214 : GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, n_cnt);
8215 nsc.num_eligible = 0;
8216 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
8217 &dv_neighbour_transmission,
8218 &nsc);
8219 }
8220}
8221
8222
8223/**
8224 * Communicator gave us a DV box. Check the message.
8225 *
8226 * @param cls a `struct CommunicatorMessageContext`
8227 * @param dvb the send message that was sent
8228 * @return #GNUNET_YES if message is well-formed
8229 */
8230static int
8231check_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
8232{
8233 uint16_t size = ntohs (dvb->header.size);
8234 uint16_t num_hops = ntohs (dvb->num_hops);
8235 const struct GNUNET_PeerIdentity *hops =
8236 (const struct GNUNET_PeerIdentity *) &dvb[1];
8237
8238 (void) cls;
8239 if (size < sizeof(*dvb) + num_hops * sizeof(struct GNUNET_PeerIdentity)
8240 + sizeof(struct GNUNET_MessageHeader))
8241 {
8242 GNUNET_break_op (0);
8243 return GNUNET_SYSERR;
8244 }
8245 /* This peer must not be on the path */
8246 for (unsigned int i = 0; i < num_hops; i++)
8247 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
8248 {
8249 GNUNET_break_op (0);
8250 return GNUNET_SYSERR;
8251 }
8252 return GNUNET_YES;
8253}
8254
8255
8256/**
8257 * Create a DV Box message and queue it for transmission to
8258 * @a next_hop.
8259 *
8260 * @param next_hop peer to receive the message next
8261 * @param total_hops how many hops did the message take so far
8262 * @param num_hops length of the @a hops array
8263 * @param origin origin of the message
8264 * @param hops next peer(s) to the destination, including destination
8265 * @param payload payload of the box
8266 * @param payload_size number of bytes in @a payload
8267 */
8268static void
8269forward_dv_box (struct Neighbour *next_hop,
8270 struct TransportDVBoxMessage *hdr,
8271 uint16_t total_hops,
8272 uint16_t num_hops,
8273 const struct GNUNET_PeerIdentity *hops,
8274 const void *enc_payload,
8275 uint16_t enc_payload_size)
8276{
8277 struct VirtualLink *vl = next_hop->vl;
8278 struct PendingMessage *pm;
8279 size_t msg_size = sizeof(struct TransportDVBoxMessage)
8280 + num_hops * sizeof(struct GNUNET_PeerIdentity)
8281 + enc_payload_size;
8282 char *buf;
8283 char msg_buf[msg_size] GNUNET_ALIGN;
8284 struct GNUNET_PeerIdentity *dhops;
8285
8286 hdr->num_hops = htons (num_hops);
8287 hdr->total_hops = htons (total_hops);
8288 hdr->header.size = htons (msg_size);
8289 memcpy (msg_buf, hdr, sizeof(*hdr));
8290 dhops = (struct GNUNET_PeerIdentity *) &msg_buf[sizeof(struct
8291 TransportDVBoxMessage)];
8292 memcpy (dhops, hops, num_hops * sizeof(struct GNUNET_PeerIdentity));
8293 memcpy (&dhops[num_hops], enc_payload, enc_payload_size);
8294
8295 if (GNUNET_YES == ntohs (hdr->without_fc))
8296 {
8297 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8298 "Forwarding control message (payload size %u) in DV Box to next hop %s (%u/%u) \n",
8299 enc_payload_size,
8300 GNUNET_i2s (&next_hop->pid),
8301 (unsigned int) num_hops,
8302 (unsigned int) total_hops);
8303 route_via_neighbour (next_hop, (const struct
8304 GNUNET_MessageHeader *) msg_buf,
8305 RMO_ANYTHING_GOES);
8306 }
8307 else
8308 {
8309 pm = GNUNET_malloc (sizeof(struct PendingMessage) + msg_size);
8310 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8311 "2 created pm %p storing vl %p \n",
8312 pm,
8313 vl);
8314 pm->pmt = PMT_DV_BOX;
8315 pm->vl = vl;
8316 pm->target = next_hop->pid;
8317 pm->timeout = GNUNET_TIME_relative_to_absolute (DV_FORWARD_TIMEOUT);
8318 pm->logging_uuid = logging_uuid_gen++;
8319 pm->prefs = GNUNET_MQ_PRIO_BACKGROUND;
8320 pm->bytes_msg = msg_size;
8321 buf = (char *) &pm[1];
8322 memcpy (buf, msg_buf, msg_size);
8323
8324 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8325 "Created pending message %" PRIu64
8326 " for DV Box with next hop %s (%u/%u)\n",
8327 pm->logging_uuid,
8328 GNUNET_i2s (&next_hop->pid),
8329 (unsigned int) num_hops,
8330 (unsigned int) total_hops);
8331
8332 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
8333 {
8334 GNUNET_CONTAINER_MDLL_insert (vl,
8335 vl->pending_msg_head,
8336 vl->pending_msg_tail,
8337 pm);
8338
8339 check_vl_transmission (vl);
8340 }
8341 else
8342 {
8343 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8344 "The virtual link is not ready for forwarding a DV Box with payload, storing PendingMessage in ring buffer.\n");
8345
8346 if (NULL != ring_buffer_dv[ring_buffer_dv_head])
8347 {
8348 struct PendingMessage *pm_old = ring_buffer_dv[ring_buffer_dv_head];
8349
8350 GNUNET_free (pm_old);
8351 }
8352 ring_buffer_dv[ring_buffer_dv_head] = pm;
8353 if (RING_BUFFER_SIZE - 1 == ring_buffer_dv_head)
8354 {
8355 ring_buffer_dv_head = 0;
8356 is_ring_buffer_dv_full = GNUNET_YES;
8357 }
8358 else
8359 ring_buffer_dv_head++;
8360
8361 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8362 "%u items stored in DV ring buffer\n",
8363 GNUNET_YES == is_ring_buffer_dv_full ? RING_BUFFER_SIZE :
8364 ring_buffer_dv_head);
8365 }
8366 }
8367}
8368
8369
8370/**
8371 * Free data structures associated with @a b.
8372 *
8373 * @param b data structure to release
8374 */
8375static void
8376free_backtalker (struct Backtalker *b)
8377{
8378 if (NULL != b->get)
8379 {
8380 GNUNET_PEERSTORE_iteration_stop (b->get);
8381 b->get = NULL;
8382 GNUNET_assert (NULL != b->cmc);
8383 finish_cmc_handling (b->cmc);
8384 b->cmc = NULL;
8385 }
8386 if (NULL != b->task)
8387 {
8388 GNUNET_SCHEDULER_cancel (b->task);
8389 b->task = NULL;
8390 }
8391 if (NULL != b->sc)
8392 {
8393 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8394 "store cancel\n");
8395 GNUNET_PEERSTORE_store_cancel (b->sc);
8396 b->sc = NULL;
8397 }
8398 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8399 "Removing backtalker for %s\n",
8400 GNUNET_i2s (&b->pid));
8401 GNUNET_assert (
8402 GNUNET_YES ==
8403 GNUNET_CONTAINER_multipeermap_remove (backtalkers, &b->pid, b));
8404 GNUNET_free (b);
8405}
8406
8407
8408/**
8409 * Callback to free backtalker records.
8410 *
8411 * @param cls NULL
8412 * @param pid unused
8413 * @param value a `struct Backtalker`
8414 * @return #GNUNET_OK (always)
8415 */
8416static int
8417free_backtalker_cb (void *cls,
8418 const struct GNUNET_PeerIdentity *pid,
8419 void *value)
8420{
8421 struct Backtalker *b = value;
8422
8423 (void) cls;
8424 (void) pid;
8425 free_backtalker (b);
8426 return GNUNET_OK;
8427}
8428
8429
8430/**
8431 * Function called when it is time to clean up a backtalker.
8432 *
8433 * @param cls a `struct Backtalker`
8434 */
8435static void
8436backtalker_timeout_cb (void *cls)
8437{
8438 struct Backtalker *b = cls;
8439
8440 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8441 "backtalker timeout.\n");
8442 b->task = NULL;
8443 if (0 != GNUNET_TIME_absolute_get_remaining (b->timeout).rel_value_us)
8444 {
8445 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8446 return;
8447 }
8448 GNUNET_assert (NULL == b->sc);
8449 free_backtalker (b);
8450}
8451
8452
8453/**
8454 * Function called with the monotonic time of a backtalker
8455 * by PEERSTORE. Updates the time and continues processing.
8456 *
8457 * @param cls a `struct Backtalker`
8458 * @param record the information found, NULL for the last call
8459 * @param emsg error message
8460 */
8461static void
8462backtalker_monotime_cb (void *cls,
8463 const struct GNUNET_PEERSTORE_Record *record,
8464 const char *emsg)
8465{
8466 struct Backtalker *b = cls;
8467 struct GNUNET_TIME_AbsoluteNBO *mtbe;
8468 struct GNUNET_TIME_Absolute mt;
8469
8470 (void) emsg;
8471 if (NULL == record)
8472 {
8473 /* we're done with #backtalker_monotime_cb() invocations,
8474 continue normal processing */
8475 b->get = NULL;
8476 GNUNET_assert (NULL != b->cmc);
8477 b->cmc->mh = (const struct GNUNET_MessageHeader *) &b[1];
8478 if (0 != b->body_size)
8479 demultiplex_with_cmc (b->cmc);
8480 else
8481 finish_cmc_handling (b->cmc);
8482 b->cmc = NULL;
8483 return;
8484 }
8485 if (sizeof(*mtbe) != record->value_size)
8486 {
8487 GNUNET_PEERSTORE_iteration_next (b->get, 1);
8488 GNUNET_break (0);
8489 return;
8490 }
8491 mtbe = record->value;
8492 mt = GNUNET_TIME_absolute_ntoh (*mtbe);
8493 if (mt.abs_value_us > b->monotonic_time.abs_value_us)
8494 {
8495 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8496 "Backtalker message from %s dropped, monotime in the past\n",
8497 GNUNET_i2s (&b->pid));
8498 GNUNET_STATISTICS_update (
8499 GST_stats,
8500 "# Backchannel messages dropped: monotonic time not increasing",
8501 1,
8502 GNUNET_NO);
8503 b->monotonic_time = mt;
8504 /* Setting body_size to 0 prevents call to #forward_backchannel_payload()
8505 */
8506 b->body_size = 0;
8507 }
8508 GNUNET_PEERSTORE_iteration_next (b->get, 1);
8509}
8510
8511
8512/**
8513 * Function called by PEERSTORE when the store operation of
8514 * a backtalker's monotonic time is complete.
8515 *
8516 * @param cls the `struct Backtalker`
8517 * @param success #GNUNET_OK on success
8518 */
8519static void
8520backtalker_monotime_store_cb (void *cls, int success)
8521{
8522 struct Backtalker *b = cls;
8523
8524 if (GNUNET_OK != success)
8525 {
8526 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8527 "Failed to store backtalker's monotonic time in PEERSTORE!\n");
8528 }
8529 b->sc = NULL;
8530 if (NULL != b->task)
8531 {
8532 GNUNET_SCHEDULER_cancel (b->task);
8533 b->task = NULL;
8534 }
8535 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8536}
8537
8538
8539/**
8540 * The backtalker @a b monotonic time changed. Update PEERSTORE.
8541 *
8542 * @param b a backtalker with updated monotonic time
8543 */
8544static void
8545update_backtalker_monotime (struct Backtalker *b)
8546{
8547 struct GNUNET_TIME_AbsoluteNBO mtbe;
8548
8549 if (NULL != b->sc)
8550 {
8551 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8552 "store cancel before store with sc %p\n",
8553 b->sc);
8554 /*GNUNET_PEERSTORE_store_cancel (b->sc);
8555 b->sc = NULL;*/
8556 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8557 "store cancel before store with sc %p is null\n",
8558 b->sc);
8559 }
8560 else
8561 {
8562 GNUNET_SCHEDULER_cancel (b->task);
8563 b->task = NULL;
8564 }
8565 mtbe = GNUNET_TIME_absolute_hton (b->monotonic_time);
8566 b->sc =
8567 GNUNET_PEERSTORE_store (peerstore,
8568 "transport",
8569 &b->pid,
8570 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
8571 &mtbe,
8572 sizeof(mtbe),
8573 GNUNET_TIME_UNIT_FOREVER_ABS,
8574 GNUNET_PEERSTORE_STOREOPTION_REPLACE,
8575 &backtalker_monotime_store_cb,
8576 b);
8577}
8578
8579
8580/**
8581 * Communicator gave us a DV box. Process the request.
8582 *
8583 * @param cls a `struct CommunicatorMessageContext` (must call
8584 * #finish_cmc_handling() when done)
8585 * @param dvb the message that was received
8586 */
8587static void
8588handle_dv_box (void *cls, const struct TransportDVBoxMessage *dvb)
8589{
8590 struct CommunicatorMessageContext *cmc = cls;
8591 uint16_t size = ntohs (dvb->header.size) - sizeof(*dvb);
8592 uint16_t num_hops = ntohs (dvb->num_hops);
8593 const struct GNUNET_PeerIdentity *hops =
8594 (const struct GNUNET_PeerIdentity *) &dvb[1];
8595 const char *enc_payload = (const char *) &hops[num_hops];
8596 uint16_t enc_payload_size =
8597 size - (num_hops * sizeof(struct GNUNET_PeerIdentity));
8598 struct DVKeyState key;
8599 struct GNUNET_HashCode hmac;
8600 const char *hdr;
8601 size_t hdr_len;
8602
8603 if (GNUNET_EXTRA_LOGGING > 0)
8604 {
8605 char *path;
8606
8607 path = GNUNET_strdup (GNUNET_i2s (&GST_my_identity));
8608 for (unsigned int i = 0; i < num_hops; i++)
8609 {
8610 char *tmp;
8611
8612 GNUNET_asprintf (&tmp, "%s->%s", path, GNUNET_i2s (&hops[i]));
8613 GNUNET_free (path);
8614 path = tmp;
8615 }
8616 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8617 "Received DVBox with remaining path %s\n",
8618 path);
8619 GNUNET_free (path);
8620 }
8621
8622 if (num_hops > 0)
8623 {
8624 /* We're trying from the end of the hops array, as we may be
8625 able to find a shortcut unknown to the origin that way */
8626 for (int i = num_hops - 1; i >= 0; i--)
8627 {
8628 struct Neighbour *n;
8629
8630 if (0 == GNUNET_memcmp (&hops[i], &GST_my_identity))
8631 {
8632 GNUNET_break_op (0);
8633 finish_cmc_handling (cmc);
8634 return;
8635 }
8636 n = lookup_neighbour (&hops[i]);
8637 if (NULL == n)
8638 continue;
8639 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8640 "Skipping %u/%u hops ahead while routing DV Box\n",
8641 i,
8642 num_hops);
8643
8644 forward_dv_box (n,
8645 (struct TransportDVBoxMessage *) dvb,
8646 ntohs (dvb->total_hops) + 1,
8647 num_hops - i - 1, /* number of hops left */
8648 &hops[i + 1], /* remaining hops */
8649 enc_payload,
8650 enc_payload_size);
8651 GNUNET_STATISTICS_update (GST_stats,
8652 "# DV hops skipped routing boxes",
8653 i,
8654 GNUNET_NO);
8655 GNUNET_STATISTICS_update (GST_stats,
8656 "# DV boxes routed (total)",
8657 1,
8658 GNUNET_NO);
8659 finish_cmc_handling (cmc);
8660 return;
8661 }
8662 /* Woopsie, next hop not in neighbours, drop! */
8663 GNUNET_STATISTICS_update (GST_stats,
8664 "# DV Boxes dropped: next hop unknown",
8665 1,
8666 GNUNET_NO);
8667 finish_cmc_handling (cmc);
8668 return;
8669 }
8670 /* We are the target. Unbox and handle message. */
8671 GNUNET_STATISTICS_update (GST_stats,
8672 "# DV boxes opened (ultimate target)",
8673 1,
8674 GNUNET_NO);
8675 cmc->total_hops = ntohs (dvb->total_hops);
8676
8677 // DH key derivation with received DV, could be garbage.
8678 struct GNUNET_HashCode km;
8679
8680 if (GNUNET_YES != GNUNET_CRYPTO_eddsa_kem_decaps (GST_my_private_key,
8681 &dvb->ephemeral_key,
8682 &km))
8683 {
8684 GNUNET_break_op (0);
8685 finish_cmc_handling (cmc);
8686 return;
8687 }
8688 dv_setup_key_state_from_km (&km, &dvb->iv, &key);
8689 hdr = (const char *) &dvb[1];
8690 hdr_len = ntohs (dvb->orig_size) - sizeof(*dvb) - sizeof(struct
8691 GNUNET_PeerIdentity)
8692 * ntohs (dvb->total_hops);
8693
8694 dv_hmac (&key, &hmac, hdr, hdr_len);
8695 if (0 != GNUNET_memcmp (&hmac, &dvb->hmac))
8696 {
8697 /* HMAC mismatch, discard! */
8698 GNUNET_break_op (0);
8699 finish_cmc_handling (cmc);
8700 return;
8701 }
8702 /* begin actual decryption */
8703 {
8704 struct Backtalker *b;
8705 struct GNUNET_TIME_Absolute monotime;
8706 struct TransportDVBoxPayloadP ppay;
8707 char body[hdr_len - sizeof(ppay)] GNUNET_ALIGN;
8708 const struct GNUNET_MessageHeader *mh;
8709
8710 GNUNET_assert (hdr_len >=
8711 sizeof(ppay) + sizeof(struct GNUNET_MessageHeader));
8712 if (GNUNET_OK != dv_decrypt (&key, &ppay, hdr, sizeof(ppay)))
8713 {
8714 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8715 "Error decrypting DV payload header\n");
8716 GNUNET_break_op (0);
8717 finish_cmc_handling (cmc);
8718 return;
8719 }
8720 if (GNUNET_OK != dv_decrypt (&key, body,
8721 &hdr[sizeof(ppay)], hdr_len - sizeof(ppay)))
8722 {
8723 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
8724 "Error decrypting DV payload\n");
8725 GNUNET_break_op (0);
8726 finish_cmc_handling (cmc);
8727 return;
8728 }
8729 mh = (const struct GNUNET_MessageHeader *) body;
8730 dv_key_clean (&key);
8731 if (ntohs (mh->size) != sizeof(body))
8732 {
8733 GNUNET_break_op (0);
8734 finish_cmc_handling (cmc);
8735 return;
8736 }
8737 /* need to prevent box-in-a-box (and DV_LEARN) so check inbox type! */
8738 switch (ntohs (mh->type))
8739 {
8740 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX:
8741 GNUNET_break_op (0);
8742 finish_cmc_handling (cmc);
8743 return;
8744
8745 case GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN:
8746 GNUNET_break_op (0);
8747 finish_cmc_handling (cmc);
8748 return;
8749
8750 default:
8751 /* permitted, continue */
8752 break;
8753 }
8754 monotime = GNUNET_TIME_absolute_ntoh (ppay.monotonic_time);
8755 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8756 "Decrypted backtalk from %s\n",
8757 GNUNET_i2s (&ppay.sender));
8758 b = GNUNET_CONTAINER_multipeermap_get (backtalkers, &ppay.sender);
8759 if ((NULL != b) && (monotime.abs_value_us < b->monotonic_time.abs_value_us))
8760 {
8761 GNUNET_STATISTICS_update (
8762 GST_stats,
8763 "# Backchannel messages dropped: monotonic time not increasing",
8764 1,
8765 GNUNET_NO);
8766 finish_cmc_handling (cmc);
8767 return;
8768 }
8769 if ((NULL == b) ||
8770 (0 != GNUNET_memcmp (&b->last_ephemeral, &dvb->ephemeral_key)))
8771 {
8772 /* Check signature */
8773 struct EphemeralConfirmationPS ec;
8774
8775 ec.purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL);
8776 ec.target = GST_my_identity;
8777 ec.ephemeral_key = dvb->ephemeral_key;
8778 ec.purpose.size = htonl (sizeof(ec));
8779 ec.sender_monotonic_time = ppay.monotonic_time;
8780 if (
8781 GNUNET_OK !=
8782 GNUNET_CRYPTO_eddsa_verify (
8783 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_EPHEMERAL,
8784 &ec,
8785 &ppay.sender_sig,
8786 &ppay.sender.public_key))
8787 {
8788 /* Signature invalid, discard! */
8789 GNUNET_break_op (0);
8790 finish_cmc_handling (cmc);
8791 return;
8792 }
8793 }
8794 /* Update sender, we now know the real origin! */
8795 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
8796 "DVBox received for me from %s via %s\n",
8797 GNUNET_i2s2 (&ppay.sender),
8798 GNUNET_i2s (&cmc->im.sender));
8799 cmc->im.sender = ppay.sender;
8800
8801 if (NULL != b)
8802 {
8803 /* update key cache and mono time */
8804 b->last_ephemeral = dvb->ephemeral_key;
8805 b->monotonic_time = monotime;
8806 update_backtalker_monotime (b);
8807 b->timeout =
8808 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8809 cmc->mh = mh;
8810 demultiplex_with_cmc (cmc);
8811 return;
8812 }
8813 /* setup data structure to cache signature AND check
8814 monotonic time with PEERSTORE before forwarding backchannel payload */
8815 b = GNUNET_malloc (sizeof(struct Backtalker) + sizeof(body));
8816 b->pid = ppay.sender;
8817 b->body_size = sizeof(body);
8818 memcpy (&b[1], body, sizeof(body));
8819 GNUNET_assert (GNUNET_YES ==
8820 GNUNET_CONTAINER_multipeermap_put (
8821 backtalkers,
8822 &b->pid,
8823 b,
8824 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
8825 b->monotonic_time = monotime; /* NOTE: to be checked still! */
8826 b->cmc = cmc;
8827 b->timeout =
8828 GNUNET_TIME_relative_to_absolute (BACKCHANNEL_INACTIVITY_TIMEOUT);
8829 b->task = GNUNET_SCHEDULER_add_at (b->timeout, &backtalker_timeout_cb, b);
8830 b->get =
8831 GNUNET_PEERSTORE_iteration_start (peerstore,
8832 "transport",
8833 &b->pid,
8834 GNUNET_PEERSTORE_TRANSPORT_BACKCHANNEL_MONOTIME,
8835 &backtalker_monotime_cb,
8836 b);
8837 } /* end actual decryption */
8838}
8839
8840
8841/**
8842 * Client notified us about transmission from a peer. Process the request.
8843 *
8844 * @param cls a `struct TransportClient` which sent us the message
8845 * @param im the send message that was sent
8846 * @return #GNUNET_YES if message is well-formed
8847 */
8848static int
8849check_incoming_msg (void *cls,
8850 const struct GNUNET_TRANSPORT_IncomingMessage *im)
8851{
8852 struct TransportClient *tc = cls;
8853
8854 if (CT_COMMUNICATOR != tc->type)
8855 {
8856 GNUNET_break (0);
8857 return GNUNET_SYSERR;
8858 }
8859 GNUNET_MQ_check_boxed_message (im);
8860 return GNUNET_OK;
8861}
8862
8863
8864/**
8865 * Closure for #check_known_address.
8866 */
8867struct CheckKnownAddressContext
8868{
8869 /**
8870 * Set to the address we are looking for.
8871 */
8872 const char *address;
8873
8874 /**
8875 * Set to a matching validation state, if one was found.
8876 */
8877 struct ValidationState *vs;
8878};
8879
8880
8881/**
8882 * Test if the validation state in @a value matches the
8883 * address from @a cls.
8884 *
8885 * @param cls a `struct CheckKnownAddressContext`
8886 * @param pid unused (must match though)
8887 * @param value a `struct ValidationState`
8888 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
8889 */
8890static int
8891check_known_address (void *cls,
8892 const struct GNUNET_PeerIdentity *pid,
8893 void *value)
8894{
8895 struct CheckKnownAddressContext *ckac = cls;
8896 struct ValidationState *vs = value;
8897
8898 (void) pid;
8899 if (0 != strcmp (vs->address, ckac->address))
8900 return GNUNET_OK;
8901 ckac->vs = vs;
8902 return GNUNET_NO;
8903}
8904
8905
8906/**
8907 * Task run periodically to validate some address based on #validation_heap.
8908 *
8909 * @param cls NULL
8910 */
8911static void
8912validation_start_cb (void *cls);
8913
8914
8915/**
8916 * Set the time for next_challenge of @a vs to @a new_time.
8917 * Updates the heap and if necessary reschedules the job.
8918 *
8919 * @param vs validation state to update
8920 * @param new_time new time for revalidation
8921 */
8922static void
8923update_next_challenge_time (struct ValidationState *vs,
8924 struct GNUNET_TIME_Absolute new_time)
8925{
8926 struct GNUNET_TIME_Relative delta;
8927
8928 if (new_time.abs_value_us == vs->next_challenge.abs_value_us)
8929 return; /* be lazy */
8930 vs->next_challenge = new_time;
8931 if (NULL == vs->hn)
8932 vs->hn =
8933 GNUNET_CONTAINER_heap_insert (validation_heap, vs, new_time.abs_value_us);
8934 else
8935 GNUNET_CONTAINER_heap_update_cost (vs->hn, new_time.abs_value_us);
8936 if ((vs != GNUNET_CONTAINER_heap_peek (validation_heap)) &&
8937 (NULL != validation_task))
8938 return;
8939 if (NULL != validation_task)
8940 GNUNET_SCHEDULER_cancel (validation_task);
8941 /* randomize a bit */
8942 delta.rel_value_us =
8943 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK,
8944 MIN_DELAY_ADDRESS_VALIDATION.rel_value_us);
8945 new_time = GNUNET_TIME_absolute_add (new_time, delta);
8946 validation_task =
8947 GNUNET_SCHEDULER_add_at (new_time, &validation_start_cb, NULL);
8948}
8949
8950
8951/**
8952 * Start address validation.
8953 *
8954 * @param pid peer the @a address is for
8955 * @param address an address to reach @a pid (presumably)
8956 */
8957static void
8958start_address_validation (const struct GNUNET_PeerIdentity *pid,
8959 const char *address)
8960{
8961 struct GNUNET_TIME_Absolute now;
8962 struct ValidationState *vs;
8963 struct CheckKnownAddressContext ckac = { .address = address, .vs = NULL };
8964
8965 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
8966 pid,
8967 &check_known_address,
8968 &ckac);
8969 if (NULL != (vs = ckac.vs))
8970 {
8971 /* if 'vs' is not currently valid, we need to speed up retrying the
8972 * validation */
8973 if (vs->validated_until.abs_value_us < vs->next_challenge.abs_value_us)
8974 {
8975 /* reduce backoff as we got a fresh advertisement */
8976 vs->challenge_backoff =
8977 GNUNET_TIME_relative_min (FAST_VALIDATION_CHALLENGE_FREQ,
8978 GNUNET_TIME_relative_divide (
8979 vs->challenge_backoff,
8980 2));
8981 update_next_challenge_time (vs,
8982 GNUNET_TIME_relative_to_absolute (
8983 vs->challenge_backoff));
8984 }
8985 return;
8986 }
8987 now = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
8988 vs = GNUNET_new (struct ValidationState);
8989 vs->pid = *pid;
8990 vs->valid_until =
8991 GNUNET_TIME_relative_to_absolute (ADDRESS_VALIDATION_LIFETIME);
8992 vs->first_challenge_use = now;
8993 vs->validation_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
8994 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
8995 &vs->challenge,
8996 sizeof(vs->challenge));
8997 vs->address = GNUNET_strdup (address);
8998 GNUNET_CRYPTO_hash (vs->address, strlen (vs->address), &vs->hc);
8999 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9000 "Starting address validation `%s' of peer %s using challenge %s\n",
9001 address,
9002 GNUNET_i2s (pid),
9003 GNUNET_sh2s (&vs->challenge.value));
9004 GNUNET_assert (GNUNET_YES ==
9005 GNUNET_CONTAINER_multipeermap_put (
9006 validation_map,
9007 &vs->pid,
9008 vs,
9009 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
9010 update_next_challenge_time (vs, now);
9011}
9012
9013
9014static struct Queue *
9015find_queue (const struct GNUNET_PeerIdentity *pid, const char *address);
9016
9017
9018static void
9019suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address);
9020
9021
9022static void
9023hello_for_incoming_cb (void *cls,
9024 const struct GNUNET_PeerIdentity *pid,
9025 const char *uri)
9026{
9027 (void) cls;
9028 struct Queue *q;
9029 int pfx_len;
9030 const char *eou;
9031 char *address;
9032
9033 eou = strstr (uri,
9034 "://");
9035 pfx_len = eou - uri;
9036 eou += 3;
9037 GNUNET_asprintf (&address,
9038 "%.*s-%s",
9039 pfx_len,
9040 uri,
9041 eou);
9042
9043 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9044 "helo for client %s\n",
9045 address);
9046 q = find_queue (pid, address);
9047 if (NULL == q)
9048 {
9049 suggest_to_connect (pid, address);
9050 }
9051 else
9052 start_address_validation (pid, address);
9053 GNUNET_free (address);
9054}
9055
9056
9057/**
9058 * Function called by PEERSTORE for each matching record.
9059 *
9060 * @param cls closure, a `struct IncomingRequest`
9061 * @param record peerstore record information
9062 * @param emsg error message, or NULL if no errors
9063 */
9064static void
9065handle_hello_for_incoming (void *cls,
9066 const struct GNUNET_PEERSTORE_Record *record,
9067 const char *emsg)
9068{
9069 struct IncomingRequest *ir = cls;
9070 struct GNUNET_HELLO_Builder *builder;
9071 struct GNUNET_MessageHeader *hello;
9072
9073 if (NULL != emsg)
9074 {
9075 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9076 "Got failure from PEERSTORE: %s\n",
9077 emsg);
9078 return;
9079 }
9080 hello = record->value;
9081 if (0 == GNUNET_memcmp (&record->peer, &GST_my_identity))
9082 {
9083 GNUNET_PEERSTORE_monitor_next (ir->nc, 1);
9084 return;
9085 }
9086 builder = GNUNET_HELLO_builder_from_msg (hello);
9087 GNUNET_HELLO_builder_iterate (builder,
9088 hello_for_incoming_cb,
9089 NULL);
9090 GNUNET_HELLO_builder_free (builder);
9091}
9092
9093
9094static void
9095hello_for_incoming_error_cb (void *cls)
9096{
9097 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9098 "Error in PEERSTORE monitoring\n");
9099}
9100
9101
9102static void
9103hello_for_incoming_sync_cb (void *cls)
9104{
9105 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
9106 "Done with initial PEERSTORE iteration during monitoring\n");
9107}
9108
9109
9110/**
9111 * Communicator gave us a transport address validation challenge. Process the
9112 * request.
9113 *
9114 * @param cls a `struct CommunicatorMessageContext` (must call
9115 * #finish_cmc_handling() when done)
9116 * @param tvc the message that was received
9117 */
9118static void
9119handle_validation_challenge (
9120 void *cls,
9121 const struct TransportValidationChallengeMessage *tvc)
9122{
9123 struct CommunicatorMessageContext *cmc = cls;
9124 struct TransportValidationResponseMessage tvr;
9125 struct VirtualLink *vl;
9126 struct GNUNET_TIME_RelativeNBO validity_duration;
9127 struct IncomingRequest *ir;
9128 struct Neighbour *n;
9129 struct GNUNET_PeerIdentity sender;
9130
9131 /* DV-routed messages are not allowed for validation challenges */
9132 if (cmc->total_hops > 0)
9133 {
9134 GNUNET_break_op (0);
9135 finish_cmc_handling (cmc);
9136 return;
9137 }
9138 validity_duration = cmc->im.expected_address_validity;
9139 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9140 "Received address validation challenge %s\n",
9141 GNUNET_sh2s (&tvc->challenge.value));
9142 /* If we have a virtual link, we use this mechanism to signal the
9143 size of the flow control window, and to allow the sender
9144 to ask for increases. If for us the virtual link is still down,
9145 we will always give a window size of zero. */
9146 tvr.header.type =
9147 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE);
9148 tvr.header.size = htons (sizeof(tvr));
9149 tvr.reserved = htonl (0);
9150 tvr.challenge = tvc->challenge;
9151 tvr.origin_time = tvc->sender_time;
9152 tvr.validity_duration = validity_duration;
9153 {
9154 /* create signature */
9155 struct TransportValidationPS tvp = {
9156 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
9157 .purpose.size = htonl (sizeof(tvp)),
9158 .validity_duration = validity_duration,
9159 .challenge = tvc->challenge
9160 };
9161
9162 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
9163 &tvp,
9164 &tvr.signature);
9165 }
9166 sender = cmc->im.sender;
9167 vl = lookup_virtual_link (&sender);
9168 if ((NULL != vl) && (GNUNET_YES == vl->confirmed))
9169 {
9170 // route_control_message_without_fc (&cmc->im.sender,
9171 route_control_message_without_fc (vl,
9172 &tvr.header,
9173 RMO_ANYTHING_GOES | RMO_REDUNDANT);
9174 }
9175 else
9176 {
9177 /* Use route via neighbour */
9178 n = lookup_neighbour (&sender);
9179 if (NULL != n)
9180 route_via_neighbour (n, &tvr.header,
9181 RMO_ANYTHING_GOES | RMO_REDUNDANT
9182 | RMO_UNCONFIRMED_ALLOWED);
9183 }
9184
9185 finish_cmc_handling (cmc);
9186 if (NULL != vl)
9187 return;
9188
9189 /* For us, the link is still down, but we need bi-directional
9190 connections (for flow-control and for this to be useful for
9191 CORE), so we must try to bring the link up! */
9192
9193 /* (1) Check existing queues, if any, we may be lucky! */
9194 n = lookup_neighbour (&sender);
9195 if (NULL != n)
9196 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
9197 start_address_validation (&sender, q->address);
9198 /* (2) Also try to see if we have addresses in PEERSTORE for this peer
9199 we could use */
9200 for (ir = ir_head; NULL != ir; ir = ir->next)
9201 if (0 == GNUNET_memcmp (&ir->pid, &sender))
9202 return;
9203 /* we are already trying */
9204 ir = GNUNET_new (struct IncomingRequest);
9205 ir->pid = sender;
9206 GNUNET_CONTAINER_DLL_insert (ir_head, ir_tail, ir);
9207
9208 ir->nc = GNUNET_PEERSTORE_monitor_start (GST_cfg,
9209 GNUNET_YES,
9210 "peerstore",
9211 NULL,
9212 GNUNET_PEERSTORE_HELLO_KEY,
9213 &hello_for_incoming_error_cb,
9214 NULL,
9215 &hello_for_incoming_sync_cb,
9216 NULL,
9217 &handle_hello_for_incoming,
9218 ir);
9219 ir_total++;
9220 /* Bound attempts we do in parallel here, might otherwise get excessive */
9221 while (ir_total > MAX_INCOMING_REQUEST)
9222 free_incoming_request (ir_head);
9223}
9224
9225
9226/**
9227 * Closure for #check_known_challenge.
9228 */
9229struct CheckKnownChallengeContext
9230{
9231 /**
9232 * Set to the challenge we are looking for.
9233 */
9234 const struct GNUNET_CRYPTO_ChallengeNonceP *challenge;
9235
9236 /**
9237 * Set to a matching validation state, if one was found.
9238 */
9239 struct ValidationState *vs;
9240};
9241
9242
9243/**
9244 * Test if the validation state in @a value matches the
9245 * challenge from @a cls.
9246 *
9247 * @param cls a `struct CheckKnownChallengeContext`
9248 * @param pid unused (must match though)
9249 * @param value a `struct ValidationState`
9250 * @return #GNUNET_OK if not matching, #GNUNET_NO if match found
9251 */
9252static int
9253check_known_challenge (void *cls,
9254 const struct GNUNET_PeerIdentity *pid,
9255 void *value)
9256{
9257 struct CheckKnownChallengeContext *ckac = cls;
9258 struct ValidationState *vs = value;
9259
9260 (void) pid;
9261 if (0 != GNUNET_memcmp (&vs->challenge, ckac->challenge))
9262 return GNUNET_OK;
9263 ckac->vs = vs;
9264 return GNUNET_NO;
9265}
9266
9267
9268/**
9269 * Function called when peerstore is done storing a
9270 * validated address.
9271 *
9272 * @param cls a `struct ValidationState`
9273 * @param success #GNUNET_YES on success
9274 */
9275static void
9276peerstore_store_validation_cb (void *cls, int success)
9277{
9278 struct ValidationState *vs = cls;
9279
9280 vs->sc = NULL;
9281 if (GNUNET_YES == success)
9282 return;
9283 GNUNET_STATISTICS_update (GST_stats,
9284 "# Peerstore failed to store foreign address",
9285 1,
9286 GNUNET_NO);
9287}
9288
9289
9290/**
9291 * Find the queue matching @a pid and @a address.
9292 *
9293 * @param pid peer the queue must go to
9294 * @param address address the queue must use
9295 * @return NULL if no such queue exists
9296 */
9297static struct Queue *
9298find_queue (const struct GNUNET_PeerIdentity *pid, const char *address)
9299{
9300 struct Neighbour *n;
9301
9302 n = lookup_neighbour (pid);
9303 if (NULL == n)
9304 return NULL;
9305 for (struct Queue *pos = n->queue_head; NULL != pos;
9306 pos = pos->next_neighbour)
9307 {
9308 if (0 == strcmp (pos->address, address))
9309 return pos;
9310 }
9311 return NULL;
9312}
9313
9314
9315static void
9316validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs);
9317
9318static void
9319revalidation_start_cb (void *cls)
9320{
9321 struct ValidationState *vs = cls;
9322 struct Queue *q;
9323 struct GNUNET_TIME_Absolute now;
9324
9325 vs->revalidation_task = NULL;
9326 q = find_queue (&vs->pid, vs->address);
9327 if (NULL == q)
9328 {
9329 now = GNUNET_TIME_absolute_get ();
9330 vs->awaiting_queue = GNUNET_YES;
9331 suggest_to_connect (&vs->pid, vs->address);
9332 update_next_challenge_time (vs, now);
9333 }
9334 else
9335 validation_transmit_on_queue (q, vs);
9336}
9337
9338
9339static enum GNUNET_GenericReturnValue
9340revalidate_map_it (
9341 void *cls,
9342 const struct GNUNET_HashCode *key,
9343 void *value)
9344{
9345 (void) cls;
9346 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9347 "Key in revalidate map %s \n",
9348 GNUNET_h2s (key));
9349 return GNUNET_YES;
9350}
9351
9352
9353/**
9354 * Communicator gave us a transport address validation response. Process the
9355 * request.
9356 *
9357 * @param cls a `struct CommunicatorMessageContext` (must call
9358 * #finish_cmc_handling() when done)
9359 * @param tvr the message that was received
9360 */
9361static void
9362handle_validation_response (
9363 void *cls,
9364 const struct TransportValidationResponseMessage *tvr)
9365{
9366 struct CommunicatorMessageContext *cmc = cls;
9367 struct ValidationState *vs;
9368 struct CheckKnownChallengeContext ckac = { .challenge = &tvr->challenge,
9369 .vs = NULL};
9370 struct GNUNET_TIME_Absolute origin_time;
9371 struct Queue *q;
9372 struct Neighbour *n;
9373 struct VirtualLink *vl;
9374 const struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get_monotonic (
9375 GST_cfg);
9376
9377 /* check this is one of our challenges */
9378 (void) GNUNET_CONTAINER_multipeermap_get_multiple (validation_map,
9379 &cmc->im.sender,
9380 &check_known_challenge,
9381 &ckac);
9382 if (NULL == (vs = ckac.vs))
9383 {
9384 /* This can happen simply if we 'forgot' the challenge by now,
9385 i.e. because we received the validation response twice */
9386 GNUNET_STATISTICS_update (GST_stats,
9387 "# Validations dropped, challenge unknown",
9388 1,
9389 GNUNET_NO);
9390 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9391 "Validation response %s dropped, challenge unknown\n",
9392 GNUNET_sh2s (&tvr->challenge.value));
9393 finish_cmc_handling (cmc);
9394 return;
9395 }
9396
9397 /* sanity check on origin time */
9398 origin_time = GNUNET_TIME_absolute_ntoh (tvr->origin_time);
9399 if ((origin_time.abs_value_us < vs->first_challenge_use.abs_value_us) ||
9400 (origin_time.abs_value_us > vs->last_challenge_use.abs_value_us))
9401 {
9402 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9403 "Diff first use %" PRIu64 " and last use %" PRIu64 "\n",
9404 vs->first_challenge_use.abs_value_us - origin_time.abs_value_us,
9405 origin_time.abs_value_us - vs->last_challenge_use.abs_value_us);
9406 GNUNET_break_op (0);
9407 finish_cmc_handling (cmc);
9408 return;
9409 }
9410
9411 {
9412 /* check signature */
9413 struct TransportValidationPS tvp = {
9414 .purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE),
9415 .purpose.size = htonl (sizeof(tvp)),
9416 .validity_duration = tvr->validity_duration,
9417 .challenge = tvr->challenge
9418 };
9419
9420 if (
9421 GNUNET_OK !=
9422 GNUNET_CRYPTO_eddsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_CHALLENGE,
9423 &tvp,
9424 &tvr->signature,
9425 &cmc->im.sender.public_key))
9426 {
9427 GNUNET_break_op (0);
9428 finish_cmc_handling (cmc);
9429 return;
9430 }
9431 }
9432
9433 /* validity is capped by our willingness to keep track of the
9434 validation entry and the maximum the other peer allows */
9435 vs->valid_until = GNUNET_TIME_relative_to_absolute (
9436 GNUNET_TIME_relative_min (GNUNET_TIME_relative_ntoh (
9437 tvr->validity_duration),
9438 MAX_ADDRESS_VALID_UNTIL));
9439 vs->validated_until =
9440 GNUNET_TIME_absolute_min (vs->valid_until,
9441 GNUNET_TIME_relative_to_absolute (
9442 ADDRESS_VALIDATION_LIFETIME));
9443 vs->validation_rtt = GNUNET_TIME_absolute_get_duration (origin_time);
9444 vs->challenge_backoff = GNUNET_TIME_UNIT_ZERO;
9445 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9446 &vs->challenge,
9447 sizeof(vs->challenge));
9448 vs->first_challenge_use = GNUNET_TIME_absolute_subtract (
9449 vs->validated_until,
9450 GNUNET_TIME_relative_multiply (vs->validation_rtt,
9451 VALIDATION_RTT_BUFFER_FACTOR));
9452 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, <, now))
9453 {
9454 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9455 "First challenge use is now %" PRIu64 " %s \n",
9456 vs->first_challenge_use.abs_value_us,
9457 GNUNET_sh2s (&vs->challenge.value));
9458 vs->first_challenge_use = now;
9459 }
9460 else
9461 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9462 "First challenge use is later %" PRIu64 " %s \n",
9463 vs->first_challenge_use.abs_value_us,
9464 GNUNET_sh2s (&vs->challenge.value));
9465 vs->last_challenge_use =
9466 GNUNET_TIME_UNIT_ZERO_ABS; /* challenge was not yet used */
9467 update_next_challenge_time (vs, vs->first_challenge_use);
9468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9469 "Validation response %s from %s accepted, address valid until %s\n",
9470 GNUNET_sh2s (&tvr->challenge.value),
9471 GNUNET_i2s (&cmc->im.sender),
9472 GNUNET_STRINGS_absolute_time_to_string (vs->valid_until));
9473 /*memcpy (&hkey,
9474 &hc,
9475 sizeof (hkey));*/
9476 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9477 "Key %s for address %s map size %u contains %u\n",
9478 GNUNET_h2s (&vs->hc),
9479 vs->address,
9480 GNUNET_CONTAINER_multihashmap_size (revalidation_map),
9481 GNUNET_CONTAINER_multihashmap_contains (revalidation_map,
9482 &vs->hc));
9483 GNUNET_assert (GNUNET_YES ==
9484 GNUNET_CONTAINER_multihashmap_put (
9485 revalidation_map,
9486 &vs->hc,
9487 vs,
9488 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9489 GNUNET_CONTAINER_multihashmap_iterate (revalidation_map,
9490 revalidate_map_it,
9491 NULL);
9492 vs->revalidation_task =
9493 GNUNET_SCHEDULER_add_at (GNUNET_TIME_absolute_subtract (vs->next_challenge,
9494 GNUNET_TIME_UNIT_MINUTES),
9495 &revalidation_start_cb, vs);
9496 vs->sc = GNUNET_PEERSTORE_store (peerstore,
9497 "transport",
9498 &cmc->im.sender,
9499 GNUNET_PEERSTORE_TRANSPORT_URLADDRESS_KEY,
9500 vs->address,
9501 strlen (vs->address) + 1,
9502 vs->valid_until,
9503 GNUNET_PEERSTORE_STOREOPTION_MULTIPLE,
9504 &peerstore_store_validation_cb,
9505 vs);
9506 finish_cmc_handling (cmc);
9507
9508 /* Finally, we now possibly have a confirmed (!) working queue,
9509 update queue status (if queue still is around) */
9510 q = find_queue (&vs->pid, vs->address);
9511 if (NULL == q)
9512 {
9513 GNUNET_STATISTICS_update (GST_stats,
9514 "# Queues lost at time of successful validation",
9515 1,
9516 GNUNET_NO);
9517 return;
9518 }
9519 q->validated_until = vs->validated_until;
9520 q->pd.aged_rtt = vs->validation_rtt;
9521 n = q->neighbour;
9522 vl = lookup_virtual_link (&vs->pid);
9523 if (NULL == vl)
9524 {
9525 vl = GNUNET_new (struct VirtualLink);
9526 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9527 "Creating new virtual link %p to %s using direct neighbour!\n",
9528 vl,
9529 GNUNET_i2s (&vs->pid));
9530 vl->confirmed = GNUNET_YES;
9531 vl->message_uuid_ctr =
9532 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
9533 vl->target = n->pid;
9534 vl->core_recv_window = RECV_WINDOW_SIZE;
9535 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
9536 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
9537 GNUNET_break (GNUNET_YES ==
9538 GNUNET_CONTAINER_multipeermap_put (
9539 links,
9540 &vl->target,
9541 vl,
9542 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9543 vl->n = n;
9544 n->vl = vl;
9545 q->idle = GNUNET_YES;
9546 vl->visibility_task =
9547 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
9548 consider_sending_fc (vl);
9549 /* We lacked a confirmed connection to the target
9550 before, so tell CORE about it (finally!) */
9551 cores_send_connect_info (&n->pid);
9552 send_msg_from_cache (vl);
9553 }
9554 else
9555 {
9556 /* Link was already up, remember n is also now available and we are done */
9557 if (NULL == vl->n)
9558 {
9559 vl->n = n;
9560 n->vl = vl;
9561 if (GNUNET_YES == vl->confirmed)
9562 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9563 "Virtual link to %s could now also use direct neighbour!\n",
9564 GNUNET_i2s (&vs->pid));
9565 }
9566 else
9567 {
9568 GNUNET_assert (n == vl->n);
9569 }
9570 if (GNUNET_NO == vl->confirmed)
9571 {
9572 vl->confirmed = GNUNET_YES;
9573 q->idle = GNUNET_YES;
9574 vl->visibility_task =
9575 GNUNET_SCHEDULER_add_at (q->validated_until, &check_link_down, vl);
9576 consider_sending_fc (vl);
9577 /* We lacked a confirmed connection to the target
9578 before, so tell CORE about it (finally!) */
9579 cores_send_connect_info (&n->pid);
9580 send_msg_from_cache (vl);
9581 }
9582 }
9583}
9584
9585
9586/**
9587 * Incoming meessage. Process the request.
9588 *
9589 * @param im the send message that was received
9590 */
9591static void
9592handle_incoming_msg (void *cls,
9593 const struct GNUNET_TRANSPORT_IncomingMessage *im)
9594{
9595 struct TransportClient *tc = cls;
9596 struct CommunicatorMessageContext *cmc =
9597 GNUNET_new (struct CommunicatorMessageContext);
9598
9599 cmc->tc = tc;
9600 cmc->im = *im;
9601 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9602 "Received message with size %u and flow control id %" PRIu64
9603 " via communicator from peer %s\n",
9604 ntohs (im->header.size),
9605 im->fc_id,
9606 GNUNET_i2s (&im->sender));
9607 cmc->im.neighbour_sender = cmc->im.sender;
9608 cmc->mh = (const struct GNUNET_MessageHeader *) &im[1];
9609 demultiplex_with_cmc (cmc);
9610}
9611
9612/**
9613 * Communicator gave us a transport address validation response. Check the
9614 * request.
9615 *
9616 * @param cls a `struct CommunicatorMessageContext`
9617 * @param fc the message that was received
9618 * @return #GNUNET_YES if message is well-formed
9619 */
9620static int
9621check_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
9622{
9623 (void) cls;
9624 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
9625
9626 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9627 "Flow control header size %u size of addresses %u number of addresses %u size of message struct %lu second struct %lu\n",
9628 ntohs (fc->header.size),
9629 ntohl (fc->size_of_addresses),
9630 ntohl (fc->number_of_addresses),
9631 sizeof(struct TransportFlowControlMessage),
9632 sizeof (struct TransportGlobalNattedAddress));
9633
9634 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))
9635 return GNUNET_OK;
9636 else
9637 {
9638 GNUNET_break_op (0);
9639 return GNUNET_SYSERR;
9640 }
9641}
9642
9643/**
9644 * Communicator gave us a transport address validation response. Process the
9645 * request.
9646 *
9647 * @param cls a `struct CommunicatorMessageContext` (must call
9648 * #finish_cmc_handling() when done)
9649 * @param fc the message that was received
9650 */
9651static void
9652handle_flow_control (void *cls, const struct TransportFlowControlMessage *fc)
9653{
9654 struct CommunicatorMessageContext *cmc = cls;
9655 struct VirtualLink *vl;
9656 uint32_t seq;
9657 struct GNUNET_TIME_Absolute st;
9658 uint64_t os;
9659 uint64_t wnd;
9660 uint32_t random;
9661
9662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9663 "Received FC from %s\n", GNUNET_i2s (&cmc->im.sender));
9664 vl = lookup_virtual_link (&cmc->im.sender);
9665 if (NULL == vl)
9666 {
9667 vl = GNUNET_new (struct VirtualLink);
9668 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9669 "No virtual link for %p FC creating new unconfirmed virtual link to %s!\n",
9670 vl,
9671 GNUNET_i2s (&cmc->im.sender));
9672 vl->confirmed = GNUNET_NO;
9673 vl->message_uuid_ctr =
9674 GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, UINT64_MAX);
9675 vl->target = cmc->im.sender;
9676 vl->core_recv_window = RECV_WINDOW_SIZE;
9677 vl->available_fc_window_size = DEFAULT_WINDOW_SIZE;
9678 vl->incoming_fc_window_size = DEFAULT_WINDOW_SIZE;
9679 GNUNET_break (GNUNET_YES ==
9680 GNUNET_CONTAINER_multipeermap_put (
9681 links,
9682 &vl->target,
9683 vl,
9684 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9685 }
9686 if (0 != ntohl (fc->number_of_addresses))
9687 {
9688 unsigned int number_of_addresses = ntohl (fc->number_of_addresses);
9689 const char *tgnas;
9690 unsigned int off = 0;
9691
9692 tgnas = (const char *) &fc[1];
9693
9694 for (int i = 1; i <= number_of_addresses; i++)
9695 {
9696 struct TransportGlobalNattedAddress *tgna = (struct TransportGlobalNattedAddress *) &tgnas[off];
9697 char *addr = (char *) &tgna[1];
9698 unsigned int address_length;
9699
9700 address_length = ntohl (tgna->address_length);
9701 off += sizeof(struct TransportGlobalNattedAddress) + address_length;
9702
9703 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9704 "received address %s length %u\n",
9705 addr,
9706 ntohl (tgna->address_length));
9707
9708 GNUNET_NAT_add_global_address (nh, addr, ntohl (tgna->address_length));
9709 }
9710 }
9711 st = GNUNET_TIME_absolute_ntoh (fc->sender_time);
9712 if (st.abs_value_us < vl->last_fc_timestamp.abs_value_us)
9713 {
9714 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9715 "FC dropped: Message out of order\n");
9716 /* out of order, drop */
9717 GNUNET_STATISTICS_update (GST_stats,
9718 "# FC dropped: message out of order",
9719 1,
9720 GNUNET_NO);
9721 finish_cmc_handling (cmc);
9722 return;
9723 }
9724 seq = ntohl (fc->seq);
9725 if (seq < vl->last_fc_seq)
9726 {
9727 /* Wrap-around/reset of other peer; start all counters from zero */
9728 vl->outbound_fc_window_size_used = 0;
9729 }
9730 vl->last_fc_seq = seq;
9731 vl->last_fc_timestamp = st;
9732 vl->outbound_fc_window_size = GNUNET_ntohll (fc->inbound_window_size);
9733 os = GNUNET_ntohll (fc->outbound_sent);
9734 vl->incoming_fc_window_size_loss =
9735 (int64_t) (os - vl->incoming_fc_window_size_used);
9736 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9737 "Received FC from %s, seq %u, new window %llu (loss at %lld)\n",
9738 GNUNET_i2s (&vl->target),
9739 (unsigned int) seq,
9740 (unsigned long long) vl->outbound_fc_window_size,
9741 (long long) vl->incoming_fc_window_size_loss);
9742 wnd = GNUNET_ntohll (fc->outbound_window_size);
9743 random = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
9744 UINT32_MAX);
9745 if ((GNUNET_YES == vl->confirmed) && ((wnd < vl->incoming_fc_window_size
9746 + vl->incoming_fc_window_size_used
9747 + vl->incoming_fc_window_size_loss) ||
9748 (vl->last_outbound_window_size_received
9749 != wnd) ||
9750 (0 == random
9751 % FC_NO_CHANGE_REPLY_PROBABILITY)))
9752 {
9753 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9754 "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",
9755 (unsigned long long) wnd,
9756 (unsigned long long) vl->incoming_fc_window_size,
9757 (unsigned long long) vl->last_outbound_window_size_received,
9758 random % FC_NO_CHANGE_REPLY_PROBABILITY);
9759 consider_sending_fc (vl);
9760 }
9761 if ((wnd == vl->incoming_fc_window_size
9762 + vl->incoming_fc_window_size_used
9763 + vl->incoming_fc_window_size_loss) &&
9764 (vl->last_outbound_window_size_received == wnd) &&
9765 (NULL != vl->fc_retransmit_task))
9766 {
9767 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9768 "Stopping FC retransmission to %s: peer is current at window %llu\n",
9769 GNUNET_i2s (&vl->target),
9770 (unsigned long long) wnd);
9771 GNUNET_SCHEDULER_cancel (vl->fc_retransmit_task);
9772 vl->fc_retransmit_task = NULL;
9773 vl->fc_retransmit_count = 0;
9774 }
9775 vl->last_outbound_window_size_received = wnd;
9776 /* FC window likely increased, check transmission possibilities! */
9777 check_vl_transmission (vl);
9778 finish_cmc_handling (cmc);
9779}
9780
9781
9782/**
9783 * Given an inbound message @a msg from a communicator @a cmc,
9784 * demultiplex it based on the type calling the right handler.
9785 *
9786 * @param cmc context for demultiplexing
9787 * @param msg message to demultiplex
9788 */
9789static void
9790demultiplex_with_cmc (struct CommunicatorMessageContext *cmc)
9791{
9792 struct GNUNET_MQ_MessageHandler handlers[] =
9793 { GNUNET_MQ_hd_var_size (fragment_box,
9794 GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT,
9795 struct TransportFragmentBoxMessage,
9796 cmc),
9797 GNUNET_MQ_hd_var_size (reliability_box,
9798 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX,
9799 struct TransportReliabilityBoxMessage,
9800 cmc),
9801 GNUNET_MQ_hd_var_size (reliability_ack,
9802 GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_ACK,
9803 struct TransportReliabilityAckMessage,
9804 cmc),
9805 GNUNET_MQ_hd_var_size (backchannel_encapsulation,
9806 GNUNET_MESSAGE_TYPE_TRANSPORT_BACKCHANNEL_ENCAPSULATION,
9807 struct TransportBackchannelEncapsulationMessage,
9808 cmc),
9809 GNUNET_MQ_hd_var_size (dv_learn,
9810 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN,
9811 struct TransportDVLearnMessage,
9812 cmc),
9813 GNUNET_MQ_hd_var_size (dv_box,
9814 GNUNET_MESSAGE_TYPE_TRANSPORT_DV_BOX,
9815 struct TransportDVBoxMessage,
9816 cmc),
9817 GNUNET_MQ_hd_var_size (flow_control,
9818 GNUNET_MESSAGE_TYPE_TRANSPORT_FLOW_CONTROL,
9819 struct TransportFlowControlMessage,
9820 cmc),
9821 GNUNET_MQ_hd_fixed_size (
9822 validation_challenge,
9823 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE,
9824 struct TransportValidationChallengeMessage,
9825 cmc),
9826 GNUNET_MQ_hd_fixed_size (
9827 validation_response,
9828 GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_RESPONSE,
9829 struct TransportValidationResponseMessage,
9830 cmc),
9831 GNUNET_MQ_handler_end () };
9832 int ret;
9833 const struct GNUNET_MessageHeader *msg = cmc->mh;
9834
9835 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9836 "Handling message of type %u with %u bytes\n",
9837 (unsigned int) ntohs (msg->type),
9838 (unsigned int) ntohs (msg->size));
9839 ret = GNUNET_MQ_handle_message (handlers, msg);
9840 if (GNUNET_SYSERR == ret)
9841 {
9842 GNUNET_break (0);
9843 GNUNET_SERVICE_client_drop (cmc->tc->client);
9844 GNUNET_free (cmc);
9845 return;
9846 }
9847 if (GNUNET_NO == ret)
9848 {
9849 /* unencapsulated 'raw' message */
9850 handle_raw_message (cmc, msg);
9851 }
9852}
9853
9854
9855/**
9856 * New queue became available. Check message.
9857 *
9858 * @param cls the client
9859 * @param aqm the send message that was sent
9860 */
9861static int
9862check_add_queue_message (void *cls,
9863 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
9864{
9865 struct TransportClient *tc = cls;
9866
9867 if (CT_COMMUNICATOR != tc->type)
9868 {
9869 GNUNET_break (0);
9870 return GNUNET_SYSERR;
9871 }
9872 GNUNET_MQ_check_zero_termination (aqm);
9873 return GNUNET_OK;
9874}
9875
9876
9877/**
9878 * If necessary, generates the UUID for a @a pm
9879 *
9880 * @param pm pending message to generate UUID for.
9881 */
9882static void
9883set_pending_message_uuid (struct PendingMessage *pm)
9884{
9885 if (pm->msg_uuid_set)
9886 return;
9887 pm->msg_uuid.uuid = pm->vl->message_uuid_ctr++;
9888 pm->msg_uuid_set = GNUNET_YES;
9889}
9890
9891
9892/**
9893 * Setup data structure waiting for acknowledgements.
9894 *
9895 * @param queue queue the @a pm will be sent over
9896 * @param dvh path the message will take, may be NULL
9897 * @param pm the pending message for transmission
9898 * @return corresponding fresh pending acknowledgement
9899 */
9900static struct PendingAcknowledgement *
9901prepare_pending_acknowledgement (struct Queue *queue,
9902 struct DistanceVectorHop *dvh,
9903 struct PendingMessage *pm)
9904{
9905 struct PendingAcknowledgement *pa;
9906
9907 pa = GNUNET_new (struct PendingAcknowledgement);
9908 pa->queue = queue;
9909 pa->dvh = dvh;
9910 pa->pm = pm;
9911 do
9912 {
9913 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
9914 &pa->ack_uuid,
9915 sizeof(pa->ack_uuid));
9916 }
9917 while (GNUNET_YES != GNUNET_CONTAINER_multiuuidmap_put (
9918 pending_acks,
9919 &pa->ack_uuid.value,
9920 pa,
9921 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
9922 GNUNET_CONTAINER_MDLL_insert (queue, queue->pa_head, queue->pa_tail, pa);
9923 GNUNET_CONTAINER_MDLL_insert (pm, pm->pa_head, pm->pa_tail, pa);
9924 if (NULL != dvh)
9925 GNUNET_CONTAINER_MDLL_insert (dvh, dvh->pa_head, dvh->pa_tail, pa);
9926 pa->transmission_time = GNUNET_TIME_absolute_get ();
9927 pa->message_size = pm->bytes_msg;
9928 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9929 "Waiting for ACKnowledgment `%s' for <%" PRIu64 ">\n",
9930 GNUNET_uuid2s (&pa->ack_uuid.value),
9931 pm->logging_uuid);
9932 return pa;
9933}
9934
9935
9936/**
9937 * Fragment the given @a pm to the given @a mtu. Adds
9938 * additional fragments to the neighbour as well. If the
9939 * @a mtu is too small, generates and error for the @a pm
9940 * and returns NULL.
9941 *
9942 * @param queue which queue to fragment for
9943 * @param dvh path the message will take, or NULL
9944 * @param pm pending message to fragment for transmission
9945 * @return new message to transmit
9946 */
9947static struct PendingMessage *
9948fragment_message (struct Queue *queue,
9949 struct DistanceVectorHop *dvh,
9950 struct PendingMessage *pm)
9951{
9952 struct PendingAcknowledgement *pa;
9953 struct PendingMessage *ff;
9954 uint16_t mtu;
9955 uint16_t msize;
9956
9957 mtu = (UINT16_MAX == queue->mtu)
9958 ? UINT16_MAX - sizeof(struct GNUNET_TRANSPORT_SendMessageTo)
9959 : queue->mtu;
9960 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9961 "Fragmenting message <%" PRIu64
9962 "> with size %u to %s for MTU %u\n",
9963 pm->logging_uuid,
9964 pm->bytes_msg,
9965 GNUNET_i2s (&pm->vl->target),
9966 (unsigned int) mtu);
9967 set_pending_message_uuid (pm);
9968 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
9969 "Fragmenting message %" PRIu64 " <%" PRIu64
9970 "> with size %u to %s for MTU %u\n",
9971 pm->msg_uuid.uuid,
9972 pm->logging_uuid,
9973 pm->bytes_msg,
9974 GNUNET_i2s (&pm->vl->target),
9975 (unsigned int) mtu);
9976
9977 /* This invariant is established in #handle_add_queue_message() */
9978 GNUNET_assert (mtu > sizeof(struct TransportFragmentBoxMessage));
9979
9980 /* select fragment for transmission, descending the tree if it has
9981 been expanded until we are at a leaf or at a fragment that is small
9982 enough
9983 */
9984 ff = pm;
9985 msize = ff->bytes_msg;
9986
9987 while (((ff->bytes_msg > mtu) || (pm == ff)) &&
9988 (ff->frag_off == msize) && (NULL != ff->head_frag))
9989 {
9990 ff = ff->head_frag; /* descent into fragmented fragments */
9991 msize = ff->bytes_msg - sizeof(struct TransportFragmentBoxMessage);
9992 }
9993
9994 if (((ff->bytes_msg > mtu) || (pm == ff)) && (ff->frag_off < msize))
9995 {
9996 /* Did not yet calculate all fragments, calculate next fragment */
9997 struct PendingMessage *frag;
9998 struct TransportFragmentBoxMessage tfb;
9999 const char *orig;
10000 char *msg;
10001 uint16_t fragmax;
10002 uint16_t fragsize;
10003 uint16_t msize;
10004 uint16_t xoff = 0;
10005 pm->frag_count++;
10006
10007 orig = (const char *) &ff[1];
10008 msize = ff->bytes_msg;
10009 if (pm != ff)
10010 {
10011 const struct TransportFragmentBoxMessage *tfbo;
10012
10013 tfbo = (const struct TransportFragmentBoxMessage *) orig;
10014 orig += sizeof(struct TransportFragmentBoxMessage);
10015 msize -= sizeof(struct TransportFragmentBoxMessage);
10016 xoff = ntohs (tfbo->frag_off);
10017 }
10018 fragmax = mtu - sizeof(struct TransportFragmentBoxMessage);
10019 fragsize = GNUNET_MIN (msize - ff->frag_off, fragmax);
10020 frag =
10021 GNUNET_malloc (sizeof(struct PendingMessage)
10022 + sizeof(struct TransportFragmentBoxMessage) + fragsize);
10023 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10024 "3 created pm %p from pm %p storing vl %p from pm %p\n",
10025 frag,
10026 ff,
10027 pm->vl,
10028 pm);
10029 frag->logging_uuid = logging_uuid_gen++;
10030 frag->vl = pm->vl;
10031 frag->frag_parent = ff;
10032 frag->timeout = pm->timeout;
10033 frag->bytes_msg = sizeof(struct TransportFragmentBoxMessage) + fragsize;
10034 frag->pmt = PMT_FRAGMENT_BOX;
10035 msg = (char *) &frag[1];
10036 tfb.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_FRAGMENT);
10037 tfb.header.size =
10038 htons (sizeof(struct TransportFragmentBoxMessage) + fragsize);
10039 pa = prepare_pending_acknowledgement (queue, dvh, frag);
10040 tfb.ack_uuid = pa->ack_uuid;
10041 tfb.msg_uuid = pm->msg_uuid;
10042 tfb.frag_off = htons (ff->frag_off + xoff);
10043 tfb.msg_size = htons (pm->bytes_msg);
10044 memcpy (msg, &tfb, sizeof(tfb));
10045 memcpy (&msg[sizeof(tfb)], &orig[ff->frag_off], fragsize);
10046 GNUNET_CONTAINER_MDLL_insert (frag, ff->head_frag,
10047 ff->tail_frag, frag);
10048 ff->frag_off += fragsize;
10049 ff = frag;
10050 }
10051
10052 /* Move head to the tail and return it */
10053 GNUNET_CONTAINER_MDLL_remove (frag,
10054 ff->frag_parent->head_frag,
10055 ff->frag_parent->tail_frag,
10056 ff);
10057 GNUNET_CONTAINER_MDLL_insert_tail (frag,
10058 ff->frag_parent->head_frag,
10059 ff->frag_parent->tail_frag,
10060 ff);
10061
10062 return ff;
10063}
10064
10065
10066/**
10067 * Reliability-box the given @a pm. On error (can there be any), NULL
10068 * may be returned, otherwise the "replacement" for @a pm (which
10069 * should then be added to the respective neighbour's queue instead of
10070 * @a pm). If the @a pm is already fragmented or reliability boxed,
10071 * or itself an ACK, this function simply returns @a pm.
10072 *
10073 * @param queue which queue to prepare transmission for
10074 * @param dvh path the message will take, or NULL
10075 * @param pm pending message to box for transmission over unreliabile queue
10076 * @return new message to transmit
10077 */
10078static struct PendingMessage *
10079reliability_box_message (struct Queue *queue,
10080 struct DistanceVectorHop *dvh,
10081 struct PendingMessage *pm)
10082{
10083 struct TransportReliabilityBoxMessage rbox;
10084 struct PendingAcknowledgement *pa;
10085 struct PendingMessage *bpm;
10086 char *msg;
10087
10088 if ((PMT_CORE != pm->pmt) && (PMT_DV_BOX != pm->pmt))
10089 return pm; /* already fragmented or reliability boxed, or control message:
10090 do nothing */
10091 if (NULL != pm->bpm)
10092 return pm->bpm; /* already computed earlier: do nothing */
10093 // TODO I guess we do not need this assertion. We might have a DLL with
10094 // fragments, because the MTU changed, and we do not need to fragment anymore.
10095 // But we should keep the fragments until message was completed, because
10096 // the MTU might change again.
10097 // GNUNET_assert (NULL == pm->head_frag);
10098 if (pm->bytes_msg + sizeof(rbox) > UINT16_MAX)
10099 {
10100 /* failed hard */
10101 GNUNET_break (0);
10102 client_send_response (pm);
10103 return NULL;
10104 }
10105
10106 pa = prepare_pending_acknowledgement (queue, dvh, pm);
10107
10108 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + sizeof(rbox)
10109 + pm->bytes_msg);
10110 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10111 "4 created pm %p storing vl %p from pm %p\n",
10112 bpm,
10113 pm->vl,
10114 pm);
10115 bpm->logging_uuid = logging_uuid_gen++;
10116 bpm->vl = pm->vl;
10117 bpm->frag_parent = pm;
10118 // Why was this needed?
10119 // GNUNET_CONTAINER_MDLL_insert (frag, pm->head_frag, pm->tail_frag, bpm);
10120 bpm->timeout = pm->timeout;
10121 bpm->pmt = PMT_RELIABILITY_BOX;
10122 bpm->bytes_msg = pm->bytes_msg + sizeof(rbox);
10123 set_pending_message_uuid (bpm);
10124 rbox.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RELIABILITY_BOX);
10125 rbox.header.size = htons (sizeof(rbox) + pm->bytes_msg);
10126 rbox.ack_countdown = htonl (0); // FIXME: implement ACK countdown support
10127
10128 rbox.ack_uuid = pa->ack_uuid;
10129 msg = (char *) &bpm[1];
10130 memcpy (msg, &rbox, sizeof(rbox));
10131 memcpy (&msg[sizeof(rbox)], &pm[1], pm->bytes_msg);
10132 pm->bpm = bpm;
10133 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10134 "Preparing reliability box for message <%" PRIu64
10135 "> of size %d (%d) to %s on queue %s\n",
10136 pm->logging_uuid,
10137 pm->bytes_msg,
10138 ntohs (((const struct GNUNET_MessageHeader *) &pm[1])->size),
10139 GNUNET_i2s (&pm->vl->target),
10140 queue->address);
10141 return bpm;
10142}
10143
10144
10145static void
10146reorder_root_pm (struct PendingMessage *pm,
10147 struct GNUNET_TIME_Absolute next_attempt)
10148{
10149 struct VirtualLink *vl = pm->vl;
10150 struct PendingMessage *pos;
10151
10152 /* re-insert sort in neighbour list */
10153 GNUNET_CONTAINER_MDLL_remove (vl,
10154 vl->pending_msg_head,
10155 vl->pending_msg_tail,
10156 pm);
10157 pos = vl->pending_msg_tail;
10158 while ((NULL != pos) &&
10159 (next_attempt.abs_value_us > pos->next_attempt.abs_value_us))
10160 pos = pos->prev_vl;
10161 GNUNET_CONTAINER_MDLL_insert_after (vl,
10162 vl->pending_msg_head,
10163 vl->pending_msg_tail,
10164 pos,
10165 pm);
10166}
10167
10168
10169static unsigned int
10170check_next_attempt_tree (struct PendingMessage *pm, struct PendingMessage *root)
10171{
10172 struct PendingMessage *pos;
10173 enum GNUNET_GenericReturnValue frags_in_flight;
10174
10175 pos = pm->head_frag;
10176 while (NULL != pos)
10177 {
10178 if (pos->frags_in_flight_round == pm->frags_in_flight_round ||
10179 GNUNET_NO == check_next_attempt_tree (pos, root))
10180 frags_in_flight = GNUNET_NO;
10181 else
10182 {
10183 frags_in_flight = GNUNET_YES;
10184 break;
10185 }
10186 pos = pos->next_frag;
10187 }
10188
10189 return frags_in_flight;
10190}
10191
10192
10193static void
10194harmonize_flight_round (struct PendingMessage *pm)
10195{
10196 struct PendingMessage *pos;
10197
10198 pos = pm->head_frag;
10199 while (NULL != pos)
10200 {
10201 pos->frags_in_flight_round = pm->frags_in_flight_round;
10202 harmonize_flight_round (pos);
10203 pos = pos->next_frag;
10204 }
10205}
10206
10207
10208/**
10209 * Change the value of the `next_attempt` field of @a pm
10210 * to @a next_attempt and re-order @a pm in the transmission
10211 * list as required by the new timestamp.
10212 *
10213 * @param pm a pending message to update
10214 * @param next_attempt timestamp to use
10215 */
10216static void
10217update_pm_next_attempt (struct PendingMessage *pm,
10218 struct GNUNET_TIME_Absolute next_attempt)
10219{
10220 if (NULL == pm->frag_parent)
10221 {
10222 pm->next_attempt = next_attempt;
10223 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10224 "Next attempt for message <%" PRIu64 "> set to %" PRIu64 "\n",
10225 pm->logging_uuid,
10226 next_attempt.abs_value_us);
10227 reorder_root_pm (pm, next_attempt);
10228 }
10229 else if ((PMT_RELIABILITY_BOX == pm->pmt) || (PMT_DV_BOX == pm->pmt))// || (PMT_FRAGMENT_BOX == pm->pmt))
10230 {
10231 struct PendingMessage *root = pm->frag_parent;
10232
10233 while (NULL != root->frag_parent)
10234 root = root->frag_parent;
10235 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10236 "Next attempt for root message <%" PRIu64 "> set to %s\n",
10237 root->logging_uuid,
10238 GNUNET_STRINGS_absolute_time_to_string (next_attempt));
10239 root->next_attempt = next_attempt;
10240 reorder_root_pm (root, next_attempt);
10241 }
10242 else
10243 {
10244 struct PendingMessage *root = pm->frag_parent;
10245
10246 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
10247 root = root->frag_parent;
10248
10249 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10250 "frag_count next atempt %u\n",
10251 root->frag_count);
10252
10253 if (GNUNET_NO == root->frags_in_flight)
10254 {
10255 root->next_attempt = next_attempt;
10256 harmonize_flight_round (root);
10257 root->frags_in_flight_round++;
10258 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10259 "Next attempt for fragmented message <%" PRIu64 "> (<%" PRIu64
10260 ">)set to %" PRIu64 "\n",
10261 pm->logging_uuid,
10262 root->logging_uuid,
10263 next_attempt.abs_value_us);
10264 }
10265
10266 pm->next_attempt = root->next_attempt;
10267 pm->frags_in_flight_round = root->frags_in_flight_round;
10268 harmonize_flight_round (pm);
10269
10270 if (root->bytes_msg == root->frag_off)
10271 root->frags_in_flight = check_next_attempt_tree (root, root);
10272 else
10273 root->frags_in_flight = GNUNET_YES;
10274
10275 if (GNUNET_NO == root->frags_in_flight)
10276 {
10277 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10278 "We have no fragments in flight for message %" PRIu64
10279 ", reorder root! Next attempt is %" PRIu64 "\n",
10280 root->logging_uuid,
10281 root->next_attempt.abs_value_us);
10282 if (PMT_DV_BOX == root->pmt)
10283 root = root->frag_parent;
10284 reorder_root_pm (root, root->next_attempt);
10285 // root->next_attempt = GNUNET_TIME_UNIT_ZERO_ABS;
10286 }
10287 else
10288 {
10289 double factor = ((double) root->frag_count - 1)
10290 / (double) root->frag_count;
10291 struct GNUNET_TIME_Relative s1;
10292 struct GNUNET_TIME_Relative s2;
10293 struct GNUNET_TIME_Relative plus_mean =
10294 GNUNET_TIME_absolute_get_remaining (root->next_attempt);
10295 struct GNUNET_TIME_Relative plus = GNUNET_TIME_absolute_get_remaining (
10296 next_attempt);
10297
10298 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10299 "frag_count %u after factor\n",
10300 root->frag_count);
10301 s1 = GNUNET_TIME_relative_multiply_double (plus_mean,
10302 factor);
10303 s2 = GNUNET_TIME_relative_divide (plus,
10304 root->frag_count);
10305 plus_mean = GNUNET_TIME_relative_add (s1, s2);
10306 root->next_attempt = GNUNET_TIME_relative_to_absolute (plus_mean);
10307 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10308 "We have fragments in flight for message %" PRIu64
10309 ", do not reorder root! Actual next attempt %" PRIu64 "\n",
10310 root->logging_uuid,
10311 root->next_attempt.abs_value_us);
10312 }
10313 }
10314}
10315
10316
10317/**
10318 * Context for #select_best_pending_from_link().
10319 */
10320struct PendingMessageScoreContext
10321{
10322 /**
10323 * Set to the best message that was found, NULL for none.
10324 */
10325 struct PendingMessage *best;
10326
10327 /**
10328 * DVH that @e best should take, or NULL for direct transmission.
10329 */
10330 struct DistanceVectorHop *dvh;
10331
10332 /**
10333 * What is the estimated total overhead for this message?
10334 */
10335 size_t real_overhead;
10336
10337 /**
10338 * Number of pending messages we seriously considered this time.
10339 */
10340 unsigned int consideration_counter;
10341
10342 /**
10343 * Did we have to fragment?
10344 */
10345 int frag;
10346
10347 /**
10348 * Did we have to reliability box?
10349 */
10350 int relb;
10351
10352 /**
10353 * There are pending messages, but it was to early to send one of them.
10354 */
10355 int to_early;
10356
10357 /**
10358 * There is a pending messages we are sending fragments at the moment.
10359 */
10360 unsigned int frags_in_flight;
10361
10362 /**
10363 * When will we try to transmit the message again for which it was to early to retry.
10364 */
10365 struct GNUNET_TIME_Relative to_early_retry_delay;
10366};
10367
10368
10369/**
10370 * Select the best pending message from @a vl for transmission
10371 * via @a queue.
10372 *
10373 * @param[in,out] sc best message so far (NULL for none), plus scoring data
10374 * @param queue the queue that will be used for transmission
10375 * @param vl the virtual link providing the messages
10376 * @param dvh path we are currently considering, or NULL for none
10377 * @param overhead number of bytes of overhead to be expected
10378 * from DV encapsulation (0 for without DV)
10379 */
10380static void
10381select_best_pending_from_link (struct PendingMessageScoreContext *sc,
10382 struct Queue *queue,
10383 struct VirtualLink *vl,
10384 struct DistanceVectorHop *dvh,
10385 size_t overhead)
10386{
10387 struct GNUNET_TIME_Absolute now;
10388
10389 now = GNUNET_TIME_absolute_get ();
10390 sc->to_early = GNUNET_NO;
10391 sc->frags_in_flight = GNUNET_NO;
10392 for (struct PendingMessage *pos = vl->pending_msg_head; NULL != pos;
10393 pos = pos->next_vl)
10394 {
10395 size_t real_overhead = overhead;
10396 int frag;
10397 int relb;
10398
10399 if ((NULL != dvh) && (PMT_DV_BOX == pos->pmt))
10400 {
10401 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10402 "DV messages must not be DV-routed to next hop!\n");
10403 continue; /* DV messages must not be DV-routed to next hop! */
10404 }
10405 if (pos->next_attempt.abs_value_us > now.abs_value_us)
10406 {
10407 if (GNUNET_YES == pos->frags_in_flight)
10408 {
10409 sc->frags_in_flight = GNUNET_YES;
10410 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10411 "Fragments in flight for message %" PRIu64 "\n",
10412 pos->logging_uuid);
10413 }
10414 else
10415 {
10416 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10417 "Maybe too early, because message are sorted by next_attempt, if there are no fragments in flight.Checked message %"
10418 PRIu64 "\n",
10419 pos->logging_uuid);
10420 sc->to_early = GNUNET_YES;
10421 sc->to_early_retry_delay = GNUNET_TIME_absolute_get_remaining (
10422 pos->next_attempt);
10423 continue;
10424 }
10425 // break; /* too early for all messages, they are sorted by next_attempt */
10426 }
10427 if (NULL != pos->qe)
10428 {
10429 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10430 "not eligible\n");
10431 continue; /* not eligible */
10432 }
10433 sc->consideration_counter++;
10434 /* determine if we have to fragment, if so add fragmentation
10435 overhead! */
10436 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10437 "check %" PRIu64 " for sc->best\n",
10438 pos->logging_uuid);
10439 frag = GNUNET_NO;
10440 if (((0 != queue->mtu) &&
10441 (pos->bytes_msg + real_overhead > queue->mtu)) ||
10442 (pos->bytes_msg > UINT16_MAX - sizeof(struct
10443 GNUNET_TRANSPORT_SendMessageTo))
10444 ||
10445 (NULL != pos->head_frag /* fragments already exist, should
10446 respect that even if MTU is UINT16_MAX for
10447 this queue */))
10448 {
10449 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10450 "fragment msg with size %u, realoverhead is %lu\n",
10451 pos->bytes_msg,
10452 real_overhead);
10453 frag = GNUNET_YES;
10454 if (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc)
10455 {
10456 /* FIXME-FRAG-REL-UUID: we could use an optimized, shorter fragmentation
10457 header without the ACK UUID when using a *reliable* channel! */
10458 }
10459 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
10460 }
10461 /* determine if we have to reliability-box, if so add reliability box
10462 overhead */
10463 relb = GNUNET_NO;
10464 if ((GNUNET_NO == frag) &&
10465 (0 == (pos->prefs & GNUNET_MQ_PREF_UNRELIABLE)) &&
10466 (GNUNET_TRANSPORT_CC_RELIABLE != queue->tc->details.communicator.cc))
10467 {
10468 real_overhead += sizeof(struct TransportReliabilityBoxMessage);
10469
10470 if ((0 != queue->mtu) && (pos->bytes_msg + real_overhead > queue->mtu))
10471 {
10472 frag = GNUNET_YES;
10473 real_overhead = overhead + sizeof(struct TransportFragmentBoxMessage);
10474 }
10475 else
10476 {
10477 relb = GNUNET_YES;
10478 }
10479 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10480 "Create reliability box of msg with size %u, realoverhead is %lu %u %u %u\n",
10481 pos->bytes_msg,
10482 real_overhead,
10483 queue->mtu,
10484 frag,
10485 relb);
10486 }
10487
10488 /* Finally, compare to existing 'best' in sc to see if this 'pos' pending
10489 message would beat it! */
10490 if (GNUNET_NO == sc->frags_in_flight && NULL != sc->best)
10491 {
10492 /* CHECK if pos fits queue BETTER (=smaller) than pm, if not: continue;
10493 OPTIMIZE-ME: This is a heuristic, which so far has NOT been
10494 experimentally validated. There may be some huge potential for
10495 improvement here. Also, we right now only compare how well the
10496 given message fits _this_ queue, and do not consider how well other
10497 queues might suit the message. Taking other queues into consideration
10498 may further improve the result, but could also be expensive
10499 in terms of CPU time. */
10500 long long sc_score = sc->frag * 40 + sc->relb * 20 + sc->real_overhead;
10501 long long pm_score = frag * 40 + relb * 20 + real_overhead;
10502 long long time_delta =
10503 (sc->best->next_attempt.abs_value_us - pos->next_attempt.abs_value_us)
10504 / 1000LL;
10505
10506 /* "time_delta" considers which message has been 'ready' for transmission
10507 for longer, if a message has a preference for low latency, increase
10508 the weight of the time_delta by 10x if it is favorable for that message */
10509 if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
10510 (0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)))
10511 time_delta *= 10; /* increase weight (always, both are low latency) */
10512 else if ((0 != (pos->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
10513 (time_delta > 0))
10514 time_delta *= 10; /* increase weight, favors 'pos', which is low latency */
10515 else if ((0 != (sc->best->prefs & GNUNET_MQ_PREF_LOW_LATENCY)) &&
10516 (time_delta < 0))
10517 time_delta *= 10; /* increase weight, favors 'sc->best', which is low latency */
10518 if (0 != queue->mtu)
10519 {
10520 /* Grant bonus if we are below MTU, larger bonus the closer we will
10521 be to the MTU */
10522 if (queue->mtu > sc->real_overhead + sc->best->bytes_msg)
10523 sc_score -= queue->mtu - (sc->real_overhead + sc->best->bytes_msg);
10524 if (queue->mtu > real_overhead + pos->bytes_msg)
10525 pm_score -= queue->mtu - (real_overhead + pos->bytes_msg);
10526 }
10527 if (sc_score + time_delta > pm_score)
10528 {
10529 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10530 "sc_score of %" PRIu64 " larger, keep sc->best %" PRIu64
10531 "\n",
10532 pos->logging_uuid,
10533 sc->best->logging_uuid);
10534 continue; /* sc_score larger, keep sc->best */
10535 }
10536 }
10537 sc->best = pos;
10538 sc->dvh = dvh;
10539 sc->frag = frag;
10540 sc->relb = relb;
10541 sc->real_overhead = real_overhead;
10542 }
10543}
10544
10545
10546/**
10547 * Function to call to further operate on the now DV encapsulated
10548 * message @a hdr, forwarding it via @a next_hop under respect of
10549 * @a options.
10550 *
10551 * @param cls a `struct PendingMessageScoreContext`
10552 * @param next_hop next hop of the DV path
10553 * @param hdr encapsulated message, technically a `struct TransportDVBoxMessage`
10554 * @param options options of the original message
10555 */
10556static void
10557extract_box_cb (void *cls,
10558 struct Neighbour *next_hop,
10559 const struct GNUNET_MessageHeader *hdr,
10560 enum RouteMessageOptions options)
10561{
10562 struct PendingMessageScoreContext *sc = cls;
10563 struct PendingMessage *pm = sc->best;
10564 struct PendingMessage *bpm;
10565 uint16_t bsize = ntohs (hdr->size);
10566
10567 GNUNET_assert (NULL == pm->bpm);
10568 bpm = GNUNET_malloc (sizeof(struct PendingMessage) + bsize);
10569 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10570 "5 created pm %p storing vl %p from pm %p\n",
10571 bpm,
10572 pm->vl,
10573 pm);
10574 bpm->logging_uuid = logging_uuid_gen++;
10575 bpm->pmt = PMT_DV_BOX;
10576 bpm->vl = pm->vl;
10577 bpm->timeout = pm->timeout;
10578 bpm->bytes_msg = bsize;
10579 bpm->frag_parent = pm;
10580 set_pending_message_uuid (bpm);
10581 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10582 "Creating DV Box %" PRIu64 " for original message %" PRIu64
10583 " (next hop is %s)\n",
10584 bpm->logging_uuid,
10585 pm->logging_uuid,
10586 GNUNET_i2s (&next_hop->pid));
10587 memcpy (&bpm[1], hdr, bsize);
10588 pm->bpm = bpm;
10589}
10590
10591
10592/**
10593 * We believe we are ready to transmit a `struct PendingMessage` on a
10594 * queue, the big question is which one! We need to see if there is
10595 * one pending that is allowed by flow control and congestion control
10596 * and (ideally) matches our queue's performance profile.
10597 *
10598 * If such a message is found, we give the message to the communicator
10599 * for transmission (updating the tracker, and re-scheduling ourselves
10600 * if applicable).
10601 *
10602 * If no such message is found, the queue's `idle` field must be set
10603 * to #GNUNET_YES.
10604 *
10605 * @param cls the `struct Queue` to process transmissions for
10606 */
10607static void
10608transmit_on_queue (void *cls)
10609{
10610 struct Queue *queue = cls;
10611 struct Neighbour *n = queue->neighbour;
10612 struct PendingMessageScoreContext sc;
10613 struct PendingMessage *pm;
10614
10615 queue->transmit_task = NULL;
10616 if (NULL == n->vl)
10617 {
10618 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10619 "Virtual link `%s' is down, cannot have PM for queue `%s'\n",
10620 GNUNET_i2s (&n->pid),
10621 queue->address);
10622 queue->idle = GNUNET_YES;
10623 return;
10624 }
10625 memset (&sc, 0, sizeof(sc));
10626 select_best_pending_from_link (&sc, queue, n->vl, NULL, 0);
10627 if (NULL == sc.best)
10628 {
10629 /* Also look at DVH that have the n as first hop! */
10630 for (struct DistanceVectorHop *dvh = n->dv_head; NULL != dvh;
10631 dvh = dvh->next_neighbour)
10632 {
10633 select_best_pending_from_link (&sc,
10634 queue,
10635 dvh->dv->vl,
10636 dvh,
10637 sizeof(struct GNUNET_PeerIdentity)
10638 * (1 + dvh->distance)
10639 + sizeof(struct TransportDVBoxMessage)
10640 + sizeof(struct TransportDVBoxPayloadP));
10641 }
10642 }
10643 if (NULL == sc.best)
10644 {
10645 /* no message pending, nothing to do here! */
10646 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10647 "No pending messages, queue `%s' to %s now idle\n",
10648 queue->address,
10649 GNUNET_i2s (&n->pid));
10650 if (GNUNET_YES == sc.to_early)
10651 schedule_transmit_on_queue (sc.to_early_retry_delay,
10652 queue,
10653 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10654 queue->idle = GNUNET_YES;
10655 return;
10656 }
10657 /* There is a message pending, we are certainly not idle */
10658 queue->idle = GNUNET_NO;
10659
10660 /* Given selection in `sc`, do transmission */
10661 pm = sc.best;
10662 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10663 "Selected message <%" PRIu64 ">\n",
10664 pm->logging_uuid);
10665 if (NULL != sc.dvh)
10666 {
10667 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10668 "Is this %u a DV box?\n",
10669 pm->pmt);
10670 GNUNET_assert (PMT_DV_BOX != pm->pmt);
10671 if ((NULL != sc.best->bpm) && (sc.best->bpm->used_dvh != sc.dvh))
10672 {
10673 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10674 "Discard old box, because we have a new DV path.\n");
10675 free_pending_message (sc.best->bpm);
10676 sc.best->bpm = NULL;
10677 }
10678
10679 if (NULL == sc.best->bpm)
10680 {
10681 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10682 "encapsulate_for_dv 2\n");
10683 encapsulate_for_dv (sc.dvh->dv,
10684 1,
10685 &sc.dvh,
10686 (const struct GNUNET_MessageHeader *) &sc.best[1],
10687 &extract_box_cb,
10688 &sc,
10689 RMO_NONE,
10690 GNUNET_NO);
10691 GNUNET_assert (NULL != sc.best->bpm);
10692 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10693 "%lu %lu %lu %lu %u\n",
10694 sizeof(struct GNUNET_PeerIdentity),
10695 sizeof(struct TransportDVBoxMessage),
10696 sizeof(struct TransportDVBoxPayloadP),
10697 sizeof(struct TransportFragmentBoxMessage),
10698 ((const struct GNUNET_MessageHeader *) &sc.best[1])->size);
10699 sc.best->bpm->used_dvh = sc.dvh;
10700 }
10701 pm = sc.best->bpm;
10702 }
10703 if (GNUNET_YES == sc.frag)
10704 {
10705 pm = fragment_message (queue, sc.dvh, pm);
10706 if (NULL == pm)
10707 {
10708 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10709 "Fragmentation failed queue %s to %s for <%" PRIu64
10710 ">, trying again\n",
10711 queue->address,
10712 GNUNET_i2s (&n->pid),
10713 sc.best->logging_uuid);
10714 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10715 queue,
10716 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10717 return;
10718 }
10719 }
10720 else if (GNUNET_YES == sc.relb)
10721 {
10722 pm = reliability_box_message (queue, sc.dvh, pm);
10723 if (NULL == pm)
10724 {
10725 /* Reliability boxing failed, try next message... */
10726 GNUNET_log (
10727 GNUNET_ERROR_TYPE_DEBUG,
10728 "Reliability boxing failed queue %s to %s for <%" PRIu64
10729 ">, trying again\n",
10730 queue->address,
10731 GNUNET_i2s (&n->pid),
10732 sc.best->logging_uuid);
10733 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10734 queue,
10735 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10736 return;
10737 }
10738 }
10739
10740 /* Pass 'pm' for transission to the communicator */
10741 GNUNET_log (
10742 GNUNET_ERROR_TYPE_DEBUG,
10743 "Passing message <%" PRIu64
10744 "> to queue %s for peer %s (considered %u others)\n",
10745 pm->logging_uuid,
10746 queue->address,
10747 GNUNET_i2s (&n->pid),
10748 sc.consideration_counter);
10749
10750 /* Flow control: increment amount of traffic sent; if we are routing
10751 via DV (and thus the ultimate target of the pending message is for
10752 a different virtual link than the one of the queue), then we need
10753 to use up not only the window of the direct link but also the
10754 flow control window for the DV link! */
10755 pm->vl->outbound_fc_window_size_used += pm->bytes_msg;
10756
10757 if (pm->vl != queue->neighbour->vl)
10758 {
10759 /* If the virtual link of the queue differs, this better be distance
10760 vector routing! */
10761 GNUNET_assert (NULL != sc.dvh);
10762 /* If we do distance vector routing, we better not do this for a
10763 message that was itself DV-routed */
10764 GNUNET_assert (PMT_DV_BOX != sc.best->pmt);
10765 /* We use the size of the unboxed message here, to avoid counting
10766 the DV-Box header which is eaten up on the way by intermediaries */
10767 queue->neighbour->vl->outbound_fc_window_size_used += sc.best->bytes_msg;
10768 }
10769 else
10770 {
10771 GNUNET_assert (NULL == sc.dvh);
10772 }
10773
10774 queue_send_msg (queue, pm, &pm[1], pm->bytes_msg);
10775
10776 /* Check if this transmission somehow conclusively finished handing 'pm'
10777 even without any explicit ACKs */
10778 if ((PMT_CORE == pm->pmt) ||
10779 (GNUNET_TRANSPORT_CC_RELIABLE == queue->tc->details.communicator.cc))
10780 {
10781 completed_pending_message (pm);
10782 }
10783 else
10784 {
10785 struct GNUNET_TIME_Relative wait_duration;
10786 unsigned int wait_multiplier;
10787
10788 if (PMT_FRAGMENT_BOX == pm->pmt)
10789 {
10790 struct PendingMessage *root;
10791
10792 root = pm->frag_parent;
10793 while (NULL != root->frag_parent && PMT_DV_BOX != root->pmt)
10794 root = root->frag_parent;
10795
10796 wait_multiplier = (unsigned int) ceil ((double) root->bytes_msg
10797 / ((double) root->frag_off
10798 / (double) root->frag_count))
10799 * 4;
10800 }
10801 else
10802 {
10803 // No fragments, we use 4 RTT before retransmitting.
10804 wait_multiplier = 4;
10805 }
10806
10807 // Depending on how much pending message the VirtualLink is queueing, we wait longer.
10808 // wait_multiplier = wait_multiplier * pm->vl->pending_msg_num;
10809
10810 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10811 "Wait multiplier %u\n",
10812 wait_multiplier);
10813
10814 /* Message not finished, waiting for acknowledgement.
10815 Update time by which we might retransmit 's' based on queue
10816 characteristics (i.e. RTT); it takes one RTT for the message to
10817 arrive and the ACK to come back in the best case; but the other
10818 side is allowed to delay ACKs by 2 RTTs, so we use 4 RTT before
10819 retransmitting.
10820
10821 OPTIMIZE: Note that in the future this heuristic should likely
10822 be improved further (measure RTT stability, consider message
10823 urgency and size when delaying ACKs, etc.) */
10824
10825 if (GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us !=
10826 queue->pd.aged_rtt.rel_value_us)
10827 wait_duration = queue->pd.aged_rtt;
10828 else
10829 {
10830 wait_duration = DEFAULT_ACK_WAIT_DURATION;
10831 wait_multiplier = 4;
10832 }
10833 struct GNUNET_TIME_Absolute next = GNUNET_TIME_relative_to_absolute (
10834 GNUNET_TIME_relative_multiply (
10835 wait_duration, wait_multiplier));
10836 struct GNUNET_TIME_Relative plus = GNUNET_TIME_relative_multiply (
10837 wait_duration, wait_multiplier);
10838 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10839 "Waiting %s for ACK until %s\n",
10840 GNUNET_STRINGS_relative_time_to_string (plus, GNUNET_NO),
10841 GNUNET_STRINGS_absolute_time_to_string (next));
10842 update_pm_next_attempt (pm,
10843 GNUNET_TIME_relative_to_absolute (
10844 GNUNET_TIME_relative_multiply (wait_duration,
10845 wait_multiplier)));
10846 }
10847 /* finally, re-schedule queue transmission task itself */
10848 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10849 queue,
10850 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10851}
10852
10853
10854/**
10855 * Queue to a peer went down. Process the request.
10856 *
10857 * @param cls the client
10858 * @param dqm the send message that was sent
10859 */
10860static void
10861handle_del_queue_message (void *cls,
10862 const struct GNUNET_TRANSPORT_DelQueueMessage *dqm)
10863{
10864 struct TransportClient *tc = cls;
10865
10866 if (CT_COMMUNICATOR != tc->type)
10867 {
10868 GNUNET_break (0);
10869 GNUNET_SERVICE_client_drop (tc->client);
10870 return;
10871 }
10872 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
10873 queue = queue->next_client)
10874 {
10875 struct Neighbour *neighbour = queue->neighbour;
10876
10877 if ((ntohl (dqm->qid) != queue->qid) ||
10878 (0 != GNUNET_memcmp (&dqm->receiver, &neighbour->pid)))
10879 continue;
10880 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10881 "Dropped queue %s to peer %s\n",
10882 queue->address,
10883 GNUNET_i2s (&neighbour->pid));
10884 free_queue (queue);
10885 GNUNET_SERVICE_client_continue (tc->client);
10886 return;
10887 }
10888 GNUNET_break (0);
10889 GNUNET_SERVICE_client_drop (tc->client);
10890}
10891
10892
10893static void
10894free_queue_entry (struct QueueEntry *qe,
10895 struct TransportClient *tc)
10896{
10897 struct PendingMessage *pm;
10898
10899 GNUNET_CONTAINER_DLL_remove (qe->queue->queue_head,
10900 qe->queue->queue_tail,
10901 qe);
10902 qe->queue->queue_length--;
10903 tc->details.communicator.total_queue_length--;
10904 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10905 "Received ACK on queue %s (QID %u) to peer %s (new length: %u/%u)\n",
10906 qe->queue->address,
10907 qe->queue->qid,
10908 GNUNET_i2s (&qe->queue->neighbour->pid),
10909 qe->queue->queue_length,
10910 tc->details.communicator.total_queue_length);
10911
10912 /* if applicable, resume transmissions that waited on ACK */
10913 if (COMMUNICATOR_TOTAL_QUEUE_LIMIT - 1 ==
10914 tc->details.communicator.total_queue_length)
10915 {
10916 /* Communicator dropped below threshold, resume all queues
10917 incident with this client! */
10918 GNUNET_STATISTICS_update (
10919 GST_stats,
10920 "# Transmission throttled due to communicator queue limit",
10921 -1,
10922 GNUNET_NO);
10923 for (struct Queue *queue = tc->details.communicator.queue_head;
10924 NULL != queue;
10925 queue = queue->next_client)
10926 {
10927 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10928 queue,
10929 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10930 }
10931 }
10932 else if (QUEUE_LENGTH_LIMIT - 1 == qe->queue->queue_length)
10933 {
10934 /* queue dropped below threshold; only resume this one queue */
10935 GNUNET_STATISTICS_update (GST_stats,
10936 "# Transmission throttled due to queue queue limit",
10937 -1,
10938 GNUNET_NO);
10939 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10940 qe->queue,
10941 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10942 }
10943 else if (1 == qe->queue->q_capacity)
10944 {
10945 // TODO I guess this will never happen, because the communicator triggers this by updating its queue length itself.
10946 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
10947 "Transmission rescheduled due to communicator message queue with qid %u has capacity %"
10948 PRIu64 ".\n",
10949 qe->queue->qid,
10950 qe->queue->q_capacity);
10951 /* message queue has capacity; only resume this one queue */
10952 /* queue dropped below threshold; only resume this one queue */
10953 GNUNET_STATISTICS_update (GST_stats,
10954 "# Transmission throttled due to message queue capacity",
10955 -1,
10956 GNUNET_NO);
10957 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
10958 qe->queue,
10959 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
10960 }
10961
10962 if (NULL != (pm = qe->pm))
10963 {
10964 struct VirtualLink *vl;
10965
10966 // GNUNET_assert (qe == pm->qe);
10967 pm->qe = NULL;
10968 /* If waiting for this communicator may have blocked transmission
10969 of pm on other queues for this neighbour, force schedule
10970 transmit on queue for queues of the neighbour */
10971 if (NULL == pm->frag_parent)
10972 {
10973 vl = pm->vl;
10974 if ((NULL != vl) &&
10975 (NULL != vl->pending_msg_head) &&
10976 (vl->pending_msg_head == pm))
10977 check_vl_transmission (vl);
10978 }
10979 }
10980 GNUNET_free (qe);
10981}
10982
10983
10984/**
10985 * Message was transmitted. Process the request.
10986 *
10987 * @param cls the client
10988 * @param sma the send message that was sent
10989 */
10990static void
10991handle_send_message_ack (void *cls,
10992 const struct GNUNET_TRANSPORT_SendMessageToAck *sma)
10993{
10994 struct TransportClient *tc = cls;
10995 struct QueueEntry *qe;
10996
10997 if (CT_COMMUNICATOR != tc->type)
10998 {
10999 GNUNET_break (0);
11000 GNUNET_SERVICE_client_drop (tc->client);
11001 return;
11002 }
11003
11004 /* find our queue entry matching the ACK */
11005 qe = NULL;
11006 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11007 "Looking for queue for PID %s\n",
11008 GNUNET_i2s (&sma->receiver));
11009 for (struct Queue *queue = tc->details.communicator.queue_head; NULL != queue;
11010 queue = queue->next_client)
11011 {
11012 if (0 != GNUNET_memcmp (&queue->neighbour->pid, &sma->receiver))
11013 continue;
11014 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11015 "Found PID %s\n",
11016 GNUNET_i2s (&queue->neighbour->pid));
11017
11018
11019 for (struct QueueEntry *qep = queue->queue_head; NULL != qep;
11020 qep = qep->next)
11021 {
11022 if (qep->mid != GNUNET_ntohll (sma->mid) || queue->qid != ntohl (
11023 sma->qid))
11024 continue;
11025 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11026 "QueueEntry MID: %" PRIu64 " on queue QID: %u, Ack MID: %"
11027 PRIu64 " Ack QID %u\n",
11028 qep->mid,
11029 queue->qid,
11030 GNUNET_ntohll (sma->mid),
11031 ntohl (sma->qid));
11032 qe = qep;
11033 if ((NULL != qe->pm) && (qe->pm->qe != qe))
11034 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11035 "For pending message %" PRIu64 " we had retransmissions.\n",
11036 qe->pm->logging_uuid);
11037 break;
11038 }
11039 }
11040 if (NULL == qe)
11041 {
11042 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11043 "No QueueEntry found for Ack MID %" PRIu64 " QID: %u\n",
11044 GNUNET_ntohll (sma->mid),
11045 ntohl (sma->qid));
11046 // TODO I guess this can happen, if the Ack from the peer comes before the Ack from the queue.
11047 // Update: Maybe QueueEntry was accidentally freed during freeing PendingMessage.
11048 /* this should never happen */
11049 // GNUNET_break (0);
11050 // GNUNET_SERVICE_client_drop (tc->client);
11051 GNUNET_SERVICE_client_continue (tc->client);
11052 return;
11053 }
11054 free_queue_entry (qe, tc);
11055 GNUNET_SERVICE_client_continue (tc->client);
11056}
11057
11058
11059/**
11060 * Iterator telling new MONITOR client about all existing
11061 * queues to peers.
11062 *
11063 * @param cls the new `struct TransportClient`
11064 * @param pid a connected peer
11065 * @param value the `struct Neighbour` with more information
11066 * @return #GNUNET_OK (continue to iterate)
11067 */
11068static int
11069notify_client_queues (void *cls,
11070 const struct GNUNET_PeerIdentity *pid,
11071 void *value)
11072{
11073 struct TransportClient *tc = cls;
11074 struct Neighbour *neighbour = value;
11075
11076 GNUNET_assert (CT_MONITOR == tc->type);
11077 for (struct Queue *q = neighbour->queue_head; NULL != q;
11078 q = q->next_neighbour)
11079 {
11080 struct MonitorEvent me = { .rtt = q->pd.aged_rtt,
11081 .cs = q->cs,
11082 .num_msg_pending = q->num_msg_pending,
11083 .num_bytes_pending = q->num_bytes_pending };
11084
11085 notify_monitor (tc, pid, q->address, q->nt, &me);
11086 }
11087 return GNUNET_OK;
11088}
11089
11090
11091/**
11092 * Initialize a monitor client.
11093 *
11094 * @param cls the client
11095 * @param start the start message that was sent
11096 */
11097static void
11098handle_monitor_start (void *cls,
11099 const struct GNUNET_TRANSPORT_MonitorStart *start)
11100{
11101 struct TransportClient *tc = cls;
11102
11103 if (CT_NONE != tc->type)
11104 {
11105 GNUNET_break (0);
11106 GNUNET_SERVICE_client_drop (tc->client);
11107 return;
11108 }
11109 tc->type = CT_MONITOR;
11110 tc->details.monitor.peer = start->peer;
11111 tc->details.monitor.one_shot = ntohl (start->one_shot);
11112 GNUNET_CONTAINER_multipeermap_iterate (neighbours, &notify_client_queues, tc);
11113 GNUNET_SERVICE_client_mark_monitor (tc->client);
11114 GNUNET_SERVICE_client_continue (tc->client);
11115}
11116
11117
11118/**
11119 * Find transport client providing communication service
11120 * for the protocol @a prefix.
11121 *
11122 * @param prefix communicator name
11123 * @return NULL if no such transport client is available
11124 */
11125static struct TransportClient *
11126lookup_communicator (const char *prefix)
11127{
11128 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
11129 {
11130 if (CT_COMMUNICATOR != tc->type)
11131 continue;
11132 if (0 == strcmp (prefix, tc->details.communicator.address_prefix))
11133 return tc;
11134 }
11135 GNUNET_log (
11136 GNUNET_ERROR_TYPE_WARNING,
11137 "Somone suggested use of communicator for `%s', but we do not have such a communicator!\n",
11138 prefix);
11139 return NULL;
11140}
11141
11142
11143/**
11144 * Signature of a function called with a communicator @a address of a peer
11145 * @a pid that an application wants us to connect to.
11146 *
11147 * @param pid target peer
11148 * @param address the address to try
11149 */
11150static void
11151suggest_to_connect (const struct GNUNET_PeerIdentity *pid, const char *address)
11152{
11153 static uint32_t idgen;
11154 struct TransportClient *tc;
11155 char *prefix;
11156 struct GNUNET_TRANSPORT_CreateQueue *cqm;
11157 struct GNUNET_MQ_Envelope *env;
11158 size_t alen;
11159
11160 prefix = GNUNET_HELLO_address_to_prefix (address);
11161 if (NULL == prefix)
11162 {
11163 GNUNET_break (0); /* We got an invalid address!? */
11164 return;
11165 }
11166 tc = lookup_communicator (prefix);
11167 if (NULL == tc)
11168 {
11169 GNUNET_STATISTICS_update (GST_stats,
11170 "# Suggestions ignored due to missing communicator",
11171 1,
11172 GNUNET_NO);
11173 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
11174 "Cannot connect to %s at `%s', no matching communicator present\n",
11175 GNUNET_i2s (pid),
11176 address);
11177 GNUNET_free (prefix);
11178 return;
11179 }
11180 /* forward suggestion for queue creation to communicator */
11181 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11182 "Request #%u for `%s' communicator to create queue to `%s' at `%s'\n",
11183 (unsigned int) idgen,
11184 prefix,
11185 GNUNET_i2s (pid),
11186 address);
11187 GNUNET_free (prefix);
11188 alen = strlen (address) + 1;
11189 env =
11190 GNUNET_MQ_msg_extra (cqm, alen, GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE);
11191 cqm->request_id = htonl (idgen++);
11192 cqm->receiver = *pid;
11193 memcpy (&cqm[1], address, alen);
11194 GNUNET_MQ_send (tc->mq, env);
11195}
11196
11197
11198/**
11199 * The queue @a q (which matches the peer and address in @a vs) is
11200 * ready for queueing. We should now queue the validation request.
11201 *
11202 * @param q queue to send on
11203 * @param vs state to derive validation challenge from
11204 */
11205static void
11206validation_transmit_on_queue (struct Queue *q, struct ValidationState *vs)
11207{
11208 struct TransportValidationChallengeMessage tvc;
11209 struct GNUNET_TIME_Absolute monotonic_time;
11210
11211 if (NULL != vs->revalidation_task)
11212 {
11213 GNUNET_SCHEDULER_cancel (vs->revalidation_task);
11214 vs->revalidation_task = NULL;
11215 }
11216 /*memcpy (&hkey,
11217 &hc,
11218 sizeof (hkey));*/
11219 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11220 "Remove key %s for address %s map size %u contains %u\n",
11221 GNUNET_h2s (&vs->hc),
11222 vs->address,
11223 GNUNET_CONTAINER_multihashmap_size (revalidation_map),
11224 GNUNET_CONTAINER_multihashmap_contains (revalidation_map,
11225 &vs->hc));
11226 GNUNET_CONTAINER_multihashmap_remove (revalidation_map, &vs->hc, vs);
11227
11228 monotonic_time = GNUNET_TIME_absolute_get_monotonic (GST_cfg);
11229 if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us ==
11230 vs->last_challenge_use.abs_value_us)
11231 {
11232 vs->first_challenge_use = monotonic_time;
11233 }
11234 vs->last_challenge_use = monotonic_time;
11235 tvc.header.type =
11236 htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_VALIDATION_CHALLENGE);
11237 tvc.header.size = htons (sizeof(tvc));
11238 tvc.reserved = htonl (0);
11239 tvc.challenge = vs->challenge;
11240 tvc.sender_time = GNUNET_TIME_absolute_hton (vs->last_challenge_use);
11241 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
11242 "Sending address validation challenge %s to %s\n",
11243 GNUNET_sh2s (&tvc.challenge.value),
11244 GNUNET_i2s (&q->neighbour->pid));
11245 queue_send_msg (q, NULL, &tvc, sizeof(tvc));
11246}
11247
11248
11249/**
11250 * Task run periodically to validate some address based on #validation_heap.
11251 *
11252 * @param cls NULL
11253 */
11254static void
11255validation_start_cb (void *cls)
11256{
11257 struct ValidationState *vs;
11258 struct Queue *q;
11259 const struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get_monotonic (
11260 GST_cfg);
11261
11262 (void) cls;
11263 validation_task = NULL;
11264 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
11265 /* drop validations past their expiration */
11266 while (
11267 (NULL != vs) &&
11268 (0 == GNUNET_TIME_absolute_get_remaining (vs->valid_until).rel_value_us))
11269 {
11270 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11271 "Validation response %s cleaned up\n",
11272 GNUNET_sh2s (&vs->challenge.value));
11273 free_validation_state (vs);
11274 vs = GNUNET_CONTAINER_heap_peek (validation_heap);
11275 }
11276 if (NULL == vs)
11277 {
11278 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
11279 "Address validation task not scheduled anymore, nothing to do\n");
11280 return; /* woopsie, no more addresses known, should only
11281 happen if we're really a lonely peer */
11282 }
11283 q = find_queue (&vs->pid, vs->address);
11284 if (GNUNET_TIME_absolute_cmp (vs->first_challenge_use, >, now))
11285 {
11286 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11287 "To early to start next address validation for challenge %s\n",
11288 GNUNET_sh2s (&vs->challenge.value));
11289 return;
11290 }
11291 if (NULL == q)
11292 {
11293 vs->awaiting_queue = GNUNET_YES;
11294 suggest_to_connect (&vs->pid, vs->address);
11295 }
11296 else
11297 validation_transmit_on_queue (q, vs);
11298 /* Finally, reschedule next attempt */
11299 vs->challenge_backoff =
11300 GNUNET_TIME_randomized_backoff (vs->challenge_backoff,
11301 MAX_VALIDATION_CHALLENGE_FREQ);
11302 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11303 "Address validation task will run again in %s\n",
11304 GNUNET_STRINGS_relative_time_to_string (vs->challenge_backoff,
11305 GNUNET_YES));
11306 update_next_challenge_time (vs,
11307 GNUNET_TIME_relative_to_absolute (
11308 vs->challenge_backoff));
11309}
11310
11311
11312/**
11313 * Closure for #check_connection_quality.
11314 */
11315struct QueueQualityContext
11316{
11317 /**
11318 * Set to the @e k'th queue encountered.
11319 */
11320 struct Queue *q;
11321
11322 /**
11323 * Set to the number of quality queues encountered.
11324 */
11325 unsigned int quality_count;
11326
11327 /**
11328 * Set to the total number of queues encountered.
11329 */
11330 unsigned int num_queues;
11331
11332 /**
11333 * Decremented for each queue, for selection of the
11334 * k-th queue in @e q.
11335 */
11336 unsigned int k;
11337};
11338
11339
11340/**
11341 * Check whether any queue to the given neighbour is
11342 * of a good "quality" and if so, increment the counter.
11343 * Also counts the total number of queues, and returns
11344 * the k-th queue found.
11345 *
11346 * @param cls a `struct QueueQualityContext *` with counters
11347 * @param pid peer this is about
11348 * @param value a `struct Neighbour`
11349 * @return #GNUNET_OK (continue to iterate)
11350 */
11351static int
11352check_connection_quality (void *cls,
11353 const struct GNUNET_PeerIdentity *pid,
11354 void *value)
11355{
11356 struct QueueQualityContext *ctx = cls;
11357 struct Neighbour *n = value;
11358 int do_inc;
11359
11360 (void) pid;
11361 do_inc = GNUNET_NO;
11362 for (struct Queue *q = n->queue_head; NULL != q; q = q->next_neighbour)
11363 {
11364 ctx->num_queues++;
11365 if (0 == ctx->k--)
11366 ctx->q = q;
11367 /* FIXME-CONQ-STATISTICS: in the future, add reliability / goodput
11368 statistics and consider those as well here? */
11369 if (q->pd.aged_rtt.rel_value_us < DV_QUALITY_RTT_THRESHOLD.rel_value_us)
11370 do_inc = GNUNET_YES;
11371 }
11372 if (GNUNET_YES == do_inc)
11373 ctx->quality_count++;
11374 return GNUNET_OK;
11375}
11376
11377
11378/**
11379 * Task run when we CONSIDER initiating a DV learn
11380 * process. We first check that sending out a message is
11381 * even possible (queues exist), then that it is desirable
11382 * (if not, reschedule the task for later), and finally
11383 * we may then begin the job. If there are too many
11384 * entries in the #dvlearn_map, we purge the oldest entry
11385 * using #lle_tail.
11386 *
11387 * @param cls NULL
11388 */
11389static void
11390start_dv_learn (void *cls)
11391{
11392 struct LearnLaunchEntry *lle;
11393 struct QueueQualityContext qqc;
11394 struct TransportDVLearnMessage dvl;
11395
11396 (void) cls;
11397 dvlearn_task = NULL;
11398 if (0 == GNUNET_CONTAINER_multipeermap_size (neighbours))
11399 return; /* lost all connectivity, cannot do learning */
11400 qqc.quality_count = 0;
11401 qqc.num_queues = 0;
11402 qqc.k = GNUNET_CONTAINER_multipeermap_size (neighbours);
11403 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
11404 &check_connection_quality,
11405 &qqc);
11406 if (qqc.quality_count > DV_LEARN_QUALITY_THRESHOLD)
11407 {
11408 struct GNUNET_TIME_Relative delay;
11409 unsigned int factor;
11410
11411 /* scale our retries by how far we are above the threshold */
11412 factor = qqc.quality_count / DV_LEARN_QUALITY_THRESHOLD;
11413 delay = GNUNET_TIME_relative_multiply (DV_LEARN_BASE_FREQUENCY, factor);
11414 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11415 "At connection quality %u, will launch DV learn in %s\n",
11416 qqc.quality_count,
11417 GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_YES));
11418 dvlearn_task = GNUNET_SCHEDULER_add_delayed (delay, &start_dv_learn, NULL);
11419 return;
11420 }
11421 /* remove old entries in #dvlearn_map if it has grown too big */
11422 while (MAX_DV_LEARN_PENDING <=
11423 GNUNET_CONTAINER_multishortmap_size (dvlearn_map))
11424 {
11425 lle = lle_tail;
11426 GNUNET_assert (GNUNET_YES ==
11427 GNUNET_CONTAINER_multishortmap_remove (dvlearn_map,
11428 &lle->challenge.value,
11429 lle));
11430 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
11431 GNUNET_free (lle);
11432 }
11433 /* setup data structure for learning */
11434 lle = GNUNET_new (struct LearnLaunchEntry);
11435 GNUNET_CRYPTO_random_block (GNUNET_CRYPTO_QUALITY_NONCE,
11436 &lle->challenge,
11437 sizeof(lle->challenge));
11438 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11439 "Starting launch DV learn with challenge %s\n",
11440 GNUNET_sh2s (&lle->challenge.value));
11441 GNUNET_CONTAINER_DLL_insert (lle_head, lle_tail, lle);
11442 GNUNET_break (GNUNET_YES ==
11443 GNUNET_CONTAINER_multishortmap_put (
11444 dvlearn_map,
11445 &lle->challenge.value,
11446 lle,
11447 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
11448 dvl.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DV_LEARN);
11449 dvl.header.size = htons (sizeof(dvl));
11450 dvl.num_hops = htons (0);
11451 dvl.bidirectional = htons (0);
11452 dvl.non_network_delay = GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_ZERO);
11453 dvl.monotonic_time =
11454 GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get_monotonic (GST_cfg));
11455 {
11456 struct DvInitPS dvip = {
11457 .purpose.purpose = htonl (
11458 GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DV_INITIATOR),
11459 .purpose.size = htonl (sizeof(dvip)),
11460 .monotonic_time = dvl.monotonic_time,
11461 .challenge = lle->challenge
11462 };
11463
11464 GNUNET_CRYPTO_eddsa_sign (GST_my_private_key,
11465 &dvip,
11466 &dvl.init_sig);
11467 }
11468 dvl.initiator = GST_my_identity;
11469 dvl.challenge = lle->challenge;
11470
11471 qqc.quality_count = 0;
11472 qqc.k = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, qqc.num_queues);
11473 qqc.num_queues = 0;
11474 qqc.q = NULL;
11475 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
11476 &check_connection_quality,
11477 &qqc);
11478 GNUNET_assert (NULL != qqc.q);
11479
11480 /* Do this as close to transmission time as possible! */
11481 lle->launch_time = GNUNET_TIME_absolute_get ();
11482
11483 queue_send_msg (qqc.q, NULL, &dvl, sizeof(dvl));
11484 /* reschedule this job, randomizing the time it runs (but no
11485 actual backoff!) */
11486 dvlearn_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_randomize (
11487 DV_LEARN_BASE_FREQUENCY),
11488 &start_dv_learn,
11489 NULL);
11490}
11491
11492
11493/**
11494 * Get the IP address without the port number.
11495 *
11496 * @param address The string contains a communicator prefix, IP address and port
11497 * like this 'tcp-92.68.150.1:55452'.
11498 * @return String with IP address only.
11499 */
11500static char *
11501get_address_without_port (const char *address)
11502{
11503 const char *colon;
11504 char *colon_rest;
11505 size_t colon_rest_length;
11506 char *address_without_port;
11507
11508 colon = strchr (address,':');
11509 colon_rest = GNUNET_strndup (address, colon - address);
11510 colon_rest_length = strlen (colon_rest);
11511 address_without_port = GNUNET_strndup (&colon_rest[4], colon_rest_length - 4);
11512 GNUNET_free (colon_rest);
11513
11514 return address_without_port;
11515}
11516
11517
11518/**
11519 * A new queue has been created, check if any address validation
11520 * requests have been waiting for it.
11521 *
11522 * @param cls a `struct Queue`
11523 * @param pid peer concerned (unused)
11524 * @param value a `struct ValidationState`
11525 * @return #GNUNET_NO if a match was found and we can stop looking
11526 */
11527static int
11528check_validation_request_pending (void *cls,
11529 const struct GNUNET_PeerIdentity *pid,
11530 void *value)
11531{
11532 struct Queue *q = cls;
11533 struct ValidationState *vs = value;
11534 char *address_without_port_vs;
11535 char *address_without_port_q;
11536 int success = GNUNET_YES;
11537
11538 //TODO Check if this is really necessary.
11539 address_without_port_vs = get_address_without_port (vs->address);
11540 address_without_port_q = get_address_without_port (q->address);
11541
11542 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11543 "Check validation request pending for `%s' at `%s'/`%s' (vs)/(q)\n",
11544 GNUNET_i2s (pid),
11545 address_without_port_vs,
11546 address_without_port_q);
11547 (void) pid;
11548 if ((GNUNET_YES == vs->awaiting_queue) &&
11549 (0 == strcmp (address_without_port_vs, address_without_port_q)))
11550 {
11551
11552 vs->awaiting_queue = GNUNET_NO;
11553 validation_transmit_on_queue (q, vs);
11554 success = GNUNET_NO;
11555 }
11556
11557 GNUNET_free (address_without_port_vs);
11558 GNUNET_free (address_without_port_q);
11559 return success;
11560}
11561
11562
11563/**
11564 * Function called with the monotonic time of a DV initiator
11565 * by PEERSTORE. Updates the time.
11566 *
11567 * @param cls a `struct Neighbour`
11568 * @param record the information found, NULL for the last call
11569 * @param emsg error message
11570 */
11571static void
11572neighbour_dv_monotime_cb (void *cls,
11573 const struct GNUNET_PEERSTORE_Record *record,
11574 const char *emsg)
11575{
11576 struct Neighbour *n = cls;
11577 struct GNUNET_TIME_AbsoluteNBO *mtbe;
11578
11579 (void) emsg;
11580 if (NULL == record)
11581 {
11582 /* we're done with #neighbour_dv_monotime_cb() invocations,
11583 continue normal processing */
11584 n->get = NULL;
11585 n->dv_monotime_available = GNUNET_YES;
11586 return;
11587 }
11588 if (0 == record->value_size)
11589 {
11590 GNUNET_PEERSTORE_iteration_next (n->get, 1);
11591 GNUNET_break (0);
11592 return;
11593 }
11594 mtbe = record->value;
11595 n->last_dv_learn_monotime =
11596 GNUNET_TIME_absolute_max (n->last_dv_learn_monotime,
11597 GNUNET_TIME_absolute_ntoh (*mtbe));
11598 GNUNET_PEERSTORE_iteration_next (n->get, 1);
11599}
11600
11601
11602static void
11603iterate_address_and_compare_cb (void *cls,
11604 const struct GNUNET_PeerIdentity *pid,
11605 const char *uri)
11606{
11607 struct Queue *queue = cls;
11608 const char *slash;
11609 char *address_uri;
11610 char *prefix;
11611 char *uri_without_port;
11612 char *address_uri_without_port;
11613
11614 slash = strrchr (uri, '/');
11615 prefix = GNUNET_strndup (uri, (slash - uri) - 2);
11616 GNUNET_assert (NULL != slash);
11617 slash++;
11618 GNUNET_asprintf (&address_uri,
11619 "%s-%s",
11620 prefix,
11621 slash);
11622
11623 address_uri_without_port = get_address_without_port (queue->address);
11624 uri_without_port = get_address_without_port (address_uri);
11625 if (0 == strcmp (uri_without_port, address_uri_without_port))
11626 {
11627 queue->is_global_natted = GNUNET_NO;
11628 }
11629
11630 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11631 "not global natted %u %s %s %s %s %s %u\n",
11632 queue->is_global_natted,
11633 uri,
11634 queue->address,
11635 uri_without_port,
11636 address_uri_without_port,
11637 prefix,
11638 GNUNET_NO);
11639 GNUNET_free (prefix);
11640 GNUNET_free (address_uri);
11641 GNUNET_free (address_uri_without_port);
11642 GNUNET_free (uri_without_port);
11643}
11644
11645
11646static void
11647check_for_global_natted_error_cb (void *cls)
11648{
11649 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
11650 "Error in PEERSTORE monitoring for checking global natted\n");
11651}
11652
11653
11654static void
11655check_for_global_natted_sync_cb (void *cls)
11656{
11657 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
11658 "Done with initial PEERSTORE iteration during monitoring for checking global natted\n");
11659}
11660
11661
11662struct TransportGlobalNattedAddressClosure
11663{
11664 /**
11665 * The address to search for.
11666 */
11667 char *addr;
11668
11669 /**
11670 * The struct TransportGlobalNattedAddress to set.
11671 */
11672 struct TransportGlobalNattedAddress *tgna;
11673};
11674
11675
11676static enum GNUNET_GenericReturnValue
11677contains_address (void *cls,
11678 const struct GNUNET_PeerIdentity *pid,
11679 void *value)
11680{
11681 struct TransportGlobalNattedAddressClosure *tgna_cls = cls;
11682 struct TransportGlobalNattedAddress *tgna = value;
11683 char *addr = (char *) &tgna[1];
11684
11685 if (strlen(tgna_cls->addr) == ntohl (tgna->address_length)
11686 && 0 == strncmp (addr, tgna_cls->addr, ntohl (tgna->address_length)))
11687 {
11688 tgna_cls->tgna = tgna;
11689 return GNUNET_NO;
11690 }
11691 return GNUNET_YES;
11692}
11693
11694
11695static void
11696check_for_global_natted (void *cls,
11697 const struct GNUNET_PEERSTORE_Record *record,
11698 const char *emsg)
11699{
11700 struct Queue *queue = cls;
11701 struct Neighbour *neighbour = queue->neighbour;
11702 struct GNUNET_HELLO_Builder *builder;
11703 struct GNUNET_MessageHeader *hello;
11704 struct TransportGlobalNattedAddressClosure tgna_cls;
11705 size_t address_len_without_port;
11706
11707 if (NULL != emsg)
11708 {
11709 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
11710 "Got failure from PEERSTORE: %s\n",
11711 emsg);
11712 return;
11713 }
11714 if (NULL == record)
11715 {
11716 queue->mo = NULL;
11717 return;
11718 }
11719 if (0 == record->value_size)
11720 {
11721 GNUNET_PEERSTORE_monitor_next (queue->mo, 1);
11722 GNUNET_break (0);
11723 return;
11724 }
11725 queue->is_global_natted = GNUNET_YES;
11726 hello = record->value;
11727 builder = GNUNET_HELLO_builder_from_msg (hello);
11728 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11729 "before not global natted %u\n",
11730 queue->is_global_natted);
11731 GNUNET_HELLO_builder_iterate (builder,
11732 &iterate_address_and_compare_cb,
11733 queue);
11734 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11735 "after not global natted %u\n",
11736 queue->is_global_natted);
11737 GNUNET_HELLO_builder_free (builder);
11738
11739 tgna_cls.addr = get_address_without_port (queue->address);
11740 tgna_cls.tgna = NULL;
11741 address_len_without_port = strlen (tgna_cls.addr);
11742 GNUNET_CONTAINER_multipeermap_get_multiple (neighbour->natted_addresses,
11743 &neighbour->pid,
11744 &contains_address,
11745 &tgna_cls);
11746 if (NULL != tgna_cls.tgna)
11747 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11748 " tgna_cls.tgna tgna %p %lu %u %u\n",
11749 tgna_cls.tgna,
11750 neighbour->size_of_global_addresses,
11751 ntohl (tgna_cls.tgna->address_length),
11752 neighbour->number_of_addresses);
11753 if (NULL == tgna_cls.tgna && GNUNET_YES == queue->is_global_natted)
11754 {
11755 struct TransportGlobalNattedAddress *tgna;
11756
11757 tgna = GNUNET_malloc (sizeof (struct TransportGlobalNattedAddress) + address_len_without_port);
11758 tgna->address_length = htonl (address_len_without_port);
11759 GNUNET_memcpy (&tgna[1], tgna_cls.addr, address_len_without_port);
11760 GNUNET_CONTAINER_multipeermap_put (neighbour->natted_addresses,
11761 &neighbour->pid,
11762 tgna,
11763 GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
11764 neighbour->number_of_addresses++;
11765 neighbour->size_of_global_addresses += address_len_without_port;
11766 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11767 "Created tgna %p\n",
11768 tgna);
11769 }
11770 else if (NULL != tgna_cls.tgna && GNUNET_NO == queue->is_global_natted)
11771 {
11772 GNUNET_CONTAINER_multipeermap_remove (neighbour->natted_addresses,
11773 &neighbour->pid,
11774 tgna_cls.tgna);
11775 GNUNET_assert (neighbour->size_of_global_addresses >= ntohl (tgna_cls.tgna->address_length));
11776 neighbour->size_of_global_addresses -= ntohl (tgna_cls.tgna->address_length);
11777 GNUNET_assert (0 < neighbour->number_of_addresses);
11778 neighbour->number_of_addresses--;
11779 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11780 "removed tgna %p\n",
11781 tgna_cls.tgna);
11782 GNUNET_free (tgna_cls.tgna);
11783 }
11784 GNUNET_free (tgna_cls.addr);
11785 GNUNET_PEERSTORE_monitor_next (queue->mo, 1);
11786}
11787
11788
11789/**
11790 * New queue became available. Process the request.
11791 *
11792 * @param cls the client
11793 * @param aqm the send message that was sent
11794 */
11795static void
11796handle_add_queue_message (void *cls,
11797 const struct GNUNET_TRANSPORT_AddQueueMessage *aqm)
11798{
11799 struct TransportClient *tc = cls;
11800 struct Queue *queue;
11801 struct Neighbour *neighbour;
11802 struct GNUNET_TIME_Absolute validated_until = GNUNET_TIME_UNIT_ZERO_ABS;
11803 const char *addr;
11804 uint16_t addr_len;
11805
11806 if (ntohl (aqm->mtu) <= sizeof(struct TransportFragmentBoxMessage))
11807 {
11808 /* MTU so small as to be useless for transmissions,
11809 required for #fragment_message()! */
11810 GNUNET_break_op (0);
11811 GNUNET_SERVICE_client_drop (tc->client);
11812 return;
11813 }
11814 /* This may simply be a queue update */
11815 for (queue = tc->details.communicator.queue_head;
11816 NULL != queue;
11817 queue = queue->next_client)
11818 {
11819 validated_until = queue->validated_until;
11820 if (queue->qid != ntohl (aqm->qid))
11821 continue;
11822 break;
11823 }
11824
11825 if (NULL != queue)
11826 {
11827 neighbour = queue->neighbour;
11828 }
11829 else
11830 {
11831 neighbour = lookup_neighbour (&aqm->receiver);
11832 if (NULL == neighbour)
11833 {
11834 neighbour = GNUNET_new (struct Neighbour);
11835 neighbour->natted_addresses = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
11836 neighbour->pid = aqm->receiver;
11837 GNUNET_assert (GNUNET_OK ==
11838 GNUNET_CONTAINER_multipeermap_put (
11839 neighbours,
11840 &neighbour->pid,
11841 neighbour,
11842 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
11843 neighbour->get =
11844 GNUNET_PEERSTORE_iteration_start (peerstore,
11845 "transport",
11846 &neighbour->pid,
11847 GNUNET_PEERSTORE_TRANSPORT_DVLEARN_MONOTIME,
11848 &neighbour_dv_monotime_cb,
11849 neighbour);
11850 }
11851 addr_len = ntohs (aqm->header.size) - sizeof(*aqm);
11852 addr = (const char *) &aqm[1];
11853 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11854 "New queue %s to %s available with QID %u and q_len %" PRIu64
11855 " and mtu %u\n",
11856 addr,
11857 GNUNET_i2s (&aqm->receiver),
11858 ntohl (aqm->qid),
11859 GNUNET_ntohll (aqm->q_len),
11860 ntohl (aqm->mtu));
11861 queue = GNUNET_malloc (sizeof(struct Queue) + addr_len);
11862 queue->tc = tc;
11863 if (GNUNET_TIME_UNIT_ZERO_ABS.abs_value_us != validated_until.abs_value_us)
11864 {
11865 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11866 "New queue with QID %u inherit validated until\n",
11867 ntohl (aqm->qid));
11868 queue->validated_until = validated_until;
11869 }
11870 queue->address = (const char *) &queue[1];
11871 queue->pd.aged_rtt = GNUNET_TIME_UNIT_FOREVER_REL;
11872 queue->qid = ntohl (aqm->qid);
11873 queue->neighbour = neighbour;
11874 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (aqm->q_len))
11875 queue->unlimited_length = GNUNET_YES;
11876 queue->q_capacity = GNUNET_ntohll (aqm->q_len);
11877 memcpy (&queue[1], addr, addr_len);
11878 /* notify monitors about new queue */
11879 {
11880 struct MonitorEvent me = { .rtt = queue->pd.aged_rtt, .cs = queue->cs };
11881
11882 notify_monitors (&neighbour->pid, queue->address, queue->nt, &me);
11883 }
11884 GNUNET_CONTAINER_MDLL_insert (neighbour,
11885 neighbour->queue_head,
11886 neighbour->queue_tail,
11887 queue);
11888 GNUNET_CONTAINER_MDLL_insert (client,
11889 tc->details.communicator.queue_head,
11890 tc->details.communicator.queue_tail,
11891 queue);
11892
11893 }
11894 queue->mtu = ntohl (aqm->mtu);
11895 queue->nt = (enum GNUNET_NetworkType) ntohl (aqm->nt);
11896 queue->cs = (enum GNUNET_TRANSPORT_ConnectionStatus) ntohl (aqm->cs);
11897 queue->idle = GNUNET_YES;
11898 queue->mo = GNUNET_PEERSTORE_monitor_start (GST_cfg,
11899 GNUNET_YES,
11900 "peerstore",
11901 &neighbour->pid,
11902 GNUNET_PEERSTORE_HELLO_KEY,
11903 &check_for_global_natted_error_cb,
11904 NULL,
11905 &check_for_global_natted_sync_cb,
11906 NULL,
11907 &check_for_global_natted,
11908 queue);
11909 /* check if valdiations are waiting for the queue */
11910 if (GNUNET_YES == GNUNET_CONTAINER_multipeermap_contains (validation_map,
11911 &aqm->receiver))
11912 {
11913 if (GNUNET_SYSERR != GNUNET_CONTAINER_multipeermap_get_multiple (
11914 validation_map,
11915 &aqm->
11916 receiver,
11917 &
11918 check_validation_request_pending,
11919 queue))
11920 start_address_validation (&aqm->receiver, queue->address);
11921 }
11922 else
11923 start_address_validation (&aqm->receiver, queue->address);
11924 /* look for traffic for this queue */
11925 // TODO Check whether this makes any sense at all.
11926 /*schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
11927 queue, GNUNET_SCHEDULER_PRIORITY_DEFAULT);*/
11928 /* might be our first queue, try launching DV learning */
11929 if (NULL == dvlearn_task)
11930 dvlearn_task = GNUNET_SCHEDULER_add_now (&start_dv_learn, NULL);
11931 GNUNET_SERVICE_client_continue (tc->client);
11932}
11933
11934
11935/**
11936 * @brief Handle updates to queues.
11937 *
11938 * @param cls the transport client.
11939 * @param msg Message struct.
11940 */
11941static void
11942handle_update_queue_message (void *cls,
11943 const struct
11944 GNUNET_TRANSPORT_UpdateQueueMessage *msg)
11945{
11946 struct TransportClient *tc = cls;
11947 struct Queue *target_queue = NULL;
11948
11949 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
11950 "Received queue update message for %u with q_len %llu and mtu %u\n",
11951 ntohl (msg->qid),
11952 (unsigned long long) GNUNET_ntohll (msg->q_len),
11953 ntohl (msg->mtu));
11954 for (target_queue = tc->details.communicator.queue_head;
11955 NULL != target_queue;
11956 target_queue = target_queue->next_client)
11957 {
11958 if (ntohl (msg->qid) == target_queue->qid)
11959 break;
11960 }
11961 if (NULL == target_queue)
11962 {
11963 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
11964 "Queue to update no longer exists! Discarding update.\n");
11965 return;
11966 }
11967
11968 target_queue->nt = msg->nt;
11969 target_queue->mtu = ntohl (msg->mtu);
11970 target_queue->cs = msg->cs;
11971 target_queue->priority = ntohl (msg->priority);
11972 /* The update message indicates how many messages
11973 * the queue should be able to handle.
11974 */
11975 if (GNUNET_TRANSPORT_QUEUE_LENGTH_UNLIMITED == GNUNET_ntohll (msg->q_len))
11976 target_queue->unlimited_length = GNUNET_YES;
11977 else
11978 target_queue->unlimited_length = GNUNET_NO;
11979 target_queue->q_capacity += GNUNET_ntohll (msg->q_len);
11980 if (0 < target_queue->q_capacity)
11981 schedule_transmit_on_queue (GNUNET_TIME_UNIT_ZERO,
11982 target_queue,
11983 GNUNET_SCHEDULER_PRIORITY_DEFAULT);
11984 GNUNET_SERVICE_client_continue (tc->client);
11985}
11986
11987
11988/**
11989 * Communicator tells us that our request to create a queue "worked", that
11990 * is setting up the queue is now in process.
11991 *
11992 * @param cls the `struct TransportClient`
11993 * @param cqr confirmation message
11994 */
11995static void
11996handle_queue_create_ok (void *cls,
11997 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
11998{
11999 struct TransportClient *tc = cls;
12000
12001 if (CT_COMMUNICATOR != tc->type)
12002 {
12003 GNUNET_break (0);
12004 GNUNET_SERVICE_client_drop (tc->client);
12005 return;
12006 }
12007 GNUNET_STATISTICS_update (GST_stats,
12008 "# Suggestions succeeded at communicator",
12009 1,
12010 GNUNET_NO);
12011 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12012 "Request #%u for communicator to create queue succeeded\n",
12013 (unsigned int) ntohs (cqr->request_id));
12014 GNUNET_SERVICE_client_continue (tc->client);
12015}
12016
12017
12018/**
12019 * Communicator tells us that our request to create a queue failed. This
12020 * usually indicates that the provided address is simply invalid or that the
12021 * communicator's resources are exhausted.
12022 *
12023 * @param cls the `struct TransportClient`
12024 * @param cqr failure message
12025 */
12026static void
12027handle_queue_create_fail (
12028 void *cls,
12029 const struct GNUNET_TRANSPORT_CreateQueueResponse *cqr)
12030{
12031 struct TransportClient *tc = cls;
12032
12033 if (CT_COMMUNICATOR != tc->type)
12034 {
12035 GNUNET_break (0);
12036 GNUNET_SERVICE_client_drop (tc->client);
12037 return;
12038 }
12039 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12040 "Request #%u for communicator to create queue failed\n",
12041 (unsigned int) ntohs (cqr->request_id));
12042 GNUNET_STATISTICS_update (GST_stats,
12043 "# Suggestions failed in queue creation at communicator",
12044 1,
12045 GNUNET_NO);
12046 GNUNET_SERVICE_client_continue (tc->client);
12047}
12048
12049
12050/**
12051 * We have received a `struct ExpressPreferenceMessage` from an application
12052 * client.
12053 *
12054 * @param cls handle to the client
12055 * @param msg the start message
12056 */
12057static void
12058handle_suggest_cancel (void *cls, const struct ExpressPreferenceMessage *msg)
12059{
12060 struct TransportClient *tc = cls;
12061 struct PeerRequest *pr;
12062
12063 if (CT_APPLICATION != tc->type)
12064 {
12065 GNUNET_break (0);
12066 GNUNET_SERVICE_client_drop (tc->client);
12067 return;
12068 }
12069 pr = GNUNET_CONTAINER_multipeermap_get (tc->details.application.requests,
12070 &msg->peer);
12071 if (NULL == pr)
12072 {
12073 GNUNET_break (0);
12074 GNUNET_SERVICE_client_drop (tc->client);
12075 return;
12076 }
12077 (void) stop_peer_request (tc, &pr->pid, pr);
12078 GNUNET_SERVICE_client_continue (tc->client);
12079}
12080
12081
12082static void
12083hello_for_client_cb (void *cls,
12084 const struct GNUNET_PeerIdentity *pid,
12085 const char *uri)
12086{
12087 (void) cls;
12088 struct Queue *q;
12089 int pfx_len;
12090 const char *eou;
12091 char *address;
12092
12093 eou = strstr (uri,
12094 "://");
12095 pfx_len = eou - uri;
12096 eou += 3;
12097 GNUNET_asprintf (&address,
12098 "%.*s-%s",
12099 pfx_len,
12100 uri,
12101 eou);
12102
12103 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12104 "hello for client %s\n",
12105 address);
12106
12107 q = find_queue (pid, address);
12108 if (NULL == q)
12109 {
12110 suggest_to_connect (pid, address);
12111 }
12112 else
12113 start_address_validation (pid, address);
12114 GNUNET_free (address);
12115}
12116
12117
12118/**
12119 * Function called by PEERSTORE for each matching record.
12120 *
12121 * @param cls closure, a `struct PeerRequest`
12122 * @param record peerstore record information
12123 * @param emsg error message, or NULL if no errors
12124 */
12125static void
12126handle_hello_for_client (void *cls,
12127 const struct GNUNET_PEERSTORE_Record *record,
12128 const char *emsg)
12129{
12130 struct PeerRequest *pr = cls;
12131 struct GNUNET_HELLO_Builder *builder;
12132 struct GNUNET_MessageHeader *hello;
12133
12134 if (NULL != emsg)
12135 {
12136 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
12137 "Got failure from PEERSTORE: %s\n",
12138 emsg);
12139 return;
12140 }
12141 hello = record->value;
12142 if (0 == GNUNET_memcmp (&record->peer, &GST_my_identity))
12143 {
12144 GNUNET_PEERSTORE_monitor_next (pr->nc, 1);
12145 return;
12146 }
12147 builder = GNUNET_HELLO_builder_from_msg (hello);
12148 GNUNET_HELLO_builder_iterate (builder,
12149 hello_for_client_cb,
12150 NULL);
12151 GNUNET_HELLO_builder_free (builder);
12152}
12153
12154
12155static void
12156hello_for_client_error_cb (void *cls)
12157{
12158 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
12159 "Error in PEERSTORE monitoring\n");
12160}
12161
12162
12163static void
12164hello_for_client_sync_cb (void *cls)
12165{
12166 GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
12167 "Done with initial PEERSTORE iteration during monitoring\n");
12168}
12169
12170
12171/**
12172 * We have received a `struct ExpressPreferenceMessage` from an application
12173 * client.
12174 *
12175 * @param cls handle to the client
12176 * @param msg the start message
12177 */
12178static void
12179handle_suggest (void *cls, const struct ExpressPreferenceMessage *msg)
12180{
12181 struct TransportClient *tc = cls;
12182 struct PeerRequest *pr;
12183
12184 if (CT_NONE == tc->type)
12185 {
12186 tc->type = CT_APPLICATION;
12187 tc->details.application.requests =
12188 GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
12189 }
12190 if (CT_APPLICATION != tc->type)
12191 {
12192 GNUNET_break (0);
12193 GNUNET_SERVICE_client_drop (tc->client);
12194 return;
12195 }
12196 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12197 "Client suggested we talk to %s with preference %d at rate %u\n",
12198 GNUNET_i2s (&msg->peer),
12199 (int) ntohl (msg->pk),
12200 (int) ntohl (msg->bw.value__));
12201 pr = GNUNET_new (struct PeerRequest);
12202 pr->tc = tc;
12203 pr->pid = msg->peer;
12204 pr->bw = msg->bw;
12205 pr->pk = (enum GNUNET_MQ_PriorityPreferences) ntohl (msg->pk);
12206 if (GNUNET_YES != GNUNET_CONTAINER_multipeermap_put (
12207 tc->details.application.requests,
12208 &pr->pid,
12209 pr,
12210 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY))
12211 {
12212 GNUNET_break (0);
12213 GNUNET_free (pr);
12214 GNUNET_SERVICE_client_drop (tc->client);
12215 return;
12216 }
12217 pr->nc =
12218 GNUNET_PEERSTORE_monitor_start (GST_cfg,
12219 GNUNET_YES,
12220 "peerstore",
12221 NULL,
12222 GNUNET_PEERSTORE_HELLO_KEY,
12223 &hello_for_client_error_cb,
12224 NULL,
12225 &hello_for_client_sync_cb,
12226 NULL,
12227 &handle_hello_for_client,
12228 pr);
12229 GNUNET_SERVICE_client_continue (tc->client);
12230}
12231
12232
12233/**
12234 * Check #GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION
12235 * messages.
12236 *
12237 * @param cls a `struct TransportClient *`
12238 * @param m message to verify
12239 * @return #GNUNET_OK on success
12240 */
12241static int
12242check_request_hello_validation (void *cls,
12243 const struct RequestHelloValidationMessage *m)
12244{
12245 (void) cls;
12246 GNUNET_MQ_check_zero_termination (m);
12247 return GNUNET_OK;
12248}
12249
12250
12251/**
12252 * A client encountered an address of another peer. Consider validating it,
12253 * and if validation succeeds, persist it to PEERSTORE.
12254 *
12255 * @param cls a `struct TransportClient *`
12256 * @param m message to verify
12257 */
12258static void
12259handle_request_hello_validation (void *cls,
12260 const struct RequestHelloValidationMessage *m)
12261{
12262 struct TransportClient *tc = cls;
12263 struct Queue *q;
12264
12265 q = find_queue (&m->peer, (const char *) &m[1]);
12266 if (NULL == q)
12267 {
12268 suggest_to_connect (&m->peer, (const char *) &m[1]);
12269 }
12270 else
12271 start_address_validation (&m->peer, (const char *) &m[1]);
12272 GNUNET_SERVICE_client_continue (tc->client);
12273}
12274
12275
12276/**
12277 * Free neighbour entry.
12278 *
12279 * @param cls NULL
12280 * @param pid unused
12281 * @param value a `struct Neighbour`
12282 * @return #GNUNET_OK (always)
12283 */
12284static int
12285free_neighbour_cb (void *cls,
12286 const struct GNUNET_PeerIdentity *pid,
12287 void *value)
12288{
12289 struct Neighbour *neighbour = value;
12290
12291 (void) cls;
12292 (void) pid;
12293 GNUNET_break (0); // should this ever happen?
12294 free_neighbour (neighbour);
12295
12296 return GNUNET_OK;
12297}
12298
12299
12300/**
12301 * Free DV route entry.
12302 *
12303 * @param cls NULL
12304 * @param pid unused
12305 * @param value a `struct DistanceVector`
12306 * @return #GNUNET_OK (always)
12307 */
12308static int
12309free_dv_routes_cb (void *cls,
12310 const struct GNUNET_PeerIdentity *pid,
12311 void *value)
12312{
12313 struct DistanceVector *dv = value;
12314
12315 (void) cls;
12316 (void) pid;
12317 free_dv_route (dv);
12318
12319 return GNUNET_OK;
12320}
12321
12322
12323/**
12324 * Free validation state.
12325 *
12326 * @param cls NULL
12327 * @param pid unused
12328 * @param value a `struct ValidationState`
12329 * @return #GNUNET_OK (always)
12330 */
12331static int
12332free_validation_state_cb (void *cls,
12333 const struct GNUNET_PeerIdentity *pid,
12334 void *value)
12335{
12336 struct ValidationState *vs = value;
12337
12338 (void) cls;
12339 (void) pid;
12340 free_validation_state (vs);
12341 return GNUNET_OK;
12342}
12343
12344
12345/**
12346 * Free pending acknowledgement.
12347 *
12348 * @param cls NULL
12349 * @param key unused
12350 * @param value a `struct PendingAcknowledgement`
12351 * @return #GNUNET_OK (always)
12352 */
12353static int
12354free_pending_ack_cb (void *cls, const struct GNUNET_Uuid *key, void *value)
12355{
12356 struct PendingAcknowledgement *pa = value;
12357
12358 (void) cls;
12359 (void) key;
12360 free_pending_acknowledgement (pa);
12361 return GNUNET_OK;
12362}
12363
12364
12365/**
12366 * Free acknowledgement cummulator.
12367 *
12368 * @param cls NULL
12369 * @param pid unused
12370 * @param value a `struct AcknowledgementCummulator`
12371 * @return #GNUNET_OK (always)
12372 */
12373static int
12374free_ack_cummulator_cb (void *cls,
12375 const struct GNUNET_PeerIdentity *pid,
12376 void *value)
12377{
12378 struct AcknowledgementCummulator *ac = value;
12379
12380 (void) cls;
12381 (void) pid;
12382 GNUNET_SCHEDULER_cancel (ac->task);
12383 GNUNET_free (ac);
12384 return GNUNET_OK;
12385}
12386
12387
12388/**
12389 * Function called when the service shuts down. Unloads our plugins
12390 * and cancels pending validations.
12391 *
12392 * @param cls closure, unused
12393 */
12394static void
12395do_shutdown (void *cls)
12396{
12397 struct LearnLaunchEntry *lle;
12398 (void) cls;
12399
12400 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12401 "shutdown logic\n");
12402 GNUNET_NAT_unregister (nh);
12403 GNUNET_CONTAINER_multipeermap_iterate (neighbours,
12404 &free_neighbour_cb, NULL);
12405 if (NULL != validation_task)
12406 {
12407 GNUNET_SCHEDULER_cancel (validation_task);
12408 validation_task = NULL;
12409 }
12410 if (NULL != dvlearn_task)
12411 {
12412 GNUNET_SCHEDULER_cancel (dvlearn_task);
12413 dvlearn_task = NULL;
12414 }
12415 if (NULL != GST_stats)
12416 {
12417 GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
12418 GST_stats = NULL;
12419 }
12420 if (NULL != GST_my_hello)
12421 {
12422 GNUNET_HELLO_builder_free (GST_my_hello);
12423 GST_my_hello = NULL;
12424 }
12425 if (NULL != GST_my_private_key)
12426 {
12427 GNUNET_free (GST_my_private_key);
12428 GST_my_private_key = NULL;
12429 }
12430 GNUNET_CONTAINER_multipeermap_iterate (ack_cummulators,
12431 &free_ack_cummulator_cb,
12432 NULL);
12433 GNUNET_CONTAINER_multipeermap_destroy (ack_cummulators);
12434 ack_cummulators = NULL;
12435 GNUNET_CONTAINER_multiuuidmap_iterate (pending_acks,
12436 &free_pending_ack_cb,
12437 NULL);
12438 GNUNET_CONTAINER_multiuuidmap_destroy (pending_acks);
12439 pending_acks = NULL;
12440 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (neighbours));
12441 GNUNET_CONTAINER_multipeermap_destroy (neighbours);
12442 neighbours = NULL;
12443 GNUNET_break (0 == GNUNET_CONTAINER_multipeermap_size (links));
12444 GNUNET_CONTAINER_multipeermap_destroy (links);
12445 links = NULL;
12446 GNUNET_CONTAINER_multipeermap_iterate (backtalkers,
12447 &free_backtalker_cb,
12448 NULL);
12449 GNUNET_CONTAINER_multipeermap_destroy (backtalkers);
12450 backtalkers = NULL;
12451 GNUNET_CONTAINER_multipeermap_iterate (validation_map,
12452 &free_validation_state_cb,
12453 NULL);
12454 GNUNET_CONTAINER_multipeermap_destroy (validation_map);
12455 validation_map = NULL;
12456 GNUNET_CONTAINER_multihashmap_destroy (revalidation_map);
12457 revalidation_map = NULL;
12458 while (NULL != ir_head)
12459 free_incoming_request (ir_head);
12460 GNUNET_assert (0 == ir_total);
12461 while (NULL != (lle = lle_head))
12462 {
12463 GNUNET_CONTAINER_DLL_remove (lle_head, lle_tail, lle);
12464 GNUNET_free (lle);
12465 }
12466 if (NULL != peerstore)
12467 {
12468 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12469 "Disconnecting from PEERSTORE service\n");
12470 GNUNET_PEERSTORE_disconnect (peerstore);
12471 peerstore = NULL;
12472 }
12473 GNUNET_CONTAINER_multishortmap_destroy (dvlearn_map);
12474 dvlearn_map = NULL;
12475 GNUNET_CONTAINER_heap_destroy (validation_heap);
12476 validation_heap = NULL;
12477 GNUNET_CONTAINER_multipeermap_iterate (dv_routes, &free_dv_routes_cb, NULL);
12478 GNUNET_CONTAINER_multipeermap_destroy (dv_routes);
12479 dv_routes = NULL;
12480 GNUNET_SCHEDULER_shutdown ();
12481}
12482
12483
12484static void
12485shutdown_task (void *cls)
12486{
12487 in_shutdown = GNUNET_YES;
12488
12489 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
12490 "Shutdown task executed\n");
12491 if (NULL != clients_head)
12492 {
12493 for (struct TransportClient *tc = clients_head; NULL != tc; tc = tc->next)
12494 {
12495 GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
12496 "client still connected: %u\n",
12497 tc->type);
12498 }
12499 }
12500 else
12501 do_shutdown (cls);
12502
12503}
12504
12505
12506/**
12507 * Initiate transport service.
12508 *
12509 * @param cls closure
12510 * @param c configuration to use
12511 * @param service the initialized service
12512 */
12513static void
12514run (void *cls,
12515 const struct GNUNET_CONFIGURATION_Handle *c,
12516 struct GNUNET_SERVICE_Handle *service)
12517{
12518 (void) cls;
12519 (void) service;
12520 /* setup globals */
12521 hello_mono_time = GNUNET_TIME_absolute_get_monotonic (c);
12522 in_shutdown = GNUNET_NO;
12523 GST_cfg = c;
12524 backtalkers = GNUNET_CONTAINER_multipeermap_create (16, GNUNET_YES);
12525 pending_acks = GNUNET_CONTAINER_multiuuidmap_create (32768, GNUNET_YES);
12526 ack_cummulators = GNUNET_CONTAINER_multipeermap_create (256, GNUNET_YES);
12527 neighbours = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
12528 links = GNUNET_CONTAINER_multipeermap_create (512, GNUNET_YES);
12529 dv_routes = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
12530 dvlearn_map = GNUNET_CONTAINER_multishortmap_create (2 * MAX_DV_LEARN_PENDING,
12531 GNUNET_YES);
12532 validation_map = GNUNET_CONTAINER_multipeermap_create (1024, GNUNET_YES);
12533 revalidation_map = GNUNET_CONTAINER_multihashmap_create (1024, GNUNET_YES);
12534 validation_heap =
12535 GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
12536 GST_my_private_key =
12537 GNUNET_CRYPTO_eddsa_key_create_from_configuration (GST_cfg);
12538 if (NULL == GST_my_private_key)
12539 {
12540 GNUNET_log (
12541 GNUNET_ERROR_TYPE_ERROR,
12542 _ (
12543 "Transport service is lacking key configuration settings. Exiting.\n"));
12544 GNUNET_SCHEDULER_shutdown ();
12545 return;
12546 }
12547 GNUNET_CRYPTO_eddsa_key_get_public (GST_my_private_key,
12548 &GST_my_identity.public_key);
12549 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
12550 "My identity is `%s'\n",
12551 GNUNET_i2s_full (&GST_my_identity));
12552 GST_my_hello = GNUNET_HELLO_builder_new (&GST_my_identity);
12553 GST_stats = GNUNET_STATISTICS_create ("transport", GST_cfg);
12554 GNUNET_SCHEDULER_add_shutdown (&shutdown_task, NULL);
12555 peerstore = GNUNET_PEERSTORE_connect (GST_cfg);
12556 nh = GNUNET_NAT_register (GST_cfg,
12557 "transport",
12558 0,
12559 0,
12560 NULL,
12561 0,
12562 NULL,
12563 NULL,
12564 NULL);
12565 if (NULL == peerstore)
12566 {
12567 GNUNET_break (0);
12568 GNUNET_SCHEDULER_shutdown ();
12569 return;
12570 }
12571}
12572
12573
12574/**
12575 * Define "main" method using service macro.
12576 */
12577GNUNET_SERVICE_MAIN (
12578 "transport",
12579 GNUNET_SERVICE_OPTION_SOFT_SHUTDOWN,
12580 &run,
12581 &client_connect_cb,
12582 &client_disconnect_cb,
12583 NULL,
12584 /* communication with applications */
12585 GNUNET_MQ_hd_fixed_size (suggest,
12586 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST,
12587 struct ExpressPreferenceMessage,
12588 NULL),
12589 GNUNET_MQ_hd_fixed_size (suggest_cancel,
12590 GNUNET_MESSAGE_TYPE_TRANSPORT_SUGGEST_CANCEL,
12591 struct ExpressPreferenceMessage,
12592 NULL),
12593 GNUNET_MQ_hd_var_size (request_hello_validation,
12594 GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_HELLO_VALIDATION,
12595 struct RequestHelloValidationMessage,
12596 NULL),
12597 /* communication with core */
12598 GNUNET_MQ_hd_fixed_size (client_start,
12599 GNUNET_MESSAGE_TYPE_TRANSPORT_START,
12600 struct StartMessage,
12601 NULL),
12602 GNUNET_MQ_hd_var_size (client_send,
12603 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND,
12604 struct OutboundMessage,
12605 NULL),
12606 GNUNET_MQ_hd_fixed_size (client_recv_ok,
12607 GNUNET_MESSAGE_TYPE_TRANSPORT_RECV_OK,
12608 struct RecvOkMessage,
12609 NULL),
12610 /* communication with communicators */
12611 GNUNET_MQ_hd_var_size (communicator_available,
12612 GNUNET_MESSAGE_TYPE_TRANSPORT_NEW_COMMUNICATOR,
12613 struct GNUNET_TRANSPORT_CommunicatorAvailableMessage,
12614 NULL),
12615 GNUNET_MQ_hd_var_size (communicator_backchannel,
12616 GNUNET_MESSAGE_TYPE_TRANSPORT_COMMUNICATOR_BACKCHANNEL,
12617 struct GNUNET_TRANSPORT_CommunicatorBackchannel,
12618 NULL),
12619 GNUNET_MQ_hd_var_size (add_address,
12620 GNUNET_MESSAGE_TYPE_TRANSPORT_ADD_ADDRESS,
12621 struct GNUNET_TRANSPORT_AddAddressMessage,
12622 NULL),
12623 GNUNET_MQ_hd_fixed_size (del_address,
12624 GNUNET_MESSAGE_TYPE_TRANSPORT_DEL_ADDRESS,
12625 struct GNUNET_TRANSPORT_DelAddressMessage,
12626 NULL),
12627 GNUNET_MQ_hd_var_size (incoming_msg,
12628 GNUNET_MESSAGE_TYPE_TRANSPORT_INCOMING_MSG,
12629 struct GNUNET_TRANSPORT_IncomingMessage,
12630 NULL),
12631 GNUNET_MQ_hd_fixed_size (queue_create_ok,
12632 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_OK,
12633 struct GNUNET_TRANSPORT_CreateQueueResponse,
12634 NULL),
12635 GNUNET_MQ_hd_fixed_size (queue_create_fail,
12636 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_CREATE_FAIL,
12637 struct GNUNET_TRANSPORT_CreateQueueResponse,
12638 NULL),
12639 GNUNET_MQ_hd_var_size (add_queue_message,
12640 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_SETUP,
12641 struct GNUNET_TRANSPORT_AddQueueMessage,
12642 NULL),
12643 GNUNET_MQ_hd_fixed_size (update_queue_message,
12644 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_UPDATE,
12645 struct GNUNET_TRANSPORT_UpdateQueueMessage,
12646 NULL),
12647 GNUNET_MQ_hd_fixed_size (del_queue_message,
12648 GNUNET_MESSAGE_TYPE_TRANSPORT_QUEUE_TEARDOWN,
12649 struct GNUNET_TRANSPORT_DelQueueMessage,
12650 NULL),
12651 GNUNET_MQ_hd_fixed_size (send_message_ack,
12652 GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_MSG_ACK,
12653 struct GNUNET_TRANSPORT_SendMessageToAck,
12654 NULL),
12655 /* communication with monitors */
12656 GNUNET_MQ_hd_fixed_size (monitor_start,
12657 GNUNET_MESSAGE_TYPE_TRANSPORT_MONITOR_START,
12658 struct GNUNET_TRANSPORT_MonitorStart,
12659 NULL),
12660 GNUNET_MQ_handler_end ());
12661
12662
12663/* 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..b46496b43
--- /dev/null
+++ b/src/service/transport/meson.build
@@ -0,0 +1,491 @@
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
77libgnunettestingtransport = library('gnunettestingtransport',
78 [
79 'testing_transport_traits.c'
80 ],
81 soversion: '0',
82 version: '0.0.0',
83 dependencies: [libgnunetutil_dep,
84 libgnunettransportcore_dep,
85 libgnunettransportapplication_dep,
86 libgnunetpeerstore_dep,
87 libgnunettesting_dep,
88 libgnunethello_dep],
89 include_directories: [incdir, configuration_inc],
90 install: true,
91 install_dir: get_option('libdir'))
92libgnunettestingtransport_dep = declare_dependency(link_with : libgnunettestingtransport)
93
94executable ('gnunet-service-transport',
95 gnunetservicetransport_src,
96 dependencies: [libgnunettransportcommunicator_dep,
97 libgnunetpeerstore_dep,
98 libgnunetstatistics_dep,
99 libgnunethello_dep,
100 libgnunetnat_dep,
101 gcrypt_dep,
102 m_dep,
103 libgnunetutil_dep],
104 include_directories: [incdir, configuration_inc],
105 install: true,
106 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
107
108executable ('gnunet-communicator-unix',
109 gnunetcommunicatorunix_src,
110 dependencies: [libgnunettransportcommunicator_dep,
111 libgnunetpeerstore_dep,
112 libgnunetstatistics_dep,
113 libgnunetnat_dep,
114 gcrypt_dep,
115 libgnunetutil_dep],
116 include_directories: [incdir, configuration_inc],
117 install: true,
118 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
119executable ('gnunet-communicator-udp',
120 gnunetcommunicatorudp_src,
121 dependencies: [libgnunettransportcommunicator_dep,
122 libgnunettransportapplication_dep,
123 libgnunetpeerstore_dep,
124 libgnunetstatistics_dep,
125 libgnunetnat_dep,
126 gcrypt_dep,
127 libgnunetutil_dep],
128 include_directories: [incdir, configuration_inc],
129 install: true,
130 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
131executable ('gnunet-communicator-tcp',
132 gnunetcommunicatortcp_src,
133 dependencies: [libgnunettransportcommunicator_dep,
134 libgnunetpeerstore_dep,
135 libgnunetstatistics_dep,
136 libgnunetnat_dep,
137 gcrypt_dep,
138 libgnunetutil_dep],
139 include_directories: [incdir, configuration_inc],
140 install: true,
141 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
142if quic_dep.found() and get_option('experimental')
143executable ('gnunet-communicator-quic',
144 gnunetcommunicatortcp_src,
145 dependencies: [libgnunettransportcommunicator_dep,
146 libgnunetpeerstore_dep,
147 libgnunetstatistics_dep,
148 libgnunetnat_dep,
149 gcrypt_dep,
150 quic_dep,
151 libgnunetutil_dep],
152 include_directories: [incdir, configuration_inc],
153 install: true,
154 install_dir: get_option('libdir') / 'gnunet' / 'libexec')
155endif
156
157if false
158
159libgnunettesttransport_cmd_simplesend = library('gnunet_test_transport_plugin_cmd_simple_send',
160 ['test_transport_plugin_cmd_simple_send.c'],
161 dependencies: [
162 libgnunetutil_dep,
163 libgnunettransportapplication_dep,
164 libgnunettestingtransport_dep,
165 libgnunettransportcore_dep,
166 libgnunettesting_dep,
167 libgnunetpeerstore_dep,
168 libgnunetstatistics_dep,
169 libgnunethello_dep,
170 libgnunetarm_dep,
171 libgnunetutil_dep
172 ],
173 include_directories: [incdir, configuration_inc],
174 install: true,
175 install_dir: get_option('libdir')/'gnunet')
176
177libgnunettesttransport_cmd_simplesendbc = library('gnunet_test_transport_plugin_cmd_simple_send_broadcast',
178 ['test_transport_plugin_cmd_simple_send_broadcast.c'],
179 dependencies: [
180 libgnunetutil_dep,
181 libgnunettransportapplication_dep,
182 libgnunettestingtransport_dep,
183 libgnunettransportcore_dep,
184 libgnunettesting_dep,
185 libgnunetpeerstore_dep,
186 libgnunetstatistics_dep,
187 libgnunethello_dep,
188 libgnunetarm_dep,
189 libgnunetutil_dep
190 ],
191 include_directories: [incdir, configuration_inc],
192 install: true,
193 install_dir: get_option('libdir')/'gnunet')
194
195libgnunettesttransport_cmd_simplesenddv = library('gnunet_test_transport_plugin_cmd_simple_send_dv',
196 ['test_transport_plugin_cmd_simple_send_dv.c'],
197 dependencies: [
198 libgnunetutil_dep,
199 libgnunettransportapplication_dep,
200 libgnunettestingtransport_dep,
201 libgnunettransportcore_dep,
202 libgnunettesting_dep,
203 libgnunetpeerstore_dep,
204 libgnunetstatistics_dep,
205 libgnunethello_dep,
206 libgnunetarm_dep,
207 libgnunetutil_dep
208 ],
209 include_directories: [incdir, configuration_inc],
210 install: true,
211 install_dir: get_option('libdir')/'gnunet')
212
213libgnunettesttransport_cmd_simplesendperf = library('gnunet_test_transport_plugin_cmd_simple_send_performance',
214 ['test_transport_plugin_cmd_simple_send_performance.c'],
215 dependencies: [
216 libgnunetutil_dep,
217 libgnunettransportapplication_dep,
218 libgnunettestingtransport_dep,
219 libgnunettransportcore_dep,
220 libgnunettesting_dep,
221 libgnunetpeerstore_dep,
222 libgnunetstatistics_dep,
223 libgnunethello_dep,
224 libgnunetarm_dep,
225 libgnunetutil_dep
226 ],
227 include_directories: [incdir, configuration_inc],
228 install: true,
229 install_dir: get_option('libdir')/'gnunet')
230
231libgnunettesttransport_cmd_udpback = library('gnunet_test_transport_plugin_cmd_udp_backchannel',
232 ['test_transport_plugin_cmd_udp_backchannel.c'],
233 dependencies: [
234 libgnunetutil_dep,
235 libgnunettestingtransport_dep,
236 libgnunettransportapplication_dep,
237 libgnunettransportcore_dep,
238 libgnunettesting_dep,
239 libgnunetpeerstore_dep,
240 libgnunetstatistics_dep,
241 libgnunethello_dep,
242 libgnunetarm_dep,
243 libgnunetutil_dep
244 ],
245 include_directories: [incdir, configuration_inc],
246 install: true,
247 install_dir: get_option('libdir')/'gnunet')
248
249libgnunettesttransport_cmd_natupnp = library('gnunet_test_transport_plugin_cmd_nat_upnp',
250 ['test_transport_plugin_cmd_nat_upnp.c'],
251 dependencies: [
252 libgnunetutil_dep,
253 libgnunettransportapplication_dep,
254 libgnunettestingtransport_dep,
255 libgnunettransportcore_dep,
256 libgnunettesting_dep,
257 libgnunetpeerstore_dep,
258 libgnunetstatistics_dep,
259 libgnunethello_dep,
260 libgnunetarm_dep,
261 libgnunetutil_dep
262 ],
263 include_directories: [incdir, configuration_inc],
264 install: true,
265 install_dir: get_option('libdir')/'gnunet')
266
267configure_file(input : 'test_transport_defaults.conf',
268 output : 'test_transport_defaults.conf',
269 copy: true)
270
271foreach p : ['unix', 'tcp', 'udp', 'quic']
272 configure_file(input : 'test_communicator_'+p+'_basic_peer1.conf',
273 output : 'test_communicator_'+p+'_basic_peer1.conf',
274 copy: true)
275 configure_file(input : 'test_communicator_'+p+'_basic_peer2.conf',
276 output : 'test_communicator_'+p+'_basic_peer2.conf',
277 copy: true)
278endforeach
279
280foreach p : ['tcp', 'udp']
281 configure_file(input : 'test_communicator_'+p+'_rekey_peer1.conf',
282 output : 'test_communicator_'+p+'_rekey_peer1.conf',
283 copy: true)
284 configure_file(input : 'test_communicator_'+p+'_rekey_peer2.conf',
285 output : 'test_communicator_'+p+'_rekey_peer2.conf',
286 copy: true)
287endforeach
288
289configure_file(input : 'test_communicator_udp_backchannel_peer1.conf',
290 output : 'test_communicator_udp_backchannel_peer1.conf',
291 copy: true)
292configure_file(input : 'test_communicator_udp_backchannel_peer2.conf',
293 output : 'test_communicator_udp_backchannel_peer2.conf',
294 copy: true)
295
296configure_file(input : 'test_communicator_tcp_bidirect_peer1.conf',
297 output : 'test_communicator_tcp_bidirect_peer1.conf',
298 copy: true)
299configure_file(input : 'test_communicator_tcp_bidirect_peer2.conf',
300 output : 'test_communicator_tcp_bidirect_peer2.conf',
301 copy: true)
302
303testcommunicator_basic_unix = executable('test_communicator_basic-unix',
304 ['test_communicator_basic.c'],
305 dependencies: [
306 libgnunetutil_dep,
307 libgnunettransportapplication_dep,
308 libgnunettestingtransport_dep,
309 libgnunettransportcore_dep,
310 libgnunettesting_dep,
311 libgnunetpeerstore_dep,
312 libgnunetstatistics_dep,
313 libgnunethello_dep,
314 libgnunetarm_dep,
315 libgnunetutil_dep
316 ],
317 include_directories: [incdir, configuration_inc],
318 install: false)
319testcommunicator_basic_tcp = executable('test_communicator_basic-tcp',
320 ['test_communicator_basic.c'],
321 dependencies: [
322 libgnunetutil_dep,
323 libgnunettransportapplication_dep,
324 libgnunettestingtransport_dep,
325 libgnunettransportcore_dep,
326 libgnunettesting_dep,
327 libgnunetpeerstore_dep,
328 libgnunetstatistics_dep,
329 libgnunethello_dep,
330 libgnunetarm_dep,
331 libgnunetutil_dep
332 ],
333 include_directories: [incdir, configuration_inc],
334 install: false)
335testcommunicator_basic_udp = executable('test_communicator_basic-udp',
336 ['test_communicator_basic.c'],
337 dependencies: [
338 libgnunetutil_dep,
339 libgnunettransportapplication_dep,
340 libgnunettestingtransport_dep,
341 libgnunettransportcore_dep,
342 libgnunettesting_dep,
343 libgnunetpeerstore_dep,
344 libgnunetstatistics_dep,
345 libgnunethello_dep,
346 libgnunetarm_dep,
347 libgnunetutil_dep
348 ],
349 include_directories: [incdir, configuration_inc],
350 install: false)
351if quic_dep.found() and get_option('experimental')
352 testcommunicator_basic_quic = executable('test_communicator_basic-quic',
353 ['test_communicator_basic.c'],
354 dependencies: [
355 libgnunetutil_dep,
356 libgnunettransportapplication_dep,
357 libgnunettestingtransport_dep,
358 libgnunettransportcore_dep,
359 libgnunettesting_dep,
360 libgnunetpeerstore_dep,
361 libgnunetstatistics_dep,
362 libgnunethello_dep,
363 libgnunetarm_dep,
364 libgnunetutil_dep
365 ],
366 include_directories: [incdir, configuration_inc],
367 install: false)
368endif
369
370testcommunicator_rekey_tcp = executable('test_communicator_rekey-tcp',
371 ['test_communicator_basic.c'],
372 dependencies: [
373 libgnunetutil_dep,
374 libgnunettransportapplication_dep,
375 libgnunettestingtransport_dep,
376 libgnunettransportcore_dep,
377 libgnunettesting_dep,
378 libgnunetpeerstore_dep,
379 libgnunetstatistics_dep,
380 libgnunethello_dep,
381 libgnunetarm_dep,
382 libgnunetutil_dep
383 ],
384 include_directories: [incdir, configuration_inc],
385 install: false)
386
387testcommunicator_rekey_udp = executable('test_communicator_rekey-udp',
388 ['test_communicator_basic.c'],
389 dependencies: [
390 libgnunetutil_dep,
391 libgnunettransportapplication_dep,
392 libgnunettestingtransport_dep,
393 libgnunettransportcore_dep,
394 libgnunettesting_dep,
395 libgnunetpeerstore_dep,
396 libgnunetstatistics_dep,
397 libgnunethello_dep,
398 libgnunetarm_dep,
399 libgnunetutil_dep
400 ],
401 include_directories: [incdir, configuration_inc],
402 install: false)
403
404testcommunicator_backchannel_udp = executable('test_communicator_backchannel-udp',
405 ['test_communicator_basic.c'],
406 dependencies: [
407 libgnunetutil_dep,
408 libgnunettransportapplication_dep,
409 libgnunettestingtransport_dep,
410 libgnunettransportcore_dep,
411 libgnunettesting_dep,
412 libgnunetpeerstore_dep,
413 libgnunetstatistics_dep,
414 libgnunethello_dep,
415 libgnunetarm_dep,
416 libgnunetutil_dep
417 ],
418 include_directories: [incdir, configuration_inc],
419 install: false)
420
421testcommunicator_bidirect_tcp = executable('test_communicator_bidirect-tcp',
422 ['test_communicator_basic.c'],
423 dependencies: [
424 libgnunetutil_dep,
425 libgnunettransportapplication_dep,
426 libgnunettestingtransport_dep,
427 libgnunettransportcore_dep,
428 libgnunettesting_dep,
429 libgnunetpeerstore_dep,
430 libgnunetstatistics_dep,
431 libgnunethello_dep,
432 libgnunetarm_dep,
433 libgnunetutil_dep
434 ],
435 include_directories: [incdir, configuration_inc],
436 install: false)
437
438
439testtransport_test_names = [
440 'test_transport_start_testcase',
441 'test_transport_simple_send_performance',
442 'test_transport_nat_icmp_tcp',
443 'test_transport_nat_upnp',
444 'test_transport_simple_send_string',
445 'test_transport_simple_send',
446 'test_transport_simple_send_broadcast',
447 'test_transport_udp_backchannel',
448 'test_transport_simple_send_dv_circle',
449 'test_transport_simple_send_dv_inverse'
450 ]
451
452foreach t : testtransport_test_names
453
454 test_filename = t + '.sh'
455 test_file = configure_file(input : test_filename,
456 output : test_filename,
457 copy: true)
458
459 if host_machine.system() != 'darwin'
460 test(t, test_file, suite: 'transport', workdir: meson.current_build_dir(), is_parallel: false)
461 endif
462endforeach
463
464test('test_communicator_basic-unix', testcommunicator_basic_unix,
465 workdir: meson.current_build_dir(),
466 suite: ['transport', 'communicator'], is_parallel: false)
467test('test_communicator_basic-tcp', testcommunicator_basic_tcp,
468 workdir: meson.current_build_dir(),
469 suite: ['transport', 'communicator'], is_parallel: false)
470test('test_communicator_basic-udp', testcommunicator_basic_udp,
471 workdir: meson.current_build_dir(),
472 suite: ['transport', 'communicator'], is_parallel: false)
473if quic_dep.found() and get_option('experimental')
474 test('test_communicator_basic-quic', testcommunicator_basic_quic,
475 workdir: meson.current_build_dir(),
476 suite: ['transport', 'communicator'], is_parallel: false)
477endif
478test('test_communicator_rekey-tcp', testcommunicator_rekey_tcp,
479 workdir: meson.current_build_dir(),
480 suite: ['transport', 'communicator'], is_parallel: false)
481test('test_communicator_rekey-udp', testcommunicator_rekey_udp,
482 workdir: meson.current_build_dir(),
483 suite: ['transport', 'communicator'], is_parallel: false)
484test('test_communicator_backchannel-udp', testcommunicator_backchannel_udp,
485 workdir: meson.current_build_dir(),
486 suite: ['transport', 'communicator'], is_parallel: false)
487test('test_communicator_bidirect-tcp', testcommunicator_bidirect_tcp,
488 workdir: meson.current_build_dir(),
489 suite: ['transport', 'communicator'], is_parallel: false)
490
491endif \ No newline at end of file
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..79b369b18
--- /dev/null
+++ b/src/service/transport/test_transport_plugin_cmd_simple_send_broadcast.c
@@ -0,0 +1,397 @@
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_lib.h"
28#include "gnunet_util_lib.h"
29#include "gnunet_transport_application_service.h"
30#include "transport-testing2.h"
31#include "transport-testing-cmds.h"
32
33/**
34 * Generic logging shortcut
35 */
36#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
37
38#define BASE_DIR "testdir"
39
40#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
41
42#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
43
44static struct GNUNET_TESTING_Command block_send;
45
46static struct GNUNET_TESTING_Command block_receive;
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 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
56 * received.
57 *
58 */
59static int
60check_test (void *cls,
61 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
62{
63 return GNUNET_OK;
64}
65
66
67/**
68 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
69 * being received.
70 *
71 */
72static void
73handle_test (void *cls,
74 const struct GNUNET_TRANSPORT_TESTING_TestMessage *message)
75{
76 struct GNUNET_TESTING_AsyncContext *ac;
77
78 GNUNET_TESTING_get_trait_async_context (&block_receive,
79 &ac);
80 GNUNET_assert (NULL != ac);
81 if ((GNUNET_NO == ac->finished) && (NULL == ac->cont))
82 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
83 else if (GNUNET_NO == ac->finished)
84 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) 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_log (GNUNET_ERROR_TYPE_DEBUG,
106 "Received message\n");
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 ts->finished_cb (rv);
133 GNUNET_free (ts->testdir);
134 GNUNET_free (ts->cfgname);
135 GNUNET_TESTING_free_topology (ts->topology);
136 GNUNET_free (ts);
137}
138
139
140/**
141 * Callback from start peer cmd for signaling a peer got connected.
142 *
143 */
144static void *
145notify_connect (struct GNUNET_TESTING_Interpreter *is,
146 const struct GNUNET_PeerIdentity *peer)
147{
148 struct GNUNET_TESTING_AsyncContext *ac;
149 void *ret = NULL;
150 const struct GNUNET_TESTING_Command *cmd;
151 struct GNUNET_TESTING_BlockState *bs;
152
153 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
154 "notify_connect\n");
155 GNUNET_TESTING_get_trait_async_context (&connect_peers,
156 &ac);
157 if (NULL != ac->is)
158 {
159 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
160 "notify_connect running\n");
161 GNUNET_assert (NULL != ac);
162 if (NULL == ac->cont)
163 GNUNET_TESTING_async_fail (ac);
164 else
165 GNUNET_TESTING_async_finish (ac);
166 }
167 else
168 {
169 cmd = GNUNET_TESTING_interpreter_lookup_future_command (is,
170 "connect-peers");
171 LOG (GNUNET_ERROR_TYPE_DEBUG,
172 "block state %s\n",
173 cmd->label.value);
174 GNUNET_TESTING_get_trait_block_state (
175 cmd,
176 &bs);
177
178 LOG (GNUNET_ERROR_TYPE_DEBUG,
179 "block state %u\n",
180 bs->asynchronous_finish);
181 bs->asynchronous_finish = GNUNET_YES;
182 LOG (GNUNET_ERROR_TYPE_DEBUG,
183 "block state %u\n",
184 bs->asynchronous_finish);
185 }
186
187 return ret;
188}
189
190
191/**
192 * Callback to set the flag indicating all peers are prepared to finish. Will be called via the plugin api.
193 */
194static void
195all_local_tests_prepared ()
196{
197 const struct GNUNET_TESTING_LocalPreparedState *lfs;
198
199 GNUNET_TESTING_get_trait_local_prepared_state (&local_prepared,
200 &lfs);
201 GNUNET_assert (NULL != &lfs->ac);
202 if (NULL == lfs->ac.cont)
203 GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) &lfs->ac);
204 else
205 GNUNET_TESTING_async_finish ((struct
206 GNUNET_TESTING_AsyncContext *) &lfs->ac);
207}
208
209
210/**
211 * Function to start a local test case.
212 *
213 * @param write_message Callback to send a message to the master loop.
214 * @param router_ip Global address of the network namespace.
215 * @param node_ip The IP address of the node.
216 * @param m The number of the node in a network namespace.
217 * @param n The number of the network namespace.
218 * @param local_m The number of nodes in a network namespace.
219 */
220static struct GNUNET_TESTING_Interpreter *
221start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
222 const char *router_ip,
223 const char *node_ip,
224 const char *m,
225 const char *n,
226 const char *local_m,
227 const char *topology_data,
228 unsigned int *read_file,
229 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
230{
231 unsigned int n_int;
232 unsigned int m_int;
233 unsigned int local_m_int;
234 unsigned int num;
235 struct TestState *ts = GNUNET_new (struct TestState);
236 struct GNUNET_TESTING_NetjailTopology *topology;
237 unsigned int sscanf_ret = 0;
238
239 ts->finished_cb = finished_cb;
240 LOG (GNUNET_ERROR_TYPE_ERROR,
241 "n %s m %s\n",
242 n,
243 m);
244
245 if (GNUNET_YES == *read_file)
246 {
247 LOG (GNUNET_ERROR_TYPE_DEBUG,
248 "read from file\n");
249 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
250 }
251 else
252 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
253
254 ts->topology = topology;
255
256 errno = 0;
257 sscanf_ret = sscanf (m, "%u", &m_int);
258 if (errno != 0)
259 {
260 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
261 }
262 GNUNET_assert (0 < sscanf_ret);
263 errno = 0;
264 sscanf_ret = sscanf (n, "%u", &n_int);
265 if (errno != 0)
266 {
267 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
268 }
269 GNUNET_assert (0 < sscanf_ret);
270 errno = 0;
271 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
272 if (errno != 0)
273 {
274 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
275 }
276 GNUNET_assert (0 < sscanf_ret);
277
278 if (0 == n_int)
279 num = m_int;
280 else
281 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
282
283 block_send = GNUNET_TESTING_cmd_block_until_external_trigger ("block");
284 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
285 "block-receive");
286 connect_peers = GNUNET_TESTING_cmd_block_until_external_trigger (
287 "connect-peers");
288 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
289 "local-test-prepared",
290 write_message);
291
292
293 GNUNET_asprintf (&ts->cfgname,
294 "test_transport_api2_tcp_node1.conf");
295
296 LOG (GNUNET_ERROR_TYPE_DEBUG,
297 "plugin cfgname: %s\n",
298 ts->cfgname);
299
300 LOG (GNUNET_ERROR_TYPE_DEBUG,
301 "node ip: %s\n",
302 node_ip);
303
304 GNUNET_asprintf (&ts->testdir,
305 "%s%s%s",
306 BASE_DIR,
307 m,
308 n);
309
310 struct GNUNET_MQ_MessageHandler handlers[] = {
311 GNUNET_MQ_hd_var_size (test,
312 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
313 struct GNUNET_TRANSPORT_TESTING_TestMessage,
314 ts),
315 GNUNET_MQ_handler_end ()
316 };
317
318 struct GNUNET_TESTING_Command commands[] = {
319 GNUNET_TESTING_cmd_system_create ("system-create",
320 ts->testdir),
321 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
322 "system-create",
323 num,
324 node_ip,
325 handlers,
326 ts->cfgname,
327 notify_connect,
328 GNUNET_YES),
329 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
330 write_message),
331 block_send,
332 connect_peers,
333 GNUNET_TRANSPORT_cmd_send_simple ("send-simple",
334 "start-peer",
335 "system-create",
336 num,
337 topology),
338 block_receive,
339 local_prepared,
340 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
341 "start-peer"),
342 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
343 "system-create"),
344 GNUNET_TESTING_cmd_end ()
345 };
346
347 ts->write_message = write_message;
348
349 is = GNUNET_TESTING_run (commands,
350 TIMEOUT,
351 &handle_result,
352 ts);
353 return is;
354}
355
356
357/**
358 * Entry point for the plugin.
359 *
360 * @param cls NULL
361 * @return the exported block API
362 */
363void *
364libgnunet_test_transport_plugin_cmd_simple_send_broadcast_init (void *cls)
365{
366 struct GNUNET_TESTING_PluginFunctions *api;
367
368 GNUNET_log_setup ("simple-send",
369 "DEBUG",
370 NULL);
371
372 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
373 api->start_testcase = &start_testcase;
374 api->all_peers_started = &all_peers_started;
375 api->all_local_tests_prepared = all_local_tests_prepared;
376 api->get_waiting_for_barriers = get_waiting_for_barriers;
377 return api;
378}
379
380
381/**
382 * Exit point from the plugin.
383 *
384 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
385 * @return NULL
386 */
387void *
388libgnunet_test_transport_plugin_cmd_simple_send_broadcast_done (void *cls)
389{
390 struct GNUNET_TESTING_PluginFunctions *api = cls;
391
392 GNUNET_free (api);
393 return NULL;
394}
395
396
397/* 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..fe92e0ad9
--- /dev/null
+++ b/src/service/transport/test_transport_plugin_cmd_simple_send_performance.c
@@ -0,0 +1,478 @@
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_util_lib.h"
28#include "gnunet_testing_lib.h"
29#include "gnunet_transport_application_service.h"
30#include "transport-testing2.h"
31#include "transport-testing-cmds.h"
32
33/**
34 * Generic logging shortcut
35 */
36#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
37
38#define BASE_DIR "testdir"
39
40#define TOPOLOGY_CONFIG "test_transport_simple_send_topo.conf"
41
42#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
43
44#define MAX_RECEIVED 1000
45
46#define MESSAGE_SIZE 65000
47
48static struct GNUNET_TESTING_Command block_send;
49
50static struct GNUNET_TESTING_Command block_receive;
51
52static struct GNUNET_TESTING_Command connect_peers;
53
54static struct GNUNET_TESTING_Command local_prepared;
55
56static struct GNUNET_TESTING_Command start_peer;
57
58static struct GNUNET_TESTING_Interpreter *is;
59
60static struct GNUNET_CONTAINER_MultiPeerMap *senders;
61
62struct Sender
63{
64 /**
65 * Number of received messages from sender.
66 */
67 unsigned long long num_received;
68
69 /**
70 * Sample mean time the message traveled.
71 */
72 struct GNUNET_TIME_Relative mean_time;
73
74 /**
75 * Time the first message was send.
76 */
77 struct GNUNET_TIME_Absolute time_first;
78};
79
80/**
81 * Function called to check a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE being
82 * received.
83 *
84 */
85static int
86check_test (void *cls,
87 const struct
88 GNUNET_TRANSPORT_TESTING_PerformanceTestMessage *message)
89{
90 return GNUNET_OK;
91}
92
93
94/**
95 * Function called to handle a message of type GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE
96 * being received.
97 *
98 */
99static void
100handle_test (void *cls,
101 const struct
102 GNUNET_TRANSPORT_TESTING_PerformanceTestMessage *message)
103{
104 struct GNUNET_PeerIdentity *peer = cls;
105 struct GNUNET_TESTING_AsyncContext *ac;
106 struct Sender *sender;
107 struct GNUNET_TIME_Absolute time_send;
108 struct GNUNET_TIME_Absolute now;
109 struct GNUNET_TIME_Relative time_traveled;
110 uint32_t num;
111 struct GNUNET_TRANSPORT_CoreHandle *ch;
112 const struct GNUNET_TESTING_StartPeerState *sps;
113
114
115 GNUNET_TRANSPORT_TESTING_get_trait_state (&start_peer,
116 &sps);
117 ch = sps->th;
118 num = ntohl (message->num);
119 GNUNET_TESTING_get_trait_async_context (&block_receive,
120 &ac);
121 GNUNET_assert (NULL != ac);
122
123 sender = GNUNET_CONTAINER_multipeermap_get (senders, peer);
124
125 now = GNUNET_TIME_absolute_get ();
126 time_send = GNUNET_TIME_absolute_ntoh (message->time_send);
127
128 time_traveled = GNUNET_TIME_absolute_get_difference (time_send, now);
129
130 if (NULL == sender)
131 {
132 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
133 "time traveled init %s\n",
134 GNUNET_i2s (peer));
135 sender = GNUNET_new (struct Sender);
136 sender->time_first = time_send;
137 sender->mean_time = GNUNET_TIME_UNIT_ZERO;
138 GNUNET_assert (GNUNET_OK == GNUNET_CONTAINER_multipeermap_put (senders,
139 peer, sender,
140 GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
141 }
142
143 if (GNUNET_TIME_UNIT_ZERO.rel_value_us == sender->mean_time.rel_value_us)
144 {
145 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
146 "time traveld mean zero\n");
147 sender->mean_time = time_traveled;
148 }
149 else
150 {
151 double factor = (double) sender->num_received
152 / ((double) sender->num_received + 1.0);
153 struct GNUNET_TIME_Relative s1;
154 struct GNUNET_TIME_Relative s2;
155
156 s1 = GNUNET_TIME_relative_multiply (sender->mean_time,
157 factor);
158 s2 = GNUNET_TIME_relative_divide (time_traveled,
159 sender->num_received + 1);
160 sender->mean_time = GNUNET_TIME_relative_add (s1, s2);
161 }
162
163 sender->num_received++;
164
165 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
166 "time traveled: %llu\n",
167 (unsigned long long) time_traveled.rel_value_us);
168 GNUNET_log (GNUNET_ERROR_TYPE_INFO,
169 "mean time traveled: %s %llu messages received with message number %u\n",
170 GNUNET_STRINGS_relative_time_to_string (sender->mean_time,
171 false),
172 sender->num_received,
173 num);
174 if (floor (MAX_RECEIVED * (1 - 1.0 / 200)) < sender->num_received && NULL ==
175 ac->cont)
176 {
177 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
178 "time traveled failed\n");
179 // GNUNET_TESTING_async_fail ((struct GNUNET_TESTING_AsyncContext *) ac);
180 }
181 else if (floor (MAX_RECEIVED * (1 - 1.0 / 200)) < sender->num_received &&
182 GNUNET_NO == ac->finished)
183 {
184 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
185 "time traveled finish\n");
186 GNUNET_TESTING_async_finish ((struct GNUNET_TESTING_AsyncContext *) ac);
187 }
188 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
189 "time traveled end\n");
190 GNUNET_TRANSPORT_core_receive_continue (ch, peer);
191}
192
193
194struct GNUNET_TESTING_BarrierList*
195get_waiting_for_barriers ()
196{
197 struct GNUNET_TESTING_BarrierList*barriers;
198 struct GNUNET_TESTING_BarrierListEntry *ble;
199
200 barriers = GNUNET_new (struct GNUNET_TESTING_BarrierList);
201 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
202 ble->barrier_name = "ready-to-connect";
203 ble->expected_reaches = 1;
204 GNUNET_CONTAINER_DLL_insert (barriers->head,
205 barriers->tail,
206 ble);
207
208 ble = GNUNET_new (struct GNUNET_TESTING_BarrierListEntry);
209 ble->barrier_name = "test-case-finished";
210 ble->expected_reaches = 1;
211 GNUNET_CONTAINER_DLL_insert (barriers->head,
212 barriers->tail,
213 ble);
214 return barriers;
215}
216
217
218/**
219 * Function called with the final result of the test.
220 *
221 * @param cls the `struct MainParams`
222 * @param rv #GNUNET_OK if the test passed
223 */
224static void
225handle_result (void *cls,
226 enum GNUNET_GenericReturnValue rv)
227{
228 struct TestState *ts = cls;
229
230 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
231 "Local test exits with status %d\n",
232 rv);
233
234 ts->finished_cb (rv);
235 GNUNET_free (ts->testdir);
236 GNUNET_free (ts->cfgname);
237 GNUNET_TESTING_free_topology (ts->topology);
238 GNUNET_free (ts);
239}
240
241
242/**
243 * Callback from start peer cmd for signaling a peer got connected.
244 *
245 */
246static void *
247notify_connect (struct GNUNET_TESTING_Interpreter *is,
248 const struct GNUNET_PeerIdentity *peer)
249{
250 const struct ConnectPeersState *cps;
251 const struct GNUNET_TESTING_Command *cmd;
252
253 cmd = GNUNET_TESTING_interpreter_lookup_command (is,
254 "connect-peers");
255 GNUNET_TRANSPORT_TESTING_get_trait_connect_peer_state (cmd,
256 &cps);
257 void *ret = NULL;
258
259 cps->notify_connect (is,
260 peer);
261 return ret;
262}
263
264
265/**
266 * Function to start a local test case.
267 *
268 * @param write_message Callback to send a message to the master loop.
269 * @param router_ip Global address of the network namespace.
270 * @param node_ip The IP address of the node.
271 * @param m The number of the node in a network namespace.
272 * @param n The number of the network namespace.
273 * @param local_m The number of nodes in a network namespace.
274 * @param topology_data A file name for the file containing the topology configuration, or a string containing
275 * the topology configuration.
276 * @param read_file If read_file is GNUNET_YES this string is the filename for the topology configuration,
277 * if read_file is GNUNET_NO the string contains the topology configuration.
278 * @param finish_cb Callback function which writes a message from the helper process running on a netjail
279 * node to the master process * signaling that the test case running on the netjail node finished.
280 * @return Returns the struct GNUNET_TESTING_Interpreter of the command loop running on this netjail node.
281 */
282static struct GNUNET_TESTING_Interpreter *
283start_testcase (GNUNET_TESTING_cmd_helper_write_cb write_message,
284 const char *router_ip,
285 const char *node_ip,
286 const char *m,
287 const char *n,
288 const char *local_m,
289 const char *topology_data,
290 unsigned int *read_file,
291 GNUNET_TESTING_cmd_helper_finish_cb finished_cb)
292{
293
294 unsigned int n_int;
295 unsigned int m_int;
296 unsigned int local_m_int;
297 unsigned int num;
298 struct TestState *ts = GNUNET_new (struct TestState);
299 struct GNUNET_TESTING_NetjailTopology *topology;
300 unsigned int sscanf_ret = 0;
301
302 senders = GNUNET_CONTAINER_multipeermap_create (1, GNUNET_NO);
303 ts->finished_cb = finished_cb;
304 LOG (GNUNET_ERROR_TYPE_ERROR,
305 "n %s m %s\n",
306 n,
307 m);
308
309 if (GNUNET_YES == *read_file)
310 {
311 LOG (GNUNET_ERROR_TYPE_DEBUG,
312 "read from file\n");
313 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
314 }
315 else
316 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
317
318 ts->topology = topology;
319
320 errno = 0;
321 sscanf_ret = sscanf (m, "%u", &m_int);
322 if (errno != 0)
323 {
324 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
325 }
326 GNUNET_assert (0 < sscanf_ret);
327 errno = 0;
328 sscanf_ret = sscanf (n, "%u", &n_int);
329 if (errno != 0)
330 {
331 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
332 }
333 GNUNET_assert (0 < sscanf_ret);
334 errno = 0;
335 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
336 if (errno != 0)
337 {
338 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
339 }
340 GNUNET_assert (0 < sscanf_ret);
341
342 if (0 == n_int)
343 num = m_int;
344 else
345 num = (n_int - 1) * local_m_int + m_int + topology->nodes_x;
346
347 block_send = GNUNET_TESTING_cmd_block_until_external_trigger (
348 "block");
349 block_receive = GNUNET_TESTING_cmd_block_until_external_trigger (
350 "block-receive");
351 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
352 "start-peer",
353 "system-create",
354 num,
355 topology,
356 0,
357 GNUNET_YES);
358 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
359 "local-test-prepared",
360 write_message);
361
362
363 GNUNET_asprintf (&ts->cfgname,
364 "test_transport_api2_tcp_node1.conf");
365
366 LOG (GNUNET_ERROR_TYPE_DEBUG,
367 "plugin cfgname: %s\n",
368 ts->cfgname);
369
370 LOG (GNUNET_ERROR_TYPE_DEBUG,
371 "node ip: %s\n",
372 node_ip);
373
374 GNUNET_asprintf (&ts->testdir,
375 "%s%s%s",
376 BASE_DIR,
377 m,
378 n);
379
380 struct GNUNET_MQ_MessageHandler handlers[] = {
381 GNUNET_MQ_hd_var_size (test,
382 GNUNET_TRANSPORT_TESTING_SIMPLE_PERFORMANCE_MTYPE,
383 struct
384 GNUNET_TRANSPORT_TESTING_PerformanceTestMessage,
385 ts),
386 GNUNET_MQ_handler_end ()
387 };
388
389 start_peer = GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
390 "system-create",
391 num,
392 node_ip,
393 handlers,
394 ts->cfgname,
395 notify_connect,
396 GNUNET_NO);
397
398 struct GNUNET_TESTING_Command commands[] = {
399 GNUNET_TESTING_cmd_system_create ("system-create",
400 ts->testdir),
401 start_peer,
402 GNUNET_TESTING_cmd_barrier_reached ("ready-to-connect-reached",
403 "ready-to-connect",
404 GNUNET_NO,
405 num,
406 GNUNET_NO,
407 write_message),
408 connect_peers,
409 GNUNET_TRANSPORT_cmd_send_simple_performance ("send-simple",
410 "start-peer",
411 "system-create",
412 num,
413 MESSAGE_SIZE,
414 MAX_RECEIVED,
415 topology),
416 block_receive,
417 GNUNET_TESTING_cmd_barrier_reached ("test-case-finished-reached",
418 "test-case-finished",
419 GNUNET_NO,
420 num,
421 GNUNET_NO,
422 write_message),
423 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
424 "start-peer"),
425 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
426 "system-create"),
427 GNUNET_TESTING_cmd_end ()
428 };
429
430 ts->write_message = write_message;
431
432 is = GNUNET_TESTING_run (commands,
433 TIMEOUT,
434 &handle_result,
435 ts);
436 return is;
437}
438
439
440/**
441 * Entry point for the plugin.
442 *
443 * @param cls NULL
444 * @return the exported block API
445 */
446void *
447libgnunet_test_transport_plugin_cmd_simple_send_performance_init (void *cls)
448{
449 struct GNUNET_TESTING_PluginFunctions *api;
450
451 GNUNET_log_setup ("simple-send",
452 "DEBUG",
453 NULL);
454
455 api = GNUNET_new (struct GNUNET_TESTING_PluginFunctions);
456 api->start_testcase = &start_testcase;
457 api->get_waiting_for_barriers = get_waiting_for_barriers;
458 return api;
459}
460
461
462/**
463 * Exit point from the plugin.
464 *
465 * @param cls the return value from #libgnunet_test_transport_plugin_simple_send_performance_init
466 * @return NULL
467 */
468void *
469libgnunet_test_transport_plugin_cmd_simple_send_performance_done (void *cls)
470{
471 struct GNUNET_TESTING_PluginFunctions *api = cls;
472
473 GNUNET_free (api);
474 return NULL;
475}
476
477
478/* 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..7e67d6fad
--- /dev/null
+++ b/src/service/transport/test_transport_plugin_cmd_udp_backchannel.c
@@ -0,0 +1,364 @@
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 * Entry point for the plugin.
180 *
181 * @param cls NULL
182 * @return the exported block API
183 */
184void *
185libgnunet_test_transport_plugin_cmd_udp_backchannel_init (void *cls)
186{
187 struct GNUNET_TESTING_PluginFunctions *api;
188
189 unsigned int n_int;
190 unsigned int m_int;
191 unsigned int local_m_int;
192 unsigned int num;
193 struct TestState *ts = GNUNET_new (struct TestState);
194 struct GNUNET_TESTING_NetjailTopology *topology;
195 unsigned int sscanf_ret = 0;
196
197 ts->finished_cb = finished_cb;
198 LOG (GNUNET_ERROR_TYPE_ERROR,
199 "n %s m %s\n",
200 n,
201 m);
202
203 if (GNUNET_YES == *read_file)
204 {
205 LOG (GNUNET_ERROR_TYPE_DEBUG,
206 "read from file\n");
207 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
208 }
209 else
210 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
211
212 ts->topology = topology;
213
214 errno = 0;
215 sscanf_ret = sscanf (m, "%u", &m_int);
216 if (errno != 0)
217 {
218 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
219 }
220 GNUNET_assert (0 < sscanf_ret);
221 errno = 0;
222 sscanf_ret = sscanf (n, "%u", &n_int);
223 if (errno != 0)
224 {
225 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
226 }
227 GNUNET_assert (0 < sscanf_ret);
228 errno = 0;
229 sscanf_ret = sscanf (local_m, "%u", &local_m_int);
230 if (errno != 0)
231 {
232 GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sscanf");
233 }
234 GNUNET_assert (0 < sscanf_ret);
235
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 connect_peers = GNUNET_TRANSPORT_cmd_connect_peers ("connect-peers",
245 "start-peer",
246 "system-create",
247 num,
248 topology,
249 0,
250 GNUNET_YES);
251 local_prepared = GNUNET_TESTING_cmd_local_test_prepared (
252 "local-test-prepared",
253 write_message);
254
255 GNUNET_asprintf (&ts->cfgname,
256 "test_transport_api2_tcp_node1.conf");
257
258 LOG (GNUNET_ERROR_TYPE_DEBUG,
259 "plugin cfgname: %s\n",
260 ts->cfgname);
261
262 LOG (GNUNET_ERROR_TYPE_DEBUG,
263 "node ip: %s\n",
264 node_ip);
265
266 GNUNET_asprintf (&ts->testdir,
267 "%s%s%s",
268 BASE_DIR,
269 m,
270 n);
271
272 struct GNUNET_MQ_MessageHandler handlers[] = {
273 GNUNET_MQ_hd_var_size (test,
274 GNUNET_TRANSPORT_TESTING_SIMPLE_MTYPE,
275 struct GNUNET_TRANSPORT_TESTING_TestMessage,
276 NULL),
277 GNUNET_MQ_handler_end ()
278 };
279
280 struct GNUNET_TESTING_Command commands[] = {
281 GNUNET_TESTING_cmd_system_create ("system-create",
282 ts->testdir),
283 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
284 "system-create",
285 num,
286 node_ip,
287 handlers,
288 ts->cfgname,
289 notify_connect,
290 GNUNET_NO),
291 GNUNET_TESTING_cmd_send_peer_ready ("send-peer-ready",
292 write_message),
293 block_send,
294 connect_peers,
295 GNUNET_TRANSPORT_cmd_backchannel_check ("backchannel-check",
296 "start-peer",
297 "system-create",
298 num,
299 m_int,
300 n_int,
301 topology),
302 local_prepared,
303 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
304 "start-peer"),
305 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
306 "system-create"),
307 GNUNET_TESTING_cmd_end ()
308 };
309
310 return GNUNET_TESTING_make_plugin (commands);
311}
312
313
314GNUNET_TESTING_MAKE_PLUGIN (
315 libgnunet,
316 udp_backchannel,
317 GNUNET_TESTING_cmd_system_create ("system-create",
318 ts->testdir),
319 GNUNET_TRANSPORT_cmd_start_peer ("start-peer",
320 "system-create",
321 num,
322 node_ip,
323 handlers,
324 ts->cfgname,
325 notify_connect,
326 GNUNET_NO),
327 GNUNET_TESTING_cmd_send_peer_ready (
328 "send-peer-ready",
329 write_message),
330 block_send,
331 connect_peers,
332 GNUNET_TRANSPORT_cmd_backchannel_check (
333 "backchannel-check",
334 "start-peer",
335 "system-create",
336 num,
337 m_int,
338 n_int,
339 topology),
340 local_prepared,
341 GNUNET_TRANSPORT_cmd_stop_peer ("stop-peer",
342 "start-peer"),
343 GNUNET_TESTING_cmd_system_destroy ("system-destroy",
344 "system-create")
345 );
346
347
348/**
349 * Exit point from the plugin.
350 *
351 * @param cls the return value from #libgnunet_test_transport_plugin_block_test_init
352 * @return NULL
353 */
354void *
355libgnunet_test_transport_plugin_cmd_udp_backchannel_done (void *cls)
356{
357 struct GNUNET_TESTING_PluginFunctions *api = cls;
358
359 GNUNET_free (api);
360 return NULL;
361}
362
363
364/* 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..af7515753
--- /dev/null
+++ b/src/service/transport/test_transport_simple_send.sh
@@ -0,0 +1,4 @@
1#!/bin/bash
2exec netjail_test_master.sh ./test_transport_start_with_config test_transport_simple_send_topo.conf
3
4# exec netjail_test_master.sh gnunet-testing-netjail-launcher 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..2c00dde8a
--- /dev/null
+++ b/src/service/transport/test_transport_start_with_config.c
@@ -0,0 +1,120 @@
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_lib.h"
28#include "gnunet_util_lib.h"
29
30#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 600)
31
32
33int
34main (int argc,
35 char *const *argv)
36{
37 char *topology_data;
38 char *topology_data_script;
39 struct GNUNET_TESTING_NetjailTopology *topology;
40 unsigned int read_file = GNUNET_YES;
41 int ret;
42 char *rest = NULL;
43 char *token;
44 size_t single_line_len;
45 size_t data_len;
46
47 GNUNET_log_setup ("test-netjail",
48 "INFO",
49 NULL);
50
51 if (0 == strcmp ("-s", argv[1]))
52 {
53 data_len = strlen (argv[2]);
54 topology_data = GNUNET_malloc (data_len);
55 topology_data_script = GNUNET_malloc (data_len);
56 token = strtok_r (argv[2], "\n", &rest);
57 while (NULL != token)
58 {
59 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
60 "token1 %s\n",
61 token);
62 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
63 "token2 %s\n",
64 token);
65 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
66 "topology_data %s\n",
67 topology_data);
68 strcat (topology_data_script, token);
69 strcat (topology_data_script, " ");
70 strcat (topology_data, token);
71 strcat (topology_data, "\n");
72 token = strtok_r (NULL, "\n", &rest);
73 }
74 single_line_len = strlen (topology_data);
75 topology_data_script [single_line_len - 1] = '\0';
76 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
77 "read from string\n");
78 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
79 "topology_data %s\n",
80 topology_data);
81 read_file = GNUNET_NO;
82 topology = GNUNET_TESTING_get_topo_from_string (topology_data);
83 }
84 else
85 {
86 topology_data = argv[1];
87 topology_data_script = argv[1];
88 topology = GNUNET_TESTING_get_topo_from_file (topology_data);
89 }
90
91 struct GNUNET_TESTING_Command commands[] = {
92 GNUNET_TESTING_cmd_netjail_start ("netjail-start",
93 topology_data_script,
94 &read_file),
95 GNUNET_TESTING_cmd_netjail_start_cmds_helper ("netjail-start-testbed",
96 topology,
97 &read_file,
98 topology_data_script,
99 TIMEOUT),
100 GNUNET_TESTING_cmd_stop_cmds_helper ("stop-testbed",
101 "netjail-start-testbed",
102 topology),
103 GNUNET_TESTING_cmd_netjail_stop ("netjail-stop",
104 topology_data_script,
105 &read_file),
106 GNUNET_TESTING_cmd_end ()
107 };
108
109 ret = GNUNET_TESTING_main (commands,
110 TIMEOUT);
111
112 if (0 == strcmp ("-s", argv[1]))
113 {
114 GNUNET_free (topology_data_script);
115 GNUNET_free (topology_data);
116 }
117 GNUNET_TESTING_free_topology (topology);
118
119 return ret;
120}
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_transport_traits.c b/src/service/transport/testing_transport_traits.c
new file mode 100644
index 000000000..131c42a5d
--- /dev/null
+++ b/src/service/transport/testing_transport_traits.c
@@ -0,0 +1,35 @@
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_util_lib.h"
28#include "gnunet_testing_lib.h"
29#include "transport-testing-cmds.h"
30
31GNUNET_TRANSPORT_SIMPLE_TRAITS (GNUNET_TESTING_MAKE_IMPL_SIMPLE_TRAIT,
32 GNUNET_TRANSPORT_TESTING)
33
34GNUNET_TRANSPORT_TESTING_SIMPLE_TRAITS (GNUNET_TESTING_MAKE_IMPL_SIMPLE_TRAIT,
35 GNUNET_TRANSPORT_TESTING)
diff --git a/src/service/transport/transport-testing-cmds.h b/src/service/transport/transport-testing-cmds.h
new file mode 100644
index 000000000..478b3cba6
--- /dev/null
+++ b/src/service/transport/transport-testing-cmds.h
@@ -0,0 +1,261 @@
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_lib.h"
31#include "gnunet_testing_transport_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_TESTBED_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
107typedef void *
108(*GNUNET_TRANSPORT_notify_connect_cb) (struct GNUNET_TESTING_Interpreter *is,
109 const struct GNUNET_PeerIdentity *peer);
110
111
112struct TestState
113{
114 /**
115 * The name for a specific test environment directory.
116 *
117 */
118 char *testdir;
119
120 /**
121 * The name for the configuration file of the specific node.
122 *
123 */
124 char *cfgname;
125
126 /**
127 * The complete topology information.
128 */
129 struct GNUNET_TESTING_NetjailTopology *topology;
130};
131
132
133/**
134 * Create command.
135 *
136 * @param label name for command.
137 * @param system_label Label of the cmd to setup a test environment.
138 * @param no Decimal number representing the last byte of the IP address of this peer.
139 * @param node_ip The IP address of this node.
140 * @param handlers Handler for messages received by this peer.
141 * @param cfgname Configuration file name for this peer.
142 * @param notify_connect Method which will be called, when a peer connects.
143 * @param broadcast Flag indicating, if broadcast should be switched on.
144 * @return command.
145 */
146struct GNUNET_TESTING_Command
147GNUNET_TRANSPORT_cmd_start_peer (const char *label,
148 const char *system_label,
149 uint32_t no,
150 const char *node_ip,
151 struct GNUNET_MQ_MessageHandler *handlers,
152 const char *cfgname,
153 GNUNET_TRANSPORT_notify_connect_cb
154 notify_connect,
155 unsigned int broadcast);
156
157
158struct GNUNET_TESTING_Command
159GNUNET_TRANSPORT_cmd_stop_peer (const char *label,
160 const char *start_label);
161
162
163/**
164 * Create command
165 *
166 * @param label name for command
167 * @param start_peer_label Label of the cmd to start a peer.
168 * @param create_label Label of the cmd which started the test system.
169 * @param num Number globally identifying the node.
170 * @param topology The topology for the test setup.
171 * @param additional_connects Number of additional connects this cmd will wait for not triggered by this cmd.
172 * @return command.
173 */
174struct GNUNET_TESTING_Command
175GNUNET_TRANSPORT_cmd_connect_peers (
176 const char *label,
177 const char *start_peer_label,
178 const char *create_label,
179 uint32_t num,
180 struct GNUNET_TESTING_NetjailTopology *topology,
181 unsigned int additional_connects,
182 unsigned int wait_for_connect);
183
184
185/**
186 * Create command.
187 *
188 * @param label name for command.
189 * @param start_peer_label Label of the cmd to start a peer.
190 * @param create_label Label of the cmd which started the test system.
191 * @param num Number globally identifying the node.
192 * @param topology The topology for the test setup.
193 * @return command.
194 */
195struct GNUNET_TESTING_Command
196GNUNET_TRANSPORT_cmd_send_simple (const char *label,
197 const char *start_peer_label,
198 const char *create_label,
199 uint32_t num,
200 struct GNUNET_TESTING_NetjailTopology *
201 topology);
202
203/**
204 *
205 *
206 * @param label name for command.
207 * @param start_peer_label Label of the cmd to start a peer.
208 * @param create_label Label of the cmd which started the test system.
209 * @param num Number globally identifying the node.
210 * @param size The size of the test message to send.
211 * @param max_send The number of messages to send.
212 * @param topology The topology for the test setup.
213 * @return command.
214 */
215struct GNUNET_TESTING_Command
216GNUNET_TRANSPORT_cmd_send_simple_performance (const char *label,
217 const char *start_peer_label,
218 const char *create_label,
219 uint32_t num,
220 int size,
221 int max_send,
222 struct
223 GNUNET_TESTING_NetjailTopology *
224 topology);
225
226
227/**
228 * Create command.
229 *
230 * @param label name for command.
231 * @param start_peer_label Label of the cmd to start a peer.
232 * @param create_label Label of the cmd to create the testing system.
233 * @param num Number globally identifying the node.
234 * @param node_n The number of the node in a network namespace.
235 * @param namespace_n The number of the network namespace.
236 * @param topology The topology for the test setup.
237 * @return command.
238 */
239struct GNUNET_TESTING_Command
240GNUNET_TRANSPORT_cmd_backchannel_check (const char *label,
241 const char *start_peer_label,
242 const char *create_label,
243 uint32_t num,
244 unsigned int node_n,
245 unsigned int namespace_n,
246 struct GNUNET_TESTING_NetjailTopology *
247 topology);
248
249
250/**
251 * Call #op on all simple traits.
252 */
253#define GNUNET_TRANSPORT_SIMPLE_TRAITS(op, prefix) \
254 op (prefix, connect_peer_state, const struct ConnectPeersState)
255
256GNUNET_TRANSPORT_SIMPLE_TRAITS (GNUNET_TESTING_MAKE_DECL_SIMPLE_TRAIT,
257 GNUNET_TRANSPORT_TESTING)
258
259
260#endif
261/* 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..42ffce3f2
--- /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_TESTBED_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..6fa61adb7
--- /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_TESTBED_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_TESTBED_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..280c0e9a2
--- /dev/null
+++ b/src/service/transport/transport_api_cmd_connecting_peers.c
@@ -0,0 +1,315 @@
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_lib.h"
29#include "gnunet_testbed_lib.h"
30#include "gnunet_transport_testing_ng_lib.h"
31#include "transport-testing-cmds.h"
32#include "gnunet_transport_application_service.h"
33
34/**
35 * Generic logging shortcut
36 */
37#define LOG(kind, ...) GNUNET_log (kind, __VA_ARGS__)
38
39/**
40 * The run method of this cmd will connect to peers.
41 *
42 */
43static void
44connect_peers_run (void *cls,
45 struct GNUNET_TESTING_Interpreter *is)
46{
47 struct ConnectPeersState *cps = cls;
48 const struct GNUNET_TESTING_Command *system_cmd;
49 const struct GNUNET_TESTBED_System *tl_system;
50
51
52 const struct GNUNET_TESTING_Command *peer1_cmd;
53 const struct GNUNET_TRANSPORT_ApplicationHandle *ah;
54 struct GNUNET_PeerIdentity *peer;
55 char *addr;
56 char *addr_and_port;
57 enum GNUNET_NetworkType nt = 0;
58 uint32_t num;
59 struct GNUNET_TESTING_NodeConnection *pos_connection;
60 struct GNUNET_TESTING_AddressPrefix *pos_prefix;
61 unsigned int con_num = 0;
62 const enum GNUNET_GenericReturnValue *broadcast;
63
64 cps->is = is;
65 peer1_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
66 cps->start_peer_label);
67 if (GNUNET_YES == cps->wait_for_connect)
68 {
69 LOG (GNUNET_ERROR_TYPE_DEBUG,
70 "Wait for connect.\n");
71 GNUNET_TRANSPORT_TESTING_get_trait_application_handle (peer1_cmd,
72 &ah);
73 }
74 else
75 {
76 LOG (GNUNET_ERROR_TYPE_DEBUG,
77 "Not waiting for connect.\n");
78 GNUNET_TRANSPORT_TESTING_get_trait_application_handle (peer1_cmd,
79 &ah);
80 }
81
82 GNUNET_TRANSPORT_TESTING_get_trait_broadcast (peer1_cmd,
83 &broadcast);
84
85 system_cmd = GNUNET_TESTING_interpreter_lookup_command (is,
86 cps->create_label);
87 GNUNET_TESTBED_get_trait_test_system (system_cmd,
88 &tl_system);
89
90 cps->tl_system = tl_system;
91
92 LOG (GNUNET_ERROR_TYPE_DEBUG,
93 "cps->num: %u \n",
94 cps->num);
95
96 cps->node_connections_head = GNUNET_TESTING_get_connections (cps->num,
97 cps->topology);
98
99 for (pos_connection = cps->node_connections_head; NULL != pos_connection;
100 pos_connection = pos_connection->next)
101 {
102 con_num++;
103 num = GNUNET_TESTING_calculate_num (pos_connection, cps->topology);
104 for (pos_prefix = pos_connection->address_prefixes_head; NULL != pos_prefix;
105 pos_prefix =
106 pos_prefix->next)
107 {
108 addr = GNUNET_TESTING_get_address (pos_connection,
109 pos_prefix->address_prefix);
110 if (NULL != addr)
111 {
112 char *natted_p = strstr (pos_prefix->address_prefix, "_");
113
114 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
115 "0 validating peer number %s %s %s\n",
116 natted_p,
117 pos_prefix->address_prefix,
118 addr);
119 if (0 == GNUNET_memcmp (pos_prefix->address_prefix, "udp"))
120 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
121 "validating memcmp\n");
122 if (GNUNET_YES == *broadcast)
123 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
124 "validating broadcast\n");
125 if ((0 == GNUNET_memcmp (pos_prefix->address_prefix, "udp")) &&
126 (GNUNET_YES == *broadcast) )
127 GNUNET_asprintf (&addr_and_port,
128 "%s:2086",
129 addr);
130 else if (NULL == natted_p)
131 GNUNET_asprintf (&addr_and_port,
132 "%s:60002",
133 addr);
134 else if (NULL != natted_p)
135 {
136 char *prefix;
137 char *rest;
138 char *address;
139
140 prefix = strtok (addr, "_");
141 rest = strtok (NULL, "_");
142 strtok (rest, "-");
143 address = strtok (NULL, "-");
144
145 GNUNET_asprintf (&addr_and_port,
146 "%s-%s:0",
147 prefix,
148 address);
149
150 }
151 peer = GNUNET_TESTING_get_peer (num, tl_system);
152 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
153 "validating peer number %u with identity %s and address %s %u %s and handle %p\n",
154 num,
155 GNUNET_i2s (peer),
156 addr_and_port,
157 *broadcast,
158 pos_prefix->address_prefix,
159 ah);
160 GNUNET_TRANSPORT_application_validate ((struct
161 GNUNET_TRANSPORT_ApplicationHandle
162 *) ah,
163 peer,
164 nt,
165 addr_and_port);
166 GNUNET_free (peer);
167 GNUNET_free (addr);
168 GNUNET_free (addr_and_port);
169 }
170 }
171 }
172 cps->con_num = con_num;
173}
174
175
176/**
177 * Callback from start peer cmd for signaling a peer got connected.
178 *
179 */
180static void *
181notify_connect (struct GNUNET_TESTING_Interpreter *is,
182 const struct GNUNET_PeerIdentity *peer)
183{
184 const struct GNUNET_TESTING_Command *cmd;
185 struct ConnectPeersState *cps;
186 struct GNUNET_PeerIdentity *peer_connection;
187 unsigned int num;
188 unsigned int con_num;
189 void *ret = NULL;
190
191 cmd = GNUNET_TESTING_interpreter_lookup_command_all (is,
192 "connect-peers");
193 cps = cmd->cls; // WTF? Never go directly into cls of another command! FIXME!
194 con_num = cps->con_num_notified;
195 for (struct GNUNET_TESTING_NodeConnection *pos_connection =
196 cps->node_connections_head;
197 NULL != pos_connection;
198 pos_connection = pos_connection->next)
199 {
200 num = GNUNET_TESTING_calculate_num (pos_connection,
201 cps->topology);
202 peer_connection = GNUNET_TESTING_get_peer (num,
203 cps->tl_system);
204 if (0 == GNUNET_memcmp (peer,
205 peer_connection))
206 cps->con_num_notified++;
207 GNUNET_free (peer_connection);
208 }
209 if (cps->con_num_notified == con_num)
210 cps->additional_connects_notified++;
211
212 GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
213 "con_num: %u add: %u num_notified: %u add_notified: %u peer: %s\n",
214 cps->con_num,
215 cps->additional_connects,
216 cps->con_num_notified,
217 cps->additional_connects_notified,
218 GNUNET_i2s (peer));
219 if ((cps->con_num == cps->con_num_notified) &&
220 (cps->additional_connects <= cps->additional_connects_notified))
221 {
222 GNUNET_TESTING_async_finish (&cps->ac);
223 }
224 return ret;
225}
226
227
228/**
229 * The cleanup function of this cmd frees resources the cmd allocated.
230 *
231 */
232static void
233connect_peers_cleanup (void *cls)
234{
235 struct ConnectPeersState *cps = cls;
236
237 GNUNET_free (cps);
238}
239
240
241/**
242 * This function prepares an array with traits.
243 *
244 */
245enum GNUNET_GenericReturnValue
246connect_peers_traits (void *cls,
247 const void **ret,
248 const char *trait,
249 unsigned int index)
250{
251 struct ConnectPeersState *cps = cls;
252 struct GNUNET_TESTING_Trait traits[] = {
253 GNUNET_TRANSPORT_TESTING_make_trait_connect_peer_state ((const void *) cps),
254 GNUNET_TESTING_trait_end ()
255 };
256 return GNUNET_TESTING_get_trait (traits,
257 ret,
258 trait,
259 index);
260}
261
262
263struct GNUNET_TESTING_Command
264GNUNET_TRANSPORT_cmd_connect_peers (const char *label,
265 const char *start_peer_label,
266 const char *create_label,
267 uint32_t num,
268 struct GNUNET_TESTING_NetjailTopology *
269 topology,
270 unsigned int additional_connects,
271 unsigned int wait_for_connect)
272{
273 struct ConnectPeersState *cps;
274 unsigned int node_additional_connects;
275
276 node_additional_connects = GNUNET_TESTING_get_additional_connects (num,
277 topology);
278
279 LOG (GNUNET_ERROR_TYPE_DEBUG,
280 "global: %u and local: %u additional_connects\n",
281 additional_connects,
282 node_additional_connects);
283
284 if (0 != node_additional_connects)
285 additional_connects = node_additional_connects;
286
287 cps = GNUNET_new (struct ConnectPeersState);
288 cps->start_peer_label = start_peer_label;
289 cps->num = num;
290 cps->create_label = create_label;
291 cps->topology = topology;
292 cps->notify_connect = notify_connect;
293 cps->additional_connects = additional_connects;
294 cps->wait_for_connect = wait_for_connect;
295
296 // FIXME: wrap with cmd_make_unblocking!
297 if (GNUNET_YES == wait_for_connect)
298 return GNUNET_TESTING_command_new_ac (cps,
299 label,
300 &connect_peers_run,
301 &connect_peers_cleanup,
302 &connect_peers_traits,
303 &cps->ac);
304 else
305 return GNUNET_TESTING_command_new (cps,
306 label,
307 &connect_peers_run,
308 &connect_peers_cleanup,
309 &connect_peers_traits);
310}
311
312
313// FIXME: likely not ideally placed here, move to its own file
314GNUNET_TRANSPORT_TESTING_SIMPLE_TRAITS (GNUNET_TESTING_MAKE_IMPL_SIMPLE_TRAIT,
315 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..b0f443584
--- /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_TESTBED_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..a3012d9cd
--- /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_TESTBED_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..862d28b4c
--- /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_TESTBED_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_TESTBED_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_TESTBED_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/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