aboutsummaryrefslogtreecommitdiff
path: root/src/transport
diff options
context:
space:
mode:
authorBertrand Marc <beberking@gmail.com>2012-05-02 21:43:37 +0200
committerBertrand Marc <beberking@gmail.com>2012-05-02 21:43:37 +0200
commit2b81464a43485fcc8ce079fafdee7b7a171835f4 (patch)
tree394774c0f735199b57d51a2d3840356317853fe1 /src/transport
Imported Upstream version 0.9.2upstream/0.9.2
Diffstat (limited to 'src/transport')
-rw-r--r--src/transport/Makefile.am811
-rw-r--r--src/transport/Makefile.in2648
-rw-r--r--src/transport/gnunet-helper-transport-wlan-dummy.c439
-rw-r--r--src/transport/gnunet-helper-transport-wlan.c1758
-rw-r--r--src/transport/gnunet-service-transport.c633
-rw-r--r--src/transport/gnunet-service-transport.h72
-rw-r--r--src/transport/gnunet-service-transport_blacklist.c822
-rw-r--r--src/transport/gnunet-service-transport_blacklist.h127
-rw-r--r--src/transport/gnunet-service-transport_clients.c1057
-rw-r--r--src/transport/gnunet-service-transport_clients.h86
-rw-r--r--src/transport/gnunet-service-transport_hello.c318
-rw-r--r--src/transport/gnunet-service-transport_hello.h100
-rw-r--r--src/transport/gnunet-service-transport_neighbours.c2721
-rw-r--r--src/transport/gnunet-service-transport_neighbours.h314
-rw-r--r--src/transport/gnunet-service-transport_plugins.c230
-rw-r--r--src/transport/gnunet-service-transport_plugins.h82
-rw-r--r--src/transport/gnunet-service-transport_validation.c1276
-rw-r--r--src/transport/gnunet-service-transport_validation.h155
-rwxr-xr-xsrc/transport/gnunet-transport-certificate-creation148
-rw-r--r--src/transport/gnunet-transport-certificate-creation.c82
-rw-r--r--src/transport/gnunet-transport-wlan-sender.c237
-rw-r--r--src/transport/gnunet-transport.c619
-rw-r--r--src/transport/plugin_transport_http.c1529
-rw-r--r--src/transport/plugin_transport_http.h504
-rw-r--r--src/transport/plugin_transport_http_client.c643
-rw-r--r--src/transport/plugin_transport_http_server.c1223
-rw-r--r--src/transport/plugin_transport_tcp.c2115
-rw-r--r--src/transport/plugin_transport_template.c299
-rw-r--r--src/transport/plugin_transport_udp.c2297
-rw-r--r--src/transport/plugin_transport_udp.h291
-rw-r--r--src/transport/plugin_transport_udp_broadcasting.c522
-rw-r--r--src/transport/plugin_transport_unix.c1078
-rw-r--r--src/transport/plugin_transport_wlan.c3201
-rw-r--r--src/transport/plugin_transport_wlan.h152
-rw-r--r--src/transport/template_cfg_peer1.conf50
-rw-r--r--src/transport/template_cfg_peer2.conf50
-rw-r--r--src/transport/test_plugin_transport_data.conf25
-rw-r--r--src/transport/test_plugin_transport_data_udp.conf1
-rw-r--r--src/transport/test_quota_compliance.c632
-rw-r--r--src/transport/test_quota_compliance_data.conf25
-rw-r--r--src/transport/test_quota_compliance_http_asymmetric_peer1.conf30
-rw-r--r--src/transport/test_quota_compliance_http_asymmetric_peer2.conf30
-rw-r--r--src/transport/test_quota_compliance_http_peer1.conf30
-rw-r--r--src/transport/test_quota_compliance_http_peer2.conf30
-rw-r--r--src/transport/test_quota_compliance_https_asymmetric_peer1.conf32
-rw-r--r--src/transport/test_quota_compliance_https_asymmetric_peer2.conf32
-rw-r--r--src/transport/test_quota_compliance_https_peer1.conf32
-rw-r--r--src/transport/test_quota_compliance_https_peer2.conf32
-rw-r--r--src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf32
-rw-r--r--src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf30
-rw-r--r--src/transport/test_quota_compliance_tcp_peer1.conf32
-rw-r--r--src/transport/test_quota_compliance_tcp_peer2.conf30
-rw-r--r--src/transport/test_quota_compliance_udp_peer1.conf30
-rw-r--r--src/transport/test_quota_compliance_udp_peer2.conf31
-rw-r--r--src/transport/test_quota_compliance_unix_asymmetric_peer1.conf29
-rw-r--r--src/transport/test_quota_compliance_unix_asymmetric_peer2.conf29
-rw-r--r--src/transport/test_quota_compliance_unix_peer1.conf28
-rw-r--r--src/transport/test_quota_compliance_unix_peer2.conf32
-rw-r--r--src/transport/test_transport_api.c442
-rw-r--r--src/transport/test_transport_api_bidirectional_connect.c415
-rw-r--r--src/transport/test_transport_api_bidirectional_connect_peer1.conf31
-rw-r--r--src/transport/test_transport_api_bidirectional_connect_peer2.conf30
-rw-r--r--src/transport/test_transport_api_blacklisting.c480
-rw-r--r--src/transport/test_transport_api_data.conf12
-rw-r--r--src/transport/test_transport_api_disconnect.c436
-rw-r--r--src/transport/test_transport_api_disconnect_tcp_peer1.conf31
-rw-r--r--src/transport/test_transport_api_disconnect_tcp_peer2.conf30
-rw-r--r--src/transport/test_transport_api_http_nat_peer1.conf38
-rw-r--r--src/transport/test_transport_api_http_nat_peer2.conf31
-rw-r--r--src/transport/test_transport_api_http_peer1.conf34
-rw-r--r--src/transport/test_transport_api_http_peer2.conf31
-rw-r--r--src/transport/test_transport_api_https_nat_peer1.conf36
-rw-r--r--src/transport/test_transport_api_https_nat_peer2.conf33
-rw-r--r--src/transport/test_transport_api_https_peer1.conf32
-rw-r--r--src/transport/test_transport_api_https_peer2.conf33
-rw-r--r--src/transport/test_transport_api_limited_sockets.c383
-rw-r--r--src/transport/test_transport_api_limited_sockets_tcp_peer1.conf31
-rw-r--r--src/transport/test_transport_api_limited_sockets_tcp_peer2.conf30
-rw-r--r--src/transport/test_transport_api_multi_peer1.conf43
-rw-r--r--src/transport/test_transport_api_multi_peer2.conf46
-rw-r--r--src/transport/test_transport_api_reliability.c538
-rw-r--r--src/transport/test_transport_api_reliability_http_nat_peer1.conf38
-rw-r--r--src/transport/test_transport_api_reliability_http_nat_peer2.conf35
-rw-r--r--src/transport/test_transport_api_reliability_http_peer1.conf33
-rw-r--r--src/transport/test_transport_api_reliability_http_peer2.conf30
-rw-r--r--src/transport/test_transport_api_reliability_https_nat_peer1.conf36
-rw-r--r--src/transport/test_transport_api_reliability_https_nat_peer2.conf33
-rw-r--r--src/transport/test_transport_api_reliability_https_peer1.conf31
-rw-r--r--src/transport/test_transport_api_reliability_https_peer2.conf32
-rw-r--r--src/transport/test_transport_api_reliability_tcp_nat_peer1.conf36
-rw-r--r--src/transport/test_transport_api_reliability_tcp_nat_peer2.conf35
-rw-r--r--src/transport/test_transport_api_reliability_tcp_peer1.conf30
-rw-r--r--src/transport/test_transport_api_reliability_tcp_peer2.conf30
-rw-r--r--src/transport/test_transport_api_reliability_wlan_peer1.conf30
-rw-r--r--src/transport/test_transport_api_reliability_wlan_peer2.conf30
-rw-r--r--src/transport/test_transport_api_restart_1peer.c491
-rw-r--r--src/transport/test_transport_api_restart_2peers.c477
-rw-r--r--src/transport/test_transport_api_tcp_nat_peer1.conf36
-rw-r--r--src/transport/test_transport_api_tcp_nat_peer2.conf34
-rw-r--r--src/transport/test_transport_api_tcp_peer1.conf31
-rw-r--r--src/transport/test_transport_api_tcp_peer2.conf30
-rw-r--r--src/transport/test_transport_api_timeout.c361
-rw-r--r--src/transport/test_transport_api_timeout_http_peer1.conf36
-rw-r--r--src/transport/test_transport_api_timeout_http_peer2.conf33
-rw-r--r--src/transport/test_transport_api_timeout_https_peer1.conf32
-rw-r--r--src/transport/test_transport_api_timeout_https_peer2.conf33
-rw-r--r--src/transport/test_transport_api_timeout_tcp_peer1.conf31
-rw-r--r--src/transport/test_transport_api_timeout_tcp_peer2.conf33
-rw-r--r--src/transport/test_transport_api_timeout_udp_peer1.conf34
-rw-r--r--src/transport/test_transport_api_timeout_udp_peer2.conf32
-rw-r--r--src/transport/test_transport_api_timeout_unix_peer1.conf29
-rw-r--r--src/transport/test_transport_api_timeout_unix_peer2.conf29
-rw-r--r--src/transport/test_transport_api_udp_nat_peer1.conf37
-rw-r--r--src/transport/test_transport_api_udp_nat_peer2.conf35
-rw-r--r--src/transport/test_transport_api_udp_peer1.conf34
-rw-r--r--src/transport/test_transport_api_udp_peer2.conf32
-rw-r--r--src/transport/test_transport_api_unix_peer1.conf29
-rw-r--r--src/transport/test_transport_api_unix_peer2.conf29
-rw-r--r--src/transport/test_transport_api_unreliability.c585
-rw-r--r--src/transport/test_transport_api_unreliability_constant.c523
-rw-r--r--src/transport/test_transport_api_unreliability_constant_udp_peer1.conf31
-rw-r--r--src/transport/test_transport_api_unreliability_constant_udp_peer2.conf31
-rw-r--r--src/transport/test_transport_api_unreliability_udp_peer1.conf31
-rw-r--r--src/transport/test_transport_api_unreliability_udp_peer2.conf31
-rw-r--r--src/transport/test_transport_api_unreliability_unix_peer1.conf29
-rw-r--r--src/transport/test_transport_api_unreliability_unix_peer2.conf29
-rw-r--r--src/transport/test_transport_api_unreliability_wlan_peer1.conf30
-rw-r--r--src/transport/test_transport_api_unreliability_wlan_peer2.conf30
-rw-r--r--src/transport/test_transport_api_wlan_peer1.conf38
-rw-r--r--src/transport/test_transport_api_wlan_peer2.conf37
-rw-r--r--src/transport/test_transport_defaults.conf54
-rw-r--r--src/transport/test_transport_startonly.c189
-rw-r--r--src/transport/test_transport_startonly.conf15
-rw-r--r--src/transport/test_transport_testing.c227
-rw-r--r--src/transport/transport-testing.c872
-rw-r--r--src/transport/transport-testing.h275
-rw-r--r--src/transport/transport.conf.in67
-rw-r--r--src/transport/transport.h438
-rw-r--r--src/transport/transport_api.c1337
-rw-r--r--src/transport/transport_api_address_lookup.c369
-rw-r--r--src/transport/transport_api_address_to_string.c192
-rw-r--r--src/transport/transport_api_blacklist.c296
142 files changed, 41362 insertions, 0 deletions
diff --git a/src/transport/Makefile.am b/src/transport/Makefile.am
new file mode 100644
index 0000000..0692450
--- /dev/null
+++ b/src/transport/Makefile.am
@@ -0,0 +1,811 @@
+INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include
+
+plugindir = $(libdir)/gnunet
+
+pkgcfgdir= $(pkgdatadir)/config.d/
+
+pkgcfg_DATA = \
+ transport.conf
+
+
+if HAVE_MHD
+ GN_LIBMHD = -lmicrohttpd
+ HTTP_PLUGIN_LA = libgnunet_plugin_transport_http.la
+ HTTP_API_TEST = test_transport_api_http
+ HTTP_NAT_API_TEST = test_transport_api_http_nat
+ HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http
+ HTTP_REL_TEST = test_transport_api_reliability_http
+ HTTP_NAT_REL_TEST = test_transport_api_reliability_http_nat
+ HTTP_QUOTA_TEST = test_quota_compliance_http \
+ test_quota_compliance_http_asymmetric
+ HTTPS_PLUGIN_LA = libgnunet_plugin_transport_https.la
+ HTTPS_API_TEST = test_transport_api_https
+ HTTPS_NAT_API_TEST = test_transport_api_https_nat
+ HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https
+ HTTPS_REL_TEST = test_transport_api_reliability_https
+ HTTPS_NAT_REL_TEST = test_transport_api_reliability_https_nat
+ HTTPS_QUOTA_TEST = test_quota_compliance_https \
+ test_quota_compliance_https_asymmetric
+endif
+
+if USE_COVERAGE
+ AM_CFLAGS = --coverage -O0
+endif
+
+if LINUX
+ WLAN_BIN = gnunet-helper-transport-wlan
+ WLAN_BIN_DUMMY = gnunet-helper-transport-wlan-dummy
+ WLAN_BIN_SENDER = gnunet-transport-wlan-sender
+ WLAN_PLUGIN_LA = libgnunet_plugin_transport_wlan.la
+ WLAN_API_TEST = test_transport_api_wlan
+ WLAN_REL_TEST = test_transport_api_reliability_wlan
+ WLAN_UREL_TEST = test_transport_api_unreliability_wlan
+endif
+
+
+if LINUX
+install-exec-hook:
+ $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-transport-wlan || true
+ $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-transport-wlan || true
+else
+install-exec-hook:
+endif
+
+if !MINGW
+UNIX_PLUGIN_LA = libgnunet_plugin_transport_unix.la
+UNIX_PLUGIN_TEST = test_transport_api_unix
+UNIX_PLUGIN_TIMEOUT_TEST = test_transport_api_timeout_unix
+UNIX_REL_TEST = test_transport_api_unreliability_unix
+UNIX_QUOTA_TEST = test_quota_compliance_unix \
+ test_quota_compliance_unix_asymmetric
+endif
+
+noinst_PROGRAMS = \
+ $(WLAN_BIN_DUMMY) \
+ $(WLAN_BIN_SENDER)
+# gnunet-transport-connect-running-peers
+
+lib_LTLIBRARIES = \
+ libgnunettransport.la \
+ libgnunettransporttesting.la
+
+libgnunettransporttesting_la_SOURCES = \
+ transport-testing.c transport-testing.h
+libgnunettransporttesting_la_LIBADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+libgnunettransporttesting_la_DEPENDENCIES = \
+ libgnunettransport.la
+libgnunettransporttesting_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS)
+
+libgnunettransport_la_SOURCES = \
+ transport_api.c transport.h \
+ transport_api_blacklist.c \
+ transport_api_address_to_string.c \
+ transport_api_address_lookup.c
+libgnunettransport_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+libgnunettransport_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) $(WINFLAGS) \
+ -version-info 0:0:0
+
+bin_PROGRAMS = \
+ gnunet-transport \
+ $(WLAN_BIN) \
+ gnunet-service-transport \
+ gnunet-transport-certificate-creation
+
+#bin_SCRIPTS = \
+# gnunet-transport-certificate-creation
+
+gnunet_transport_certificate_creation_SOURCES = \
+ gnunet-transport-certificate-creation.c
+gnunet_transport_certificate_creation_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+gnunet_helper_transport_wlan_SOURCES = \
+ gnunet-helper-transport-wlan.c
+
+gnunet_helper_transport_wlan_dummy_SOURCES = \
+ gnunet-helper-transport-wlan-dummy.c
+gnunet_helper_transport_wlan_dummy_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+gnunet_transport_wlan_sender_SOURCES = \
+ gnunet-transport-wlan-sender.c
+gnunet_transport_wlan_sender_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+gnunet_transport_SOURCES = \
+ gnunet-transport.c
+gnunet_transport_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+gnunet_transport_DEPENDENCIES = \
+ libgnunettransport.la
+
+gnunet_service_transport_SOURCES = \
+ gnunet-service-transport.c gnunet-service-transport.h \
+ gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \
+ gnunet-service-transport_clients.h gnunet-service-transport_clients.c \
+ gnunet-service-transport_hello.h gnunet-service-transport_hello.c \
+ gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \
+ gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \
+ gnunet-service-transport_validation.h gnunet-service-transport_validation.c
+gnunet_service_transport_LDADD = \
+ $(top_builddir)/src/ats/libgnunetats.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_GLPK) \
+ $(GN_LIBINTL)
+
+plugin_LTLIBRARIES = \
+ libgnunet_plugin_transport_tcp.la \
+ libgnunet_plugin_transport_udp.la \
+ $(UNIX_PLUGIN_LA) \
+ $(HTTP_PLUGIN_LA) \
+ $(HTTPS_PLUGIN_LA) \
+ $(WLAN_PLUGIN_LA) \
+ libgnunet_plugin_transport_template.la
+
+libgnunet_plugin_transport_tcp_la_SOURCES = \
+ plugin_transport_tcp.c
+libgnunet_plugin_transport_tcp_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+libgnunet_plugin_transport_tcp_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_template_la_SOURCES = \
+ plugin_transport_template.c
+libgnunet_plugin_transport_template_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+libgnunet_plugin_transport_template_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_wlan_la_SOURCES = \
+ plugin_transport_wlan.c plugin_transport_wlan.h
+libgnunet_plugin_transport_wlan_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+libgnunet_plugin_transport_wlan_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_udp_la_SOURCES = \
+ plugin_transport_udp.c plugin_transport_udp.h \
+ plugin_transport_udp_broadcasting.c
+libgnunet_plugin_transport_udp_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+libgnunet_plugin_transport_udp_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_unix_la_SOURCES = \
+ plugin_transport_unix.c
+libgnunet_plugin_transport_unix_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+libgnunet_plugin_transport_unix_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_http_la_SOURCES = \
+ plugin_transport_http.c plugin_transport_http.h \
+ plugin_transport_http_client.c plugin_transport_http_server.c
+libgnunet_plugin_transport_http_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ @LIBCURL@ \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+libgnunet_plugin_transport_http_la_LDFLAGS = \
+ $(GN_LIBMHD) \
+ $(GN_PLUGIN_LDFLAGS)
+libgnunet_plugin_transport_http_la_CFLAGS = \
+ $(CFLAGS)
+libgnunet_plugin_transport_http_la_CPPFLAGS = \
+ @LIBCURL_CPPFLAGS@
+
+libgnunet_plugin_transport_https_la_SOURCES = \
+ plugin_transport_http.c plugin_transport_http.h \
+ plugin_transport_http_client.c plugin_transport_http_server.c
+libgnunet_plugin_transport_https_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ @LIBCURL@ \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+libgnunet_plugin_transport_https_la_LDFLAGS = \
+ $(GN_LIBMHD) \
+ $(GN_PLUGIN_LDFLAGS)
+libgnunet_plugin_transport_https_la_CFLAGS = \
+ $(CFLAGS) -DBUILD_HTTPS
+libgnunet_plugin_transport_https_la_CPPFLAGS = \
+ @LIBCURL_CPPFLAGS@
+
+
+check_PROGRAMS = \
+ test_transport_testing \
+ test_transport_startonly \
+ test_transport_api_blacklisting \
+ test_transport_api_disconnect_tcp \
+ test_transport_api_bidirectional_connect \
+ test_transport_api_tcp \
+ test_transport_api_restart_1peer \
+ test_transport_api_restart_2peers \
+ test_transport_api_timeout_tcp \
+ test_transport_api_limited_sockets_tcp \
+ test_transport_api_tcp_nat \
+ test_transport_api_udp \
+ test_transport_api_timeout_udp \
+ $(UNIX_PLUGIN_TEST) \
+ $(UNIX_PLUGIN_TIMEOUT_TEST) \
+ test_transport_api_udp_nat \
+ $(HTTP_API_TEST) \
+ $(HTTP_NAT_API_TEST) \
+ $(HTTP_API_TIMEOUT_TEST) \
+ $(HTTPS_API_TEST) \
+ $(HTTPS_NAT_API_TEST) \
+ $(HTTPS_API_TIMEOUT_TEST) \
+ test_transport_api_multi \
+ test_transport_api_reliability_tcp \
+ test_transport_api_reliability_tcp_nat \
+ test_transport_api_unreliability_udp \
+ test_transport_api_unreliability_constant_udp \
+ $(UNIX_REL_TEST) \
+ $(HTTP_REL_TEST) \
+ $(HTTP_NAT_REL_TEST) \
+ $(HTTPS_REL_TEST) \
+ $(HTTPS_NAT_REL_TEST) \
+ test_quota_compliance_tcp \
+ test_quota_compliance_tcp_asymmetric \
+ test_quota_compliance_udp \
+ $(UNIX_QUOTA_TEST) \
+ $(HTTP_QUOTA_TEST) \
+ $(HTTPS_QUOTA_TEST) \
+ $(WLAN_API_TEST) \
+ $(WLAN_REL_TEST) \
+ $(WLAN_UREL_TEST)
+
+if ENABLE_TEST_RUN
+TESTS = \
+ test_transport_testing \
+ test_transport_startonly \
+ test_transport_api_blacklisting \
+ test_transport_api_disconnect_tcp \
+ test_transport_api_bidirectional_connect \
+ test_transport_api_tcp \
+ test_transport_api_restart_1peer \
+ test_transport_api_restart_2peers \
+ test_transport_api_timeout_tcp \
+ test_transport_api_limited_sockets_tcp \
+ test_transport_api_tcp_nat \
+ test_transport_api_udp \
+ test_transport_api_timeout_udp \
+ $(UNIX_PLUGIN_TEST) \
+ $(UNIX_PLUGIN_TIMEOUT_TEST) \
+ test_transport_api_udp_nat \
+ $(HTTP_API_TEST) \
+ $(HTTP_NAT_API_TEST) \
+ $(HTTP_API_TIMEOUT_TEST) \
+ $(HTTPS_API_TEST) \
+ $(HTTPS_NAT_API_TEST) \
+ $(HTTPS_API_TIMEOUT_TEST) \
+ test_transport_api_multi \
+ test_transport_api_reliability_tcp \
+ test_transport_api_reliability_tcp_nat \
+ test_transport_api_unreliability_udp \
+ test_transport_api_unreliability_constant_udp \
+ $(UNIX_REL_TEST) \
+ $(HTTP_REL_TEST) \
+ $(HTTP_NAT_REL_TEST) \
+ $(HTTPS_REL_TEST) \
+ $(HTTPS_NAT_REL_TEST) \
+ test_quota_compliance_tcp \
+ test_quota_compliance_tcp_asymmetric \
+ test_quota_compliance_udp \
+ $(UNIX_QUOTA_TEST) \
+ $(HTTP_QUOTA_TEST) \
+ $(HTTPS_QUOTA_TEST) \
+ $(WLAN_API_TEST) \
+ $(WLAN_REL_TEST) \
+ $(WLAN_UREL_TEST)
+endif
+
+test_transport_testing_SOURCES = \
+ test_transport_testing.c
+test_transport_testing_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+#gnunet_transport_connect_running_peers_SOURCES = \
+# gnunet-transport-connect-running-peers.c
+#gnunet_transport_connect_running_peers_LDADD = \
+# $(top_builddir)/src/transport/libgnunettransport.la \
+# $(top_builddir)/src/hello/libgnunethello.la \
+# $(top_builddir)/src/util/libgnunetutil.la \
+# $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_blacklisting_SOURCES = \
+ test_transport_api_blacklisting.c
+test_transport_api_blacklisting_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_disconnect_tcp_SOURCES = \
+ test_transport_api_disconnect.c
+test_transport_api_disconnect_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_startonly_SOURCES = \
+ test_transport_startonly.c
+test_transport_startonly_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_tcp_SOURCES = \
+ test_transport_api.c
+test_transport_api_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_bidirectional_connect_SOURCES = \
+ test_transport_api_bidirectional_connect.c
+test_transport_api_bidirectional_connect_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_restart_1peer_SOURCES = \
+ test_transport_api_restart_1peer.c
+test_transport_api_restart_1peer_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_restart_2peers_SOURCES = \
+ test_transport_api_restart_2peers.c
+test_transport_api_restart_2peers_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_limited_sockets_tcp_SOURCES = \
+ test_transport_api_limited_sockets.c
+test_transport_api_limited_sockets_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_tcp_nat_SOURCES = \
+ test_transport_api.c
+test_transport_api_tcp_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_tcp_SOURCES = \
+ test_transport_api_reliability.c
+test_transport_api_reliability_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_timeout_tcp_SOURCES = \
+ test_transport_api_timeout.c
+test_transport_api_timeout_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_timeout_unix_SOURCES = \
+ test_transport_api_timeout.c
+test_transport_api_timeout_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_timeout_http_SOURCES = \
+ test_transport_api_timeout.c
+test_transport_api_timeout_http_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_timeout_https_SOURCES = \
+ test_transport_api_timeout.c
+test_transport_api_timeout_https_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_tcp_nat_SOURCES = \
+ test_transport_api_reliability.c
+test_transport_api_reliability_tcp_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_wlan_SOURCES = \
+ test_transport_api_reliability.c
+test_transport_api_reliability_wlan_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_unreliability_wlan_SOURCES = \
+ test_transport_api_unreliability.c
+test_transport_api_unreliability_wlan_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_udp_SOURCES = \
+ test_transport_api.c
+test_transport_api_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_timeout_udp_SOURCES = \
+ test_transport_api_timeout.c
+test_transport_api_timeout_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_udp_nat_SOURCES = \
+ test_transport_api.c
+test_transport_api_udp_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_unix_SOURCES = \
+ test_transport_api.c
+test_transport_api_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_http_SOURCES = \
+ test_transport_api.c
+test_transport_api_http_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+ test_transport_api_http_nat_SOURCES = \
+ test_transport_api.c
+test_transport_api_http_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_http_SOURCES = \
+ test_transport_api_reliability.c
+test_transport_api_reliability_http_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_http_nat_SOURCES = \
+ test_transport_api_reliability.c
+test_transport_api_reliability_http_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_https_SOURCES = \
+ test_transport_api.c
+test_transport_api_https_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_https_nat_SOURCES = \
+ test_transport_api.c
+test_transport_api_https_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_https_SOURCES = \
+ test_transport_api_reliability.c
+test_transport_api_reliability_https_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_https_nat_SOURCES = \
+ test_transport_api_reliability.c
+test_transport_api_reliability_https_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_unreliability_unix_SOURCES = \
+ test_transport_api_unreliability.c
+test_transport_api_unreliability_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_unreliability_udp_SOURCES = \
+ test_transport_api_unreliability.c
+test_transport_api_unreliability_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_unreliability_constant_udp_SOURCES = \
+ test_transport_api_unreliability_constant.c
+test_transport_api_unreliability_constant_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+if LINUX
+test_transport_api_wlan_SOURCES = \
+ test_transport_api.c
+test_transport_api_wlan_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+endif
+
+test_quota_compliance_tcp_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_quota_compliance_tcp_asymmetric_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_tcp_asymmetric_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+#test_quota_compliance_tcp_asymmetric_send_constant_SOURCES = \
+# test_quota_compliance.c
+#test_quota_compliance_tcp_asymmetric_send_constant_LDADD = \
+# $(top_builddir)/src/transport/libgnunettransport.la \
+# $(top_builddir)/src/util/libgnunetutil.la
+
+test_quota_compliance_http_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_http_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+ test_quota_compliance_http_asymmetric_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_http_asymmetric_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+#test_quota_compliance_http_asymmetric_send_constant_SOURCES = \
+# test_quota_compliance.c
+#test_quota_compliance_http_asymmetric_send_constant_LDADD = \
+# $(top_builddir)/src/transport/libgnunettransport.la \
+# $(top_builddir)/src/util/libgnunetutil.la
+
+test_quota_compliance_https_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_https_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+ test_quota_compliance_https_asymmetric_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_https_asymmetric_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+#test_quota_compliance_https_asymmetric_send_constant_SOURCES = \
+# test_quota_compliance.c
+#test_quota_compliance_https_asymmetric_send_constant_LDADD = \
+# $(top_builddir)/src/transport/libgnunettransport.la \
+# $(top_builddir)/src/util/libgnunetutil.la
+
+test_quota_compliance_udp_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_quota_compliance_unix_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_quota_compliance_unix_asymmetric_SOURCES = \
+ test_quota_compliance.c
+test_quota_compliance_unix_asymmetric_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_multi_SOURCES = \
+ test_transport_api.c
+test_transport_api_multi_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+
+EXTRA_DIST = \
+gnunet-transport-certificate-creation \
+template_cfg_peer1.conf\
+template_cfg_peer2.conf\
+test_plugin_transport_data.conf\
+test_plugin_transport_data_udp.conf\
+test_quota_compliance_data.conf\
+test_quota_compliance_http_peer1.conf\
+test_quota_compliance_http_peer2.conf\
+test_quota_compliance_https_peer1.conf\
+test_quota_compliance_https_peer2.conf\
+test_quota_compliance_tcp_peer1.conf\
+test_quota_compliance_tcp_peer2.conf\
+test_quota_compliance_udp_peer1.conf\
+test_quota_compliance_udp_peer2.conf\
+test_quota_compliance_unix_peer1.conf\
+test_quota_compliance_unix_peer2.conf\
+test_quota_compliance_http_asymmetric_peer1.conf\
+test_quota_compliance_http_asymmetric_peer2.conf\
+test_quota_compliance_https_asymmetric_peer1.conf\
+test_quota_compliance_https_asymmetric_peer2.conf\
+test_quota_compliance_tcp_asymmetric_peer1.conf\
+test_quota_compliance_tcp_asymmetric_peer2.conf\
+test_quota_compliance_unix_asymmetric_peer1.conf\
+test_quota_compliance_unix_asymmetric_peer2.conf\
+test_transport_api_data.conf\
+test_transport_api_http_peer1.conf\
+test_transport_api_http_peer2.conf\
+test_transport_api_https_peer1.conf\
+test_transport_api_https_peer2.conf\
+test_transport_api_limited_sockets_tcp_peer1.conf\
+test_transport_api_limited_sockets_tcp_peer2.conf\
+test_transport_api_timeout_tcp_peer1.conf\
+test_transport_api_timeout_tcp_peer2.conf\
+test_transport_api_multi_peer1.conf\
+test_transport_api_multi_peer2.conf\
+test_transport_api_reliability_http_peer1.conf\
+test_transport_api_reliability_http_peer2.conf\
+test_transport_api_reliability_https_peer1.conf\
+test_transport_api_reliability_https_peer2.conf\
+test_transport_api_reliability_tcp_nat_peer1.conf\
+test_transport_api_reliability_tcp_nat_peer2.conf\
+test_transport_api_reliability_tcp_peer1.conf\
+test_transport_api_reliability_tcp_peer2.conf\
+test_transport_api_reliability_wlan_peer1.conf\
+test_transport_api_reliability_wlan_peer2.conf\
+test_transport_api_bidirectional_connect_peer1.conf\
+test_transport_api_bidirectional_connect_peer2.conf\
+test_transport_api_tcp_nat_peer1.conf\
+test_transport_api_tcp_nat_peer2.conf\
+test_transport_api_tcp_peer1.conf\
+test_transport_api_tcp_peer2.conf\
+test_transport_api_udp_nat_peer1.conf\
+test_transport_api_udp_nat_peer2.conf\
+test_transport_api_udp_peer1.conf\
+test_transport_api_udp_peer2.conf\
+test_transport_api_timeout_udp_peer1.conf\
+test_transport_api_timeout_udp_peer2.conf\
+test_transport_api_unix_peer1.conf\
+test_transport_api_unix_peer2.conf\
+test_transport_api_timeout_unix_peer1.conf\
+test_transport_api_timeout_unix_peer2.conf\
+test_transport_api_unreliability_udp_peer1.conf\
+test_transport_api_unreliability_udp_peer2.conf\
+test_transport_api_unreliability_unix_peer1.conf\
+test_transport_api_unreliability_unix_peer2.conf\
+test_transport_api_unreliability_wlan_peer1.conf\
+test_transport_api_unreliability_wlan_peer2.conf\
+test_transport_api_wlan_peer1.conf\
+test_transport_api_wlan_peer2.conf\
+test_transport_defaults.conf\
+test_transport_startonly.conf\
+test_transport_api_disconnect_tcp_peer1.conf\
+test_transport_api_disconnect_tcp_peer2.conf\
+test_transport_api_http_nat_peer1.conf\
+test_transport_api_http_nat_peer2.conf\
+test_transport_api_https_nat_peer1.conf\
+test_transport_api_https_nat_peer2.conf\
+test_transport_api_reliability_http_nat_peer1.conf\
+test_transport_api_reliability_http_nat_peer2.conf\
+test_transport_api_reliability_https_nat_peer1.conf\
+test_transport_api_reliability_https_nat_peer2.conf\
+test_transport_api_timeout_http_peer1.conf\
+test_transport_api_timeout_http_peer2.conf\
+test_transport_api_timeout_https_peer1.conf\
+test_transport_api_timeout_https_peer2.conf\
+test_transport_api_unreliability_constant_udp_peer1.conf\
+test_transport_api_unreliability_constant_udp_peer2.conf
diff --git a/src/transport/Makefile.in b/src/transport/Makefile.in
new file mode 100644
index 0000000..36df686
--- /dev/null
+++ b/src/transport/Makefile.in
@@ -0,0 +1,2648 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+target_triplet = @target@
+noinst_PROGRAMS = $(am__EXEEXT_21) $(am__EXEEXT_22)
+bin_PROGRAMS = gnunet-transport$(EXEEXT) $(am__EXEEXT_1) \
+ gnunet-service-transport$(EXEEXT) \
+ gnunet-transport-certificate-creation$(EXEEXT)
+check_PROGRAMS = test_transport_testing$(EXEEXT) \
+ test_transport_startonly$(EXEEXT) \
+ test_transport_api_blacklisting$(EXEEXT) \
+ test_transport_api_disconnect_tcp$(EXEEXT) \
+ test_transport_api_bidirectional_connect$(EXEEXT) \
+ test_transport_api_tcp$(EXEEXT) \
+ test_transport_api_restart_1peer$(EXEEXT) \
+ test_transport_api_restart_2peers$(EXEEXT) \
+ test_transport_api_timeout_tcp$(EXEEXT) \
+ test_transport_api_limited_sockets_tcp$(EXEEXT) \
+ test_transport_api_tcp_nat$(EXEEXT) \
+ test_transport_api_udp$(EXEEXT) \
+ test_transport_api_timeout_udp$(EXEEXT) $(am__EXEEXT_2) \
+ $(am__EXEEXT_3) test_transport_api_udp_nat$(EXEEXT) \
+ $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
+ $(am__EXEEXT_7) $(am__EXEEXT_8) $(am__EXEEXT_9) \
+ test_transport_api_multi$(EXEEXT) \
+ test_transport_api_reliability_tcp$(EXEEXT) \
+ test_transport_api_reliability_tcp_nat$(EXEEXT) \
+ test_transport_api_unreliability_udp$(EXEEXT) \
+ test_transport_api_unreliability_constant_udp$(EXEEXT) \
+ $(am__EXEEXT_10) $(am__EXEEXT_11) $(am__EXEEXT_12) \
+ $(am__EXEEXT_13) $(am__EXEEXT_14) \
+ test_quota_compliance_tcp$(EXEEXT) \
+ test_quota_compliance_tcp_asymmetric$(EXEEXT) \
+ test_quota_compliance_udp$(EXEEXT) $(am__EXEEXT_15) \
+ $(am__EXEEXT_16) $(am__EXEEXT_17) $(am__EXEEXT_18) \
+ $(am__EXEEXT_19) $(am__EXEEXT_20)
+@ENABLE_TEST_RUN_TRUE@TESTS = test_transport_testing$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_startonly$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_blacklisting$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_disconnect_tcp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_bidirectional_connect$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_tcp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_restart_1peer$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_restart_2peers$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_timeout_tcp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_limited_sockets_tcp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_tcp_nat$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_udp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_timeout_udp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_2) $(am__EXEEXT_3) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_udp_nat$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_4) $(am__EXEEXT_5) \
+@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_6) $(am__EXEEXT_7) \
+@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_8) $(am__EXEEXT_9) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_multi$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_reliability_tcp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_reliability_tcp_nat$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_unreliability_udp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_transport_api_unreliability_constant_udp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_10) $(am__EXEEXT_11) \
+@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_12) $(am__EXEEXT_13) \
+@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_14) \
+@ENABLE_TEST_RUN_TRUE@ test_quota_compliance_tcp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_quota_compliance_tcp_asymmetric$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ test_quota_compliance_udp$(EXEEXT) \
+@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_15) $(am__EXEEXT_16) \
+@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_17) $(am__EXEEXT_18) \
+@ENABLE_TEST_RUN_TRUE@ $(am__EXEEXT_19) $(am__EXEEXT_20)
+subdir = src/transport
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/transport.conf.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/m4/absolute-header.m4 \
+ $(top_srcdir)/m4/align.m4 $(top_srcdir)/m4/argz.m4 \
+ $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \
+ $(top_srcdir)/m4/lib-ld.m4 $(top_srcdir)/m4/lib-link.m4 \
+ $(top_srcdir)/m4/lib-prefix.m4 $(top_srcdir)/m4/libcurl.m4 \
+ $(top_srcdir)/m4/libgcrypt.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/libunistring.m4 $(top_srcdir)/m4/ltdl.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/nls.m4 $(top_srcdir)/m4/po.m4 \
+ $(top_srcdir)/m4/progtest.m4 $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/gnunet_config.h
+CONFIG_CLEAN_FILES = transport.conf
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \
+ "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(plugin_LTLIBRARIES)
+libgnunet_plugin_transport_http_la_DEPENDENCIES = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_libgnunet_plugin_transport_http_la_OBJECTS = \
+ libgnunet_plugin_transport_http_la-plugin_transport_http.lo \
+ libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo \
+ libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo
+libgnunet_plugin_transport_http_la_OBJECTS = \
+ $(am_libgnunet_plugin_transport_http_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libgnunet_plugin_transport_http_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) \
+ $(libgnunet_plugin_transport_http_la_LDFLAGS) $(LDFLAGS) -o $@
+@HAVE_MHD_TRUE@am_libgnunet_plugin_transport_http_la_rpath = -rpath \
+@HAVE_MHD_TRUE@ $(plugindir)
+libgnunet_plugin_transport_https_la_DEPENDENCIES = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_libgnunet_plugin_transport_https_la_OBJECTS = \
+ libgnunet_plugin_transport_https_la-plugin_transport_http.lo \
+ libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo \
+ libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo
+libgnunet_plugin_transport_https_la_OBJECTS = \
+ $(am_libgnunet_plugin_transport_https_la_OBJECTS)
+libgnunet_plugin_transport_https_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(libgnunet_plugin_transport_https_la_CFLAGS) \
+ $(CFLAGS) $(libgnunet_plugin_transport_https_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@HAVE_MHD_TRUE@am_libgnunet_plugin_transport_https_la_rpath = -rpath \
+@HAVE_MHD_TRUE@ $(plugindir)
+libgnunet_plugin_transport_tcp_la_DEPENDENCIES = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_libgnunet_plugin_transport_tcp_la_OBJECTS = \
+ plugin_transport_tcp.lo
+libgnunet_plugin_transport_tcp_la_OBJECTS = \
+ $(am_libgnunet_plugin_transport_tcp_la_OBJECTS)
+libgnunet_plugin_transport_tcp_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libgnunet_plugin_transport_tcp_la_LDFLAGS) $(LDFLAGS) -o $@
+libgnunet_plugin_transport_template_la_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_libgnunet_plugin_transport_template_la_OBJECTS = \
+ plugin_transport_template.lo
+libgnunet_plugin_transport_template_la_OBJECTS = \
+ $(am_libgnunet_plugin_transport_template_la_OBJECTS)
+libgnunet_plugin_transport_template_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libgnunet_plugin_transport_template_la_LDFLAGS) $(LDFLAGS) \
+ -o $@
+libgnunet_plugin_transport_udp_la_DEPENDENCIES = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_libgnunet_plugin_transport_udp_la_OBJECTS = \
+ plugin_transport_udp.lo plugin_transport_udp_broadcasting.lo
+libgnunet_plugin_transport_udp_la_OBJECTS = \
+ $(am_libgnunet_plugin_transport_udp_la_OBJECTS)
+libgnunet_plugin_transport_udp_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libgnunet_plugin_transport_udp_la_LDFLAGS) $(LDFLAGS) -o $@
+libgnunet_plugin_transport_unix_la_DEPENDENCIES = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_libgnunet_plugin_transport_unix_la_OBJECTS = \
+ plugin_transport_unix.lo
+libgnunet_plugin_transport_unix_la_OBJECTS = \
+ $(am_libgnunet_plugin_transport_unix_la_OBJECTS)
+libgnunet_plugin_transport_unix_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libgnunet_plugin_transport_unix_la_LDFLAGS) $(LDFLAGS) -o $@
+@MINGW_FALSE@am_libgnunet_plugin_transport_unix_la_rpath = -rpath \
+@MINGW_FALSE@ $(plugindir)
+libgnunet_plugin_transport_wlan_la_DEPENDENCIES = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_libgnunet_plugin_transport_wlan_la_OBJECTS = \
+ plugin_transport_wlan.lo
+libgnunet_plugin_transport_wlan_la_OBJECTS = \
+ $(am_libgnunet_plugin_transport_wlan_la_OBJECTS)
+libgnunet_plugin_transport_wlan_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libgnunet_plugin_transport_wlan_la_LDFLAGS) $(LDFLAGS) -o $@
+@LINUX_TRUE@am_libgnunet_plugin_transport_wlan_la_rpath = -rpath \
+@LINUX_TRUE@ $(plugindir)
+am__DEPENDENCIES_1 =
+libgnunettransport_la_DEPENDENCIES = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(am__DEPENDENCIES_1)
+am_libgnunettransport_la_OBJECTS = transport_api.lo \
+ transport_api_blacklist.lo transport_api_address_to_string.lo \
+ transport_api_address_lookup.lo
+libgnunettransport_la_OBJECTS = $(am_libgnunettransport_la_OBJECTS)
+libgnunettransport_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libgnunettransport_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am_libgnunettransporttesting_la_OBJECTS = transport-testing.lo
+libgnunettransporttesting_la_OBJECTS = \
+ $(am_libgnunettransporttesting_la_OBJECTS)
+libgnunettransporttesting_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+ $(AM_CFLAGS) $(CFLAGS) $(libgnunettransporttesting_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@LINUX_TRUE@am__EXEEXT_1 = gnunet-helper-transport-wlan$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_2 = test_transport_api_unix$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_3 = test_transport_api_timeout_unix$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_4 = test_transport_api_http$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_5 = test_transport_api_http_nat$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_6 = \
+@HAVE_MHD_TRUE@ test_transport_api_timeout_http$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_7 = test_transport_api_https$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_8 = test_transport_api_https_nat$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_9 = \
+@HAVE_MHD_TRUE@ test_transport_api_timeout_https$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_10 = \
+@MINGW_FALSE@ test_transport_api_unreliability_unix$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_11 = \
+@HAVE_MHD_TRUE@ test_transport_api_reliability_http$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_12 = test_transport_api_reliability_http_nat$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_13 = \
+@HAVE_MHD_TRUE@ test_transport_api_reliability_https$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_14 = test_transport_api_reliability_https_nat$(EXEEXT)
+@MINGW_FALSE@am__EXEEXT_15 = test_quota_compliance_unix$(EXEEXT) \
+@MINGW_FALSE@ test_quota_compliance_unix_asymmetric$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_16 = test_quota_compliance_http$(EXEEXT) \
+@HAVE_MHD_TRUE@ test_quota_compliance_http_asymmetric$(EXEEXT)
+@HAVE_MHD_TRUE@am__EXEEXT_17 = test_quota_compliance_https$(EXEEXT) \
+@HAVE_MHD_TRUE@ test_quota_compliance_https_asymmetric$(EXEEXT)
+@LINUX_TRUE@am__EXEEXT_18 = test_transport_api_wlan$(EXEEXT)
+@LINUX_TRUE@am__EXEEXT_19 = \
+@LINUX_TRUE@ test_transport_api_reliability_wlan$(EXEEXT)
+@LINUX_TRUE@am__EXEEXT_20 = \
+@LINUX_TRUE@ test_transport_api_unreliability_wlan$(EXEEXT)
+@LINUX_TRUE@am__EXEEXT_21 = \
+@LINUX_TRUE@ gnunet-helper-transport-wlan-dummy$(EXEEXT)
+@LINUX_TRUE@am__EXEEXT_22 = gnunet-transport-wlan-sender$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS) $(noinst_PROGRAMS)
+am_gnunet_helper_transport_wlan_OBJECTS = \
+ gnunet-helper-transport-wlan.$(OBJEXT)
+gnunet_helper_transport_wlan_OBJECTS = \
+ $(am_gnunet_helper_transport_wlan_OBJECTS)
+gnunet_helper_transport_wlan_LDADD = $(LDADD)
+am_gnunet_helper_transport_wlan_dummy_OBJECTS = \
+ gnunet-helper-transport-wlan-dummy.$(OBJEXT)
+gnunet_helper_transport_wlan_dummy_OBJECTS = \
+ $(am_gnunet_helper_transport_wlan_dummy_OBJECTS)
+gnunet_helper_transport_wlan_dummy_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_gnunet_service_transport_OBJECTS = \
+ gnunet-service-transport.$(OBJEXT) \
+ gnunet-service-transport_blacklist.$(OBJEXT) \
+ gnunet-service-transport_clients.$(OBJEXT) \
+ gnunet-service-transport_hello.$(OBJEXT) \
+ gnunet-service-transport_neighbours.$(OBJEXT) \
+ gnunet-service-transport_plugins.$(OBJEXT) \
+ gnunet-service-transport_validation.$(OBJEXT)
+gnunet_service_transport_OBJECTS = \
+ $(am_gnunet_service_transport_OBJECTS)
+gnunet_service_transport_DEPENDENCIES = \
+ $(top_builddir)/src/ats/libgnunetats.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(am__DEPENDENCIES_1)
+am_gnunet_transport_OBJECTS = gnunet-transport.$(OBJEXT)
+gnunet_transport_OBJECTS = $(am_gnunet_transport_OBJECTS)
+am_gnunet_transport_certificate_creation_OBJECTS = \
+ gnunet-transport-certificate-creation.$(OBJEXT)
+gnunet_transport_certificate_creation_OBJECTS = \
+ $(am_gnunet_transport_certificate_creation_OBJECTS)
+gnunet_transport_certificate_creation_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_gnunet_transport_wlan_sender_OBJECTS = \
+ gnunet-transport-wlan-sender.$(OBJEXT)
+gnunet_transport_wlan_sender_OBJECTS = \
+ $(am_gnunet_transport_wlan_sender_OBJECTS)
+gnunet_transport_wlan_sender_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la
+am_test_quota_compliance_http_OBJECTS = \
+ test_quota_compliance.$(OBJEXT)
+test_quota_compliance_http_OBJECTS = \
+ $(am_test_quota_compliance_http_OBJECTS)
+test_quota_compliance_http_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_quota_compliance_http_asymmetric_OBJECTS = \
+ test_quota_compliance.$(OBJEXT)
+test_quota_compliance_http_asymmetric_OBJECTS = \
+ $(am_test_quota_compliance_http_asymmetric_OBJECTS)
+test_quota_compliance_http_asymmetric_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_quota_compliance_https_OBJECTS = \
+ test_quota_compliance.$(OBJEXT)
+test_quota_compliance_https_OBJECTS = \
+ $(am_test_quota_compliance_https_OBJECTS)
+test_quota_compliance_https_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_quota_compliance_https_asymmetric_OBJECTS = \
+ test_quota_compliance.$(OBJEXT)
+test_quota_compliance_https_asymmetric_OBJECTS = \
+ $(am_test_quota_compliance_https_asymmetric_OBJECTS)
+test_quota_compliance_https_asymmetric_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_quota_compliance_tcp_OBJECTS = \
+ test_quota_compliance.$(OBJEXT)
+test_quota_compliance_tcp_OBJECTS = \
+ $(am_test_quota_compliance_tcp_OBJECTS)
+test_quota_compliance_tcp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_quota_compliance_tcp_asymmetric_OBJECTS = \
+ test_quota_compliance.$(OBJEXT)
+test_quota_compliance_tcp_asymmetric_OBJECTS = \
+ $(am_test_quota_compliance_tcp_asymmetric_OBJECTS)
+test_quota_compliance_tcp_asymmetric_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_quota_compliance_udp_OBJECTS = \
+ test_quota_compliance.$(OBJEXT)
+test_quota_compliance_udp_OBJECTS = \
+ $(am_test_quota_compliance_udp_OBJECTS)
+test_quota_compliance_udp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_quota_compliance_unix_OBJECTS = \
+ test_quota_compliance.$(OBJEXT)
+test_quota_compliance_unix_OBJECTS = \
+ $(am_test_quota_compliance_unix_OBJECTS)
+test_quota_compliance_unix_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_quota_compliance_unix_asymmetric_OBJECTS = \
+ test_quota_compliance.$(OBJEXT)
+test_quota_compliance_unix_asymmetric_OBJECTS = \
+ $(am_test_quota_compliance_unix_asymmetric_OBJECTS)
+test_quota_compliance_unix_asymmetric_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_bidirectional_connect_OBJECTS = \
+ test_transport_api_bidirectional_connect.$(OBJEXT)
+test_transport_api_bidirectional_connect_OBJECTS = \
+ $(am_test_transport_api_bidirectional_connect_OBJECTS)
+test_transport_api_bidirectional_connect_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_blacklisting_OBJECTS = \
+ test_transport_api_blacklisting.$(OBJEXT)
+test_transport_api_blacklisting_OBJECTS = \
+ $(am_test_transport_api_blacklisting_OBJECTS)
+test_transport_api_blacklisting_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_disconnect_tcp_OBJECTS = \
+ test_transport_api_disconnect.$(OBJEXT)
+test_transport_api_disconnect_tcp_OBJECTS = \
+ $(am_test_transport_api_disconnect_tcp_OBJECTS)
+test_transport_api_disconnect_tcp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_http_OBJECTS = test_transport_api.$(OBJEXT)
+test_transport_api_http_OBJECTS = \
+ $(am_test_transport_api_http_OBJECTS)
+test_transport_api_http_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_http_nat_OBJECTS = test_transport_api.$(OBJEXT)
+test_transport_api_http_nat_OBJECTS = \
+ $(am_test_transport_api_http_nat_OBJECTS)
+test_transport_api_http_nat_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_https_OBJECTS = test_transport_api.$(OBJEXT)
+test_transport_api_https_OBJECTS = \
+ $(am_test_transport_api_https_OBJECTS)
+test_transport_api_https_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_https_nat_OBJECTS = \
+ test_transport_api.$(OBJEXT)
+test_transport_api_https_nat_OBJECTS = \
+ $(am_test_transport_api_https_nat_OBJECTS)
+test_transport_api_https_nat_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_limited_sockets_tcp_OBJECTS = \
+ test_transport_api_limited_sockets.$(OBJEXT)
+test_transport_api_limited_sockets_tcp_OBJECTS = \
+ $(am_test_transport_api_limited_sockets_tcp_OBJECTS)
+test_transport_api_limited_sockets_tcp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_multi_OBJECTS = test_transport_api.$(OBJEXT)
+test_transport_api_multi_OBJECTS = \
+ $(am_test_transport_api_multi_OBJECTS)
+test_transport_api_multi_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_reliability_http_OBJECTS = \
+ test_transport_api_reliability.$(OBJEXT)
+test_transport_api_reliability_http_OBJECTS = \
+ $(am_test_transport_api_reliability_http_OBJECTS)
+test_transport_api_reliability_http_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_reliability_http_nat_OBJECTS = \
+ test_transport_api_reliability.$(OBJEXT)
+test_transport_api_reliability_http_nat_OBJECTS = \
+ $(am_test_transport_api_reliability_http_nat_OBJECTS)
+test_transport_api_reliability_http_nat_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_reliability_https_OBJECTS = \
+ test_transport_api_reliability.$(OBJEXT)
+test_transport_api_reliability_https_OBJECTS = \
+ $(am_test_transport_api_reliability_https_OBJECTS)
+test_transport_api_reliability_https_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_reliability_https_nat_OBJECTS = \
+ test_transport_api_reliability.$(OBJEXT)
+test_transport_api_reliability_https_nat_OBJECTS = \
+ $(am_test_transport_api_reliability_https_nat_OBJECTS)
+test_transport_api_reliability_https_nat_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_reliability_tcp_OBJECTS = \
+ test_transport_api_reliability.$(OBJEXT)
+test_transport_api_reliability_tcp_OBJECTS = \
+ $(am_test_transport_api_reliability_tcp_OBJECTS)
+test_transport_api_reliability_tcp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_reliability_tcp_nat_OBJECTS = \
+ test_transport_api_reliability.$(OBJEXT)
+test_transport_api_reliability_tcp_nat_OBJECTS = \
+ $(am_test_transport_api_reliability_tcp_nat_OBJECTS)
+test_transport_api_reliability_tcp_nat_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_reliability_wlan_OBJECTS = \
+ test_transport_api_reliability.$(OBJEXT)
+test_transport_api_reliability_wlan_OBJECTS = \
+ $(am_test_transport_api_reliability_wlan_OBJECTS)
+test_transport_api_reliability_wlan_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_restart_1peer_OBJECTS = \
+ test_transport_api_restart_1peer.$(OBJEXT)
+test_transport_api_restart_1peer_OBJECTS = \
+ $(am_test_transport_api_restart_1peer_OBJECTS)
+test_transport_api_restart_1peer_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_restart_2peers_OBJECTS = \
+ test_transport_api_restart_2peers.$(OBJEXT)
+test_transport_api_restart_2peers_OBJECTS = \
+ $(am_test_transport_api_restart_2peers_OBJECTS)
+test_transport_api_restart_2peers_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_tcp_OBJECTS = test_transport_api.$(OBJEXT)
+test_transport_api_tcp_OBJECTS = $(am_test_transport_api_tcp_OBJECTS)
+test_transport_api_tcp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_tcp_nat_OBJECTS = test_transport_api.$(OBJEXT)
+test_transport_api_tcp_nat_OBJECTS = \
+ $(am_test_transport_api_tcp_nat_OBJECTS)
+test_transport_api_tcp_nat_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_timeout_http_OBJECTS = \
+ test_transport_api_timeout.$(OBJEXT)
+test_transport_api_timeout_http_OBJECTS = \
+ $(am_test_transport_api_timeout_http_OBJECTS)
+test_transport_api_timeout_http_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_timeout_https_OBJECTS = \
+ test_transport_api_timeout.$(OBJEXT)
+test_transport_api_timeout_https_OBJECTS = \
+ $(am_test_transport_api_timeout_https_OBJECTS)
+test_transport_api_timeout_https_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_timeout_tcp_OBJECTS = \
+ test_transport_api_timeout.$(OBJEXT)
+test_transport_api_timeout_tcp_OBJECTS = \
+ $(am_test_transport_api_timeout_tcp_OBJECTS)
+test_transport_api_timeout_tcp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_timeout_udp_OBJECTS = \
+ test_transport_api_timeout.$(OBJEXT)
+test_transport_api_timeout_udp_OBJECTS = \
+ $(am_test_transport_api_timeout_udp_OBJECTS)
+test_transport_api_timeout_udp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_timeout_unix_OBJECTS = \
+ test_transport_api_timeout.$(OBJEXT)
+test_transport_api_timeout_unix_OBJECTS = \
+ $(am_test_transport_api_timeout_unix_OBJECTS)
+test_transport_api_timeout_unix_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_udp_OBJECTS = test_transport_api.$(OBJEXT)
+test_transport_api_udp_OBJECTS = $(am_test_transport_api_udp_OBJECTS)
+test_transport_api_udp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_udp_nat_OBJECTS = test_transport_api.$(OBJEXT)
+test_transport_api_udp_nat_OBJECTS = \
+ $(am_test_transport_api_udp_nat_OBJECTS)
+test_transport_api_udp_nat_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_unix_OBJECTS = test_transport_api.$(OBJEXT)
+test_transport_api_unix_OBJECTS = \
+ $(am_test_transport_api_unix_OBJECTS)
+test_transport_api_unix_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_unreliability_constant_udp_OBJECTS = \
+ test_transport_api_unreliability_constant.$(OBJEXT)
+test_transport_api_unreliability_constant_udp_OBJECTS = \
+ $(am_test_transport_api_unreliability_constant_udp_OBJECTS)
+test_transport_api_unreliability_constant_udp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_unreliability_udp_OBJECTS = \
+ test_transport_api_unreliability.$(OBJEXT)
+test_transport_api_unreliability_udp_OBJECTS = \
+ $(am_test_transport_api_unreliability_udp_OBJECTS)
+test_transport_api_unreliability_udp_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_unreliability_unix_OBJECTS = \
+ test_transport_api_unreliability.$(OBJEXT)
+test_transport_api_unreliability_unix_OBJECTS = \
+ $(am_test_transport_api_unreliability_unix_OBJECTS)
+test_transport_api_unreliability_unix_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_api_unreliability_wlan_OBJECTS = \
+ test_transport_api_unreliability.$(OBJEXT)
+test_transport_api_unreliability_wlan_OBJECTS = \
+ $(am_test_transport_api_unreliability_wlan_OBJECTS)
+test_transport_api_unreliability_wlan_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am__test_transport_api_wlan_SOURCES_DIST = test_transport_api.c
+@LINUX_TRUE@am_test_transport_api_wlan_OBJECTS = \
+@LINUX_TRUE@ test_transport_api.$(OBJEXT)
+test_transport_api_wlan_OBJECTS = \
+ $(am_test_transport_api_wlan_OBJECTS)
+@LINUX_TRUE@test_transport_api_wlan_DEPENDENCIES = $(top_builddir)/src/transport/libgnunettransport.la \
+@LINUX_TRUE@ $(top_builddir)/src/hello/libgnunethello.la \
+@LINUX_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \
+@LINUX_TRUE@ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_startonly_OBJECTS = \
+ test_transport_startonly.$(OBJEXT)
+test_transport_startonly_OBJECTS = \
+ $(am_test_transport_startonly_OBJECTS)
+test_transport_startonly_DEPENDENCIES = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+am_test_transport_testing_OBJECTS = test_transport_testing.$(OBJEXT)
+test_transport_testing_OBJECTS = $(am_test_transport_testing_OBJECTS)
+test_transport_testing_DEPENDENCIES = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libgnunet_plugin_transport_http_la_SOURCES) \
+ $(libgnunet_plugin_transport_https_la_SOURCES) \
+ $(libgnunet_plugin_transport_tcp_la_SOURCES) \
+ $(libgnunet_plugin_transport_template_la_SOURCES) \
+ $(libgnunet_plugin_transport_udp_la_SOURCES) \
+ $(libgnunet_plugin_transport_unix_la_SOURCES) \
+ $(libgnunet_plugin_transport_wlan_la_SOURCES) \
+ $(libgnunettransport_la_SOURCES) \
+ $(libgnunettransporttesting_la_SOURCES) \
+ $(gnunet_helper_transport_wlan_SOURCES) \
+ $(gnunet_helper_transport_wlan_dummy_SOURCES) \
+ $(gnunet_service_transport_SOURCES) \
+ $(gnunet_transport_SOURCES) \
+ $(gnunet_transport_certificate_creation_SOURCES) \
+ $(gnunet_transport_wlan_sender_SOURCES) \
+ $(test_quota_compliance_http_SOURCES) \
+ $(test_quota_compliance_http_asymmetric_SOURCES) \
+ $(test_quota_compliance_https_SOURCES) \
+ $(test_quota_compliance_https_asymmetric_SOURCES) \
+ $(test_quota_compliance_tcp_SOURCES) \
+ $(test_quota_compliance_tcp_asymmetric_SOURCES) \
+ $(test_quota_compliance_udp_SOURCES) \
+ $(test_quota_compliance_unix_SOURCES) \
+ $(test_quota_compliance_unix_asymmetric_SOURCES) \
+ $(test_transport_api_bidirectional_connect_SOURCES) \
+ $(test_transport_api_blacklisting_SOURCES) \
+ $(test_transport_api_disconnect_tcp_SOURCES) \
+ $(test_transport_api_http_SOURCES) \
+ $(test_transport_api_http_nat_SOURCES) \
+ $(test_transport_api_https_SOURCES) \
+ $(test_transport_api_https_nat_SOURCES) \
+ $(test_transport_api_limited_sockets_tcp_SOURCES) \
+ $(test_transport_api_multi_SOURCES) \
+ $(test_transport_api_reliability_http_SOURCES) \
+ $(test_transport_api_reliability_http_nat_SOURCES) \
+ $(test_transport_api_reliability_https_SOURCES) \
+ $(test_transport_api_reliability_https_nat_SOURCES) \
+ $(test_transport_api_reliability_tcp_SOURCES) \
+ $(test_transport_api_reliability_tcp_nat_SOURCES) \
+ $(test_transport_api_reliability_wlan_SOURCES) \
+ $(test_transport_api_restart_1peer_SOURCES) \
+ $(test_transport_api_restart_2peers_SOURCES) \
+ $(test_transport_api_tcp_SOURCES) \
+ $(test_transport_api_tcp_nat_SOURCES) \
+ $(test_transport_api_timeout_http_SOURCES) \
+ $(test_transport_api_timeout_https_SOURCES) \
+ $(test_transport_api_timeout_tcp_SOURCES) \
+ $(test_transport_api_timeout_udp_SOURCES) \
+ $(test_transport_api_timeout_unix_SOURCES) \
+ $(test_transport_api_udp_SOURCES) \
+ $(test_transport_api_udp_nat_SOURCES) \
+ $(test_transport_api_unix_SOURCES) \
+ $(test_transport_api_unreliability_constant_udp_SOURCES) \
+ $(test_transport_api_unreliability_udp_SOURCES) \
+ $(test_transport_api_unreliability_unix_SOURCES) \
+ $(test_transport_api_unreliability_wlan_SOURCES) \
+ $(test_transport_api_wlan_SOURCES) \
+ $(test_transport_startonly_SOURCES) \
+ $(test_transport_testing_SOURCES)
+DIST_SOURCES = $(libgnunet_plugin_transport_http_la_SOURCES) \
+ $(libgnunet_plugin_transport_https_la_SOURCES) \
+ $(libgnunet_plugin_transport_tcp_la_SOURCES) \
+ $(libgnunet_plugin_transport_template_la_SOURCES) \
+ $(libgnunet_plugin_transport_udp_la_SOURCES) \
+ $(libgnunet_plugin_transport_unix_la_SOURCES) \
+ $(libgnunet_plugin_transport_wlan_la_SOURCES) \
+ $(libgnunettransport_la_SOURCES) \
+ $(libgnunettransporttesting_la_SOURCES) \
+ $(gnunet_helper_transport_wlan_SOURCES) \
+ $(gnunet_helper_transport_wlan_dummy_SOURCES) \
+ $(gnunet_service_transport_SOURCES) \
+ $(gnunet_transport_SOURCES) \
+ $(gnunet_transport_certificate_creation_SOURCES) \
+ $(gnunet_transport_wlan_sender_SOURCES) \
+ $(test_quota_compliance_http_SOURCES) \
+ $(test_quota_compliance_http_asymmetric_SOURCES) \
+ $(test_quota_compliance_https_SOURCES) \
+ $(test_quota_compliance_https_asymmetric_SOURCES) \
+ $(test_quota_compliance_tcp_SOURCES) \
+ $(test_quota_compliance_tcp_asymmetric_SOURCES) \
+ $(test_quota_compliance_udp_SOURCES) \
+ $(test_quota_compliance_unix_SOURCES) \
+ $(test_quota_compliance_unix_asymmetric_SOURCES) \
+ $(test_transport_api_bidirectional_connect_SOURCES) \
+ $(test_transport_api_blacklisting_SOURCES) \
+ $(test_transport_api_disconnect_tcp_SOURCES) \
+ $(test_transport_api_http_SOURCES) \
+ $(test_transport_api_http_nat_SOURCES) \
+ $(test_transport_api_https_SOURCES) \
+ $(test_transport_api_https_nat_SOURCES) \
+ $(test_transport_api_limited_sockets_tcp_SOURCES) \
+ $(test_transport_api_multi_SOURCES) \
+ $(test_transport_api_reliability_http_SOURCES) \
+ $(test_transport_api_reliability_http_nat_SOURCES) \
+ $(test_transport_api_reliability_https_SOURCES) \
+ $(test_transport_api_reliability_https_nat_SOURCES) \
+ $(test_transport_api_reliability_tcp_SOURCES) \
+ $(test_transport_api_reliability_tcp_nat_SOURCES) \
+ $(test_transport_api_reliability_wlan_SOURCES) \
+ $(test_transport_api_restart_1peer_SOURCES) \
+ $(test_transport_api_restart_2peers_SOURCES) \
+ $(test_transport_api_tcp_SOURCES) \
+ $(test_transport_api_tcp_nat_SOURCES) \
+ $(test_transport_api_timeout_http_SOURCES) \
+ $(test_transport_api_timeout_https_SOURCES) \
+ $(test_transport_api_timeout_tcp_SOURCES) \
+ $(test_transport_api_timeout_udp_SOURCES) \
+ $(test_transport_api_timeout_unix_SOURCES) \
+ $(test_transport_api_udp_SOURCES) \
+ $(test_transport_api_udp_nat_SOURCES) \
+ $(test_transport_api_unix_SOURCES) \
+ $(test_transport_api_unreliability_constant_udp_SOURCES) \
+ $(test_transport_api_unreliability_udp_SOURCES) \
+ $(test_transport_api_unreliability_unix_SOURCES) \
+ $(test_transport_api_unreliability_wlan_SOURCES) \
+ $(am__test_transport_api_wlan_SOURCES_DIST) \
+ $(test_transport_startonly_SOURCES) \
+ $(test_transport_testing_SOURCES)
+DATA = $(pkgcfg_DATA)
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+ARGZ_H = @ARGZ_H@
+AS = @AS@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFAULT_INTERFACE = @DEFAULT_INTERFACE@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DLLDIR = @DLLDIR@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+EXT_LIBS = @EXT_LIBS@
+EXT_LIB_PATH = @EXT_LIB_PATH@
+FGREP = @FGREP@
+GMSGFMT = @GMSGFMT@
+GMSGFMT_015 = @GMSGFMT_015@
+GNUNETDNS_GROUP = @GNUNETDNS_GROUP@
+GN_DAEMON_CONFIG_DIR = @GN_DAEMON_CONFIG_DIR@
+GN_DAEMON_HOME_DIR = @GN_DAEMON_HOME_DIR@
+GN_INTLINCL = @GN_INTLINCL@
+GN_LIBINTL = @GN_LIBINTL@
+GN_LIB_LDFLAGS = @GN_LIB_LDFLAGS@
+GN_PLUGIN_LDFLAGS = @GN_PLUGIN_LDFLAGS@
+GN_USER_HOME_DIR = @GN_USER_HOME_DIR@
+GREP = @GREP@
+HAVE_LIBUNISTRING = @HAVE_LIBUNISTRING@
+INCLTDL = @INCLTDL@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INTLLIBS = @INTLLIBS@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBADD_DL = @LIBADD_DL@
+LIBADD_DLD_LINK = @LIBADD_DLD_LINK@
+LIBADD_DLOPEN = @LIBADD_DLOPEN@
+LIBADD_SHL_LOAD = @LIBADD_SHL_LOAD@
+LIBCURL = @LIBCURL@
+LIBCURL_CPPFLAGS = @LIBCURL_CPPFLAGS@
+LIBGCRYPT_CFLAGS = @LIBGCRYPT_CFLAGS@
+LIBGCRYPT_CONFIG = @LIBGCRYPT_CONFIG@
+LIBGCRYPT_LIBS = @LIBGCRYPT_LIBS@
+LIBICONV = @LIBICONV@
+LIBINTL = @LIBINTL@
+LIBLTDL = @LIBLTDL@
+LIBOBJS = @LIBOBJS@
+LIBPREFIX = @LIBPREFIX@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNISTRING = @LIBUNISTRING@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTDLDEPS = @LTDLDEPS@
+LTDLINCL = @LTDLINCL@
+LTDLOPEN = @LTDLOPEN@
+LTLIBICONV = @LTLIBICONV@
+LTLIBINTL = @LTLIBINTL@
+LTLIBOBJS = @LTLIBOBJS@
+LTLIBUNISTRING = @LTLIBUNISTRING@
+LT_CONFIG_H = @LT_CONFIG_H@
+LT_DLLOADERS = @LT_DLLOADERS@
+LT_DLPREOPEN = @LT_DLPREOPEN@
+MAKEINFO = @MAKEINFO@
+MKDIR_P = @MKDIR_P@
+MSGFMT = @MSGFMT@
+MSGFMT_015 = @MSGFMT_015@
+MSGMERGE = @MSGMERGE@
+MYSQL_CPPFLAGS = @MYSQL_CPPFLAGS@
+MYSQL_LDFLAGS = @MYSQL_LDFLAGS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJC = @OBJC@
+OBJCDEPMODE = @OBJCDEPMODE@
+OBJCFLAGS = @OBJCFLAGS@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+POSTGRES_CPPFLAGS = @POSTGRES_CPPFLAGS@
+POSTGRES_LDFLAGS = @POSTGRES_LDFLAGS@
+POSUB = @POSUB@
+PYTHON = @PYTHON@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE_CPPFLAGS = @SQLITE_CPPFLAGS@
+SQLITE_LDFLAGS = @SQLITE_LDFLAGS@
+STRIP = @STRIP@
+SUDO_BINARY = @SUDO_BINARY@
+UNIXONLY = @UNIXONLY@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_015 = @XGETTEXT_015@
+XMKMF = @XMKMF@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+_libcurl_config = @_libcurl_config@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+ac_ct_OBJC = @ac_ct_OBJC@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_target = @build_target@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+lt_ECHO = @lt_ECHO@
+ltdl_LIBOBJS = @ltdl_LIBOBJS@
+ltdl_LTLIBOBJS = @ltdl_LTLIBOBJS@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+subdirs = @subdirs@
+sys_symbol_underscore = @sys_symbol_underscore@
+sysconfdir = @sysconfdir@
+target = @target@
+target_alias = @target_alias@
+target_cpu = @target_cpu@
+target_os = @target_os@
+target_vendor = @target_vendor@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+INCLUDES = -I$(top_srcdir)/src/include -I$(top_builddir)/src/include
+plugindir = $(libdir)/gnunet
+pkgcfgdir = $(pkgdatadir)/config.d/
+pkgcfg_DATA = \
+ transport.conf
+
+@HAVE_MHD_TRUE@GN_LIBMHD = -lmicrohttpd
+@HAVE_MHD_TRUE@HTTP_PLUGIN_LA = libgnunet_plugin_transport_http.la
+@HAVE_MHD_TRUE@HTTP_API_TEST = test_transport_api_http
+@HAVE_MHD_TRUE@HTTP_NAT_API_TEST = test_transport_api_http_nat
+@HAVE_MHD_TRUE@HTTP_API_TIMEOUT_TEST = test_transport_api_timeout_http
+@HAVE_MHD_TRUE@HTTP_REL_TEST = test_transport_api_reliability_http
+@HAVE_MHD_TRUE@HTTP_NAT_REL_TEST = test_transport_api_reliability_http_nat
+@HAVE_MHD_TRUE@HTTP_QUOTA_TEST = test_quota_compliance_http \
+@HAVE_MHD_TRUE@ test_quota_compliance_http_asymmetric
+
+@HAVE_MHD_TRUE@HTTPS_PLUGIN_LA = libgnunet_plugin_transport_https.la
+@HAVE_MHD_TRUE@HTTPS_API_TEST = test_transport_api_https
+@HAVE_MHD_TRUE@HTTPS_NAT_API_TEST = test_transport_api_https_nat
+@HAVE_MHD_TRUE@HTTPS_API_TIMEOUT_TEST = test_transport_api_timeout_https
+@HAVE_MHD_TRUE@HTTPS_REL_TEST = test_transport_api_reliability_https
+@HAVE_MHD_TRUE@HTTPS_NAT_REL_TEST = test_transport_api_reliability_https_nat
+@HAVE_MHD_TRUE@HTTPS_QUOTA_TEST = test_quota_compliance_https \
+@HAVE_MHD_TRUE@ test_quota_compliance_https_asymmetric
+
+@USE_COVERAGE_TRUE@AM_CFLAGS = --coverage -O0
+@LINUX_TRUE@WLAN_BIN = gnunet-helper-transport-wlan
+@LINUX_TRUE@WLAN_BIN_DUMMY = gnunet-helper-transport-wlan-dummy
+@LINUX_TRUE@WLAN_BIN_SENDER = gnunet-transport-wlan-sender
+@LINUX_TRUE@WLAN_PLUGIN_LA = libgnunet_plugin_transport_wlan.la
+@LINUX_TRUE@WLAN_API_TEST = test_transport_api_wlan
+@LINUX_TRUE@WLAN_REL_TEST = test_transport_api_reliability_wlan
+@LINUX_TRUE@WLAN_UREL_TEST = test_transport_api_unreliability_wlan
+@MINGW_FALSE@UNIX_PLUGIN_LA = libgnunet_plugin_transport_unix.la
+@MINGW_FALSE@UNIX_PLUGIN_TEST = test_transport_api_unix
+@MINGW_FALSE@UNIX_PLUGIN_TIMEOUT_TEST = test_transport_api_timeout_unix
+@MINGW_FALSE@UNIX_REL_TEST = test_transport_api_unreliability_unix
+@MINGW_FALSE@UNIX_QUOTA_TEST = test_quota_compliance_unix \
+@MINGW_FALSE@ test_quota_compliance_unix_asymmetric
+
+# gnunet-transport-connect-running-peers
+lib_LTLIBRARIES = \
+ libgnunettransport.la \
+ libgnunettransporttesting.la
+
+libgnunettransporttesting_la_SOURCES = \
+ transport-testing.c transport-testing.h
+
+libgnunettransporttesting_la_LIBADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+
+libgnunettransporttesting_la_DEPENDENCIES = \
+ libgnunettransport.la
+
+libgnunettransporttesting_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS)
+
+libgnunettransport_la_SOURCES = \
+ transport_api.c transport.h \
+ transport_api_blacklist.c \
+ transport_api_address_to_string.c \
+ transport_api_address_lookup.c
+
+libgnunettransport_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+
+libgnunettransport_la_LDFLAGS = \
+ $(GN_LIB_LDFLAGS) $(WINFLAGS) \
+ -version-info 0:0:0
+
+
+#bin_SCRIPTS = \
+# gnunet-transport-certificate-creation
+gnunet_transport_certificate_creation_SOURCES = \
+ gnunet-transport-certificate-creation.c
+
+gnunet_transport_certificate_creation_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+gnunet_helper_transport_wlan_SOURCES = \
+ gnunet-helper-transport-wlan.c
+
+gnunet_helper_transport_wlan_dummy_SOURCES = \
+ gnunet-helper-transport-wlan-dummy.c
+
+gnunet_helper_transport_wlan_dummy_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+gnunet_transport_wlan_sender_SOURCES = \
+ gnunet-transport-wlan-sender.c
+
+gnunet_transport_wlan_sender_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+gnunet_transport_SOURCES = \
+ gnunet-transport.c
+
+gnunet_transport_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_LIBINTL)
+
+gnunet_transport_DEPENDENCIES = \
+ libgnunettransport.la
+
+gnunet_service_transport_SOURCES = \
+ gnunet-service-transport.c gnunet-service-transport.h \
+ gnunet-service-transport_blacklist.h gnunet-service-transport_blacklist.c \
+ gnunet-service-transport_clients.h gnunet-service-transport_clients.c \
+ gnunet-service-transport_hello.h gnunet-service-transport_hello.c \
+ gnunet-service-transport_neighbours.h gnunet-service-transport_neighbours.c \
+ gnunet-service-transport_plugins.h gnunet-service-transport_plugins.c \
+ gnunet-service-transport_validation.h gnunet-service-transport_validation.c
+
+gnunet_service_transport_LDADD = \
+ $(top_builddir)/src/ats/libgnunetats.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(GN_GLPK) \
+ $(GN_LIBINTL)
+
+plugin_LTLIBRARIES = \
+ libgnunet_plugin_transport_tcp.la \
+ libgnunet_plugin_transport_udp.la \
+ $(UNIX_PLUGIN_LA) \
+ $(HTTP_PLUGIN_LA) \
+ $(HTTPS_PLUGIN_LA) \
+ $(WLAN_PLUGIN_LA) \
+ libgnunet_plugin_transport_template.la
+
+libgnunet_plugin_transport_tcp_la_SOURCES = \
+ plugin_transport_tcp.c
+
+libgnunet_plugin_transport_tcp_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+libgnunet_plugin_transport_tcp_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_template_la_SOURCES = \
+ plugin_transport_template.c
+
+libgnunet_plugin_transport_template_la_LIBADD = \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+libgnunet_plugin_transport_template_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_wlan_la_SOURCES = \
+ plugin_transport_wlan.c plugin_transport_wlan.h
+
+libgnunet_plugin_transport_wlan_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+libgnunet_plugin_transport_wlan_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_udp_la_SOURCES = \
+ plugin_transport_udp.c plugin_transport_udp.h \
+ plugin_transport_udp_broadcasting.c
+
+libgnunet_plugin_transport_udp_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/fragmentation/libgnunetfragmentation.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+libgnunet_plugin_transport_udp_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_unix_la_SOURCES = \
+ plugin_transport_unix.c
+
+libgnunet_plugin_transport_unix_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+libgnunet_plugin_transport_unix_la_LDFLAGS = \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_http_la_SOURCES = \
+ plugin_transport_http.c plugin_transport_http.h \
+ plugin_transport_http_client.c plugin_transport_http_server.c
+
+libgnunet_plugin_transport_http_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ @LIBCURL@ \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+libgnunet_plugin_transport_http_la_LDFLAGS = \
+ $(GN_LIBMHD) \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_http_la_CFLAGS = \
+ $(CFLAGS)
+
+libgnunet_plugin_transport_http_la_CPPFLAGS = \
+ @LIBCURL_CPPFLAGS@
+
+libgnunet_plugin_transport_https_la_SOURCES = \
+ plugin_transport_http.c plugin_transport_http.h \
+ plugin_transport_http_client.c plugin_transport_http_server.c
+
+libgnunet_plugin_transport_https_la_LIBADD = \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/peerinfo/libgnunetpeerinfo.la \
+ @LIBCURL@ \
+ $(top_builddir)/src/nat/libgnunetnat.la \
+ $(top_builddir)/src/util/libgnunetutil.la
+
+libgnunet_plugin_transport_https_la_LDFLAGS = \
+ $(GN_LIBMHD) \
+ $(GN_PLUGIN_LDFLAGS)
+
+libgnunet_plugin_transport_https_la_CFLAGS = \
+ $(CFLAGS) -DBUILD_HTTPS
+
+libgnunet_plugin_transport_https_la_CPPFLAGS = \
+ @LIBCURL_CPPFLAGS@
+
+test_transport_testing_SOURCES = \
+ test_transport_testing.c
+
+test_transport_testing_LDADD = \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+
+#gnunet_transport_connect_running_peers_SOURCES = \
+# gnunet-transport-connect-running-peers.c
+#gnunet_transport_connect_running_peers_LDADD = \
+# $(top_builddir)/src/transport/libgnunettransport.la \
+# $(top_builddir)/src/hello/libgnunethello.la \
+# $(top_builddir)/src/util/libgnunetutil.la \
+# $(top_builddir)/src/transport/libgnunettransporttesting.la
+test_transport_api_blacklisting_SOURCES = \
+ test_transport_api_blacklisting.c
+
+test_transport_api_blacklisting_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_disconnect_tcp_SOURCES = \
+ test_transport_api_disconnect.c
+
+test_transport_api_disconnect_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_startonly_SOURCES = \
+ test_transport_startonly.c
+
+test_transport_startonly_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_tcp_SOURCES = \
+ test_transport_api.c
+
+test_transport_api_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_bidirectional_connect_SOURCES = \
+ test_transport_api_bidirectional_connect.c
+
+test_transport_api_bidirectional_connect_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_restart_1peer_SOURCES = \
+ test_transport_api_restart_1peer.c
+
+test_transport_api_restart_1peer_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_restart_2peers_SOURCES = \
+ test_transport_api_restart_2peers.c
+
+test_transport_api_restart_2peers_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/statistics/libgnunetstatistics.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_limited_sockets_tcp_SOURCES = \
+ test_transport_api_limited_sockets.c
+
+test_transport_api_limited_sockets_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_tcp_nat_SOURCES = \
+ test_transport_api.c
+
+test_transport_api_tcp_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_tcp_SOURCES = \
+ test_transport_api_reliability.c
+
+test_transport_api_reliability_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_timeout_tcp_SOURCES = \
+ test_transport_api_timeout.c
+
+test_transport_api_timeout_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_timeout_unix_SOURCES = \
+ test_transport_api_timeout.c
+
+test_transport_api_timeout_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_timeout_http_SOURCES = \
+ test_transport_api_timeout.c
+
+test_transport_api_timeout_http_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_timeout_https_SOURCES = \
+ test_transport_api_timeout.c
+
+test_transport_api_timeout_https_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_tcp_nat_SOURCES = \
+ test_transport_api_reliability.c
+
+test_transport_api_reliability_tcp_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_wlan_SOURCES = \
+ test_transport_api_reliability.c
+
+test_transport_api_reliability_wlan_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_unreliability_wlan_SOURCES = \
+ test_transport_api_unreliability.c
+
+test_transport_api_unreliability_wlan_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_udp_SOURCES = \
+ test_transport_api.c
+
+test_transport_api_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_timeout_udp_SOURCES = \
+ test_transport_api_timeout.c
+
+test_transport_api_timeout_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_udp_nat_SOURCES = \
+ test_transport_api.c
+
+test_transport_api_udp_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_unix_SOURCES = \
+ test_transport_api.c
+
+test_transport_api_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_http_SOURCES = \
+ test_transport_api.c
+
+test_transport_api_http_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_http_nat_SOURCES = \
+ test_transport_api.c
+
+test_transport_api_http_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_http_SOURCES = \
+ test_transport_api_reliability.c
+
+test_transport_api_reliability_http_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_http_nat_SOURCES = \
+ test_transport_api_reliability.c
+
+test_transport_api_reliability_http_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_https_SOURCES = \
+ test_transport_api.c
+
+test_transport_api_https_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_https_nat_SOURCES = \
+ test_transport_api.c
+
+test_transport_api_https_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_https_SOURCES = \
+ test_transport_api_reliability.c
+
+test_transport_api_reliability_https_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_reliability_https_nat_SOURCES = \
+ test_transport_api_reliability.c
+
+test_transport_api_reliability_https_nat_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_unreliability_unix_SOURCES = \
+ test_transport_api_unreliability.c
+
+test_transport_api_unreliability_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_unreliability_udp_SOURCES = \
+ test_transport_api_unreliability.c
+
+test_transport_api_unreliability_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_unreliability_constant_udp_SOURCES = \
+ test_transport_api_unreliability_constant.c
+
+test_transport_api_unreliability_constant_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+@LINUX_TRUE@test_transport_api_wlan_SOURCES = \
+@LINUX_TRUE@ test_transport_api.c
+
+@LINUX_TRUE@test_transport_api_wlan_LDADD = \
+@LINUX_TRUE@ $(top_builddir)/src/transport/libgnunettransport.la \
+@LINUX_TRUE@ $(top_builddir)/src/hello/libgnunethello.la \
+@LINUX_TRUE@ $(top_builddir)/src/util/libgnunetutil.la \
+@LINUX_TRUE@ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_quota_compliance_tcp_SOURCES = \
+ test_quota_compliance.c
+
+test_quota_compliance_tcp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_quota_compliance_tcp_asymmetric_SOURCES = \
+ test_quota_compliance.c
+
+test_quota_compliance_tcp_asymmetric_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+
+#test_quota_compliance_tcp_asymmetric_send_constant_SOURCES = \
+# test_quota_compliance.c
+#test_quota_compliance_tcp_asymmetric_send_constant_LDADD = \
+# $(top_builddir)/src/transport/libgnunettransport.la \
+# $(top_builddir)/src/util/libgnunetutil.la
+test_quota_compliance_http_SOURCES = \
+ test_quota_compliance.c
+
+test_quota_compliance_http_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_quota_compliance_http_asymmetric_SOURCES = \
+ test_quota_compliance.c
+
+test_quota_compliance_http_asymmetric_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+
+#test_quota_compliance_http_asymmetric_send_constant_SOURCES = \
+# test_quota_compliance.c
+#test_quota_compliance_http_asymmetric_send_constant_LDADD = \
+# $(top_builddir)/src/transport/libgnunettransport.la \
+# $(top_builddir)/src/util/libgnunetutil.la
+test_quota_compliance_https_SOURCES = \
+ test_quota_compliance.c
+
+test_quota_compliance_https_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_quota_compliance_https_asymmetric_SOURCES = \
+ test_quota_compliance.c
+
+test_quota_compliance_https_asymmetric_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+
+#test_quota_compliance_https_asymmetric_send_constant_SOURCES = \
+# test_quota_compliance.c
+#test_quota_compliance_https_asymmetric_send_constant_LDADD = \
+# $(top_builddir)/src/transport/libgnunettransport.la \
+# $(top_builddir)/src/util/libgnunetutil.la
+test_quota_compliance_udp_SOURCES = \
+ test_quota_compliance.c
+
+test_quota_compliance_udp_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_quota_compliance_unix_SOURCES = \
+ test_quota_compliance.c
+
+test_quota_compliance_unix_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_quota_compliance_unix_asymmetric_SOURCES = \
+ test_quota_compliance.c
+
+test_quota_compliance_unix_asymmetric_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+test_transport_api_multi_SOURCES = \
+ test_transport_api.c
+
+test_transport_api_multi_LDADD = \
+ $(top_builddir)/src/transport/libgnunettransport.la \
+ $(top_builddir)/src/hello/libgnunethello.la \
+ $(top_builddir)/src/util/libgnunetutil.la \
+ $(top_builddir)/src/transport/libgnunettransporttesting.la
+
+EXTRA_DIST = \
+gnunet-transport-certificate-creation \
+template_cfg_peer1.conf\
+template_cfg_peer2.conf\
+test_plugin_transport_data.conf\
+test_plugin_transport_data_udp.conf\
+test_quota_compliance_data.conf\
+test_quota_compliance_http_peer1.conf\
+test_quota_compliance_http_peer2.conf\
+test_quota_compliance_https_peer1.conf\
+test_quota_compliance_https_peer2.conf\
+test_quota_compliance_tcp_peer1.conf\
+test_quota_compliance_tcp_peer2.conf\
+test_quota_compliance_udp_peer1.conf\
+test_quota_compliance_udp_peer2.conf\
+test_quota_compliance_unix_peer1.conf\
+test_quota_compliance_unix_peer2.conf\
+test_quota_compliance_http_asymmetric_peer1.conf\
+test_quota_compliance_http_asymmetric_peer2.conf\
+test_quota_compliance_https_asymmetric_peer1.conf\
+test_quota_compliance_https_asymmetric_peer2.conf\
+test_quota_compliance_tcp_asymmetric_peer1.conf\
+test_quota_compliance_tcp_asymmetric_peer2.conf\
+test_quota_compliance_unix_asymmetric_peer1.conf\
+test_quota_compliance_unix_asymmetric_peer2.conf\
+test_transport_api_data.conf\
+test_transport_api_http_peer1.conf\
+test_transport_api_http_peer2.conf\
+test_transport_api_https_peer1.conf\
+test_transport_api_https_peer2.conf\
+test_transport_api_limited_sockets_tcp_peer1.conf\
+test_transport_api_limited_sockets_tcp_peer2.conf\
+test_transport_api_timeout_tcp_peer1.conf\
+test_transport_api_timeout_tcp_peer2.conf\
+test_transport_api_multi_peer1.conf\
+test_transport_api_multi_peer2.conf\
+test_transport_api_reliability_http_peer1.conf\
+test_transport_api_reliability_http_peer2.conf\
+test_transport_api_reliability_https_peer1.conf\
+test_transport_api_reliability_https_peer2.conf\
+test_transport_api_reliability_tcp_nat_peer1.conf\
+test_transport_api_reliability_tcp_nat_peer2.conf\
+test_transport_api_reliability_tcp_peer1.conf\
+test_transport_api_reliability_tcp_peer2.conf\
+test_transport_api_reliability_wlan_peer1.conf\
+test_transport_api_reliability_wlan_peer2.conf\
+test_transport_api_bidirectional_connect_peer1.conf\
+test_transport_api_bidirectional_connect_peer2.conf\
+test_transport_api_tcp_nat_peer1.conf\
+test_transport_api_tcp_nat_peer2.conf\
+test_transport_api_tcp_peer1.conf\
+test_transport_api_tcp_peer2.conf\
+test_transport_api_udp_nat_peer1.conf\
+test_transport_api_udp_nat_peer2.conf\
+test_transport_api_udp_peer1.conf\
+test_transport_api_udp_peer2.conf\
+test_transport_api_timeout_udp_peer1.conf\
+test_transport_api_timeout_udp_peer2.conf\
+test_transport_api_unix_peer1.conf\
+test_transport_api_unix_peer2.conf\
+test_transport_api_timeout_unix_peer1.conf\
+test_transport_api_timeout_unix_peer2.conf\
+test_transport_api_unreliability_udp_peer1.conf\
+test_transport_api_unreliability_udp_peer2.conf\
+test_transport_api_unreliability_unix_peer1.conf\
+test_transport_api_unreliability_unix_peer2.conf\
+test_transport_api_unreliability_wlan_peer1.conf\
+test_transport_api_unreliability_wlan_peer2.conf\
+test_transport_api_wlan_peer1.conf\
+test_transport_api_wlan_peer2.conf\
+test_transport_defaults.conf\
+test_transport_startonly.conf\
+test_transport_api_disconnect_tcp_peer1.conf\
+test_transport_api_disconnect_tcp_peer2.conf\
+test_transport_api_http_nat_peer1.conf\
+test_transport_api_http_nat_peer2.conf\
+test_transport_api_https_nat_peer1.conf\
+test_transport_api_https_nat_peer2.conf\
+test_transport_api_reliability_http_nat_peer1.conf\
+test_transport_api_reliability_http_nat_peer2.conf\
+test_transport_api_reliability_https_nat_peer1.conf\
+test_transport_api_reliability_https_nat_peer2.conf\
+test_transport_api_timeout_http_peer1.conf\
+test_transport_api_timeout_http_peer2.conf\
+test_transport_api_timeout_https_peer1.conf\
+test_transport_api_timeout_https_peer2.conf\
+test_transport_api_unreliability_constant_udp_peer1.conf\
+test_transport_api_unreliability_constant_udp_peer2.conf
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/transport/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu src/transport/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+transport.conf: $(top_builddir)/config.status $(srcdir)/transport.conf.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
+ }
+
+uninstall-pluginLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(plugindir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(plugindir)/$$f"; \
+ done
+
+clean-pluginLTLIBRARIES:
+ -test -z "$(plugin_LTLIBRARIES)" || rm -f $(plugin_LTLIBRARIES)
+ @list='$(plugin_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libgnunet_plugin_transport_http.la: $(libgnunet_plugin_transport_http_la_OBJECTS) $(libgnunet_plugin_transport_http_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunet_plugin_transport_http_la_LINK) $(am_libgnunet_plugin_transport_http_la_rpath) $(libgnunet_plugin_transport_http_la_OBJECTS) $(libgnunet_plugin_transport_http_la_LIBADD) $(LIBS)
+libgnunet_plugin_transport_https.la: $(libgnunet_plugin_transport_https_la_OBJECTS) $(libgnunet_plugin_transport_https_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunet_plugin_transport_https_la_LINK) $(am_libgnunet_plugin_transport_https_la_rpath) $(libgnunet_plugin_transport_https_la_OBJECTS) $(libgnunet_plugin_transport_https_la_LIBADD) $(LIBS)
+libgnunet_plugin_transport_tcp.la: $(libgnunet_plugin_transport_tcp_la_OBJECTS) $(libgnunet_plugin_transport_tcp_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunet_plugin_transport_tcp_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_tcp_la_OBJECTS) $(libgnunet_plugin_transport_tcp_la_LIBADD) $(LIBS)
+libgnunet_plugin_transport_template.la: $(libgnunet_plugin_transport_template_la_OBJECTS) $(libgnunet_plugin_transport_template_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunet_plugin_transport_template_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_template_la_OBJECTS) $(libgnunet_plugin_transport_template_la_LIBADD) $(LIBS)
+libgnunet_plugin_transport_udp.la: $(libgnunet_plugin_transport_udp_la_OBJECTS) $(libgnunet_plugin_transport_udp_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunet_plugin_transport_udp_la_LINK) -rpath $(plugindir) $(libgnunet_plugin_transport_udp_la_OBJECTS) $(libgnunet_plugin_transport_udp_la_LIBADD) $(LIBS)
+libgnunet_plugin_transport_unix.la: $(libgnunet_plugin_transport_unix_la_OBJECTS) $(libgnunet_plugin_transport_unix_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunet_plugin_transport_unix_la_LINK) $(am_libgnunet_plugin_transport_unix_la_rpath) $(libgnunet_plugin_transport_unix_la_OBJECTS) $(libgnunet_plugin_transport_unix_la_LIBADD) $(LIBS)
+libgnunet_plugin_transport_wlan.la: $(libgnunet_plugin_transport_wlan_la_OBJECTS) $(libgnunet_plugin_transport_wlan_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunet_plugin_transport_wlan_la_LINK) $(am_libgnunet_plugin_transport_wlan_la_rpath) $(libgnunet_plugin_transport_wlan_la_OBJECTS) $(libgnunet_plugin_transport_wlan_la_LIBADD) $(LIBS)
+libgnunettransport.la: $(libgnunettransport_la_OBJECTS) $(libgnunettransport_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunettransport_la_LINK) -rpath $(libdir) $(libgnunettransport_la_OBJECTS) $(libgnunettransport_la_LIBADD) $(LIBS)
+libgnunettransporttesting.la: $(libgnunettransporttesting_la_OBJECTS) $(libgnunettransporttesting_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgnunettransporttesting_la_LINK) -rpath $(libdir) $(libgnunettransporttesting_la_OBJECTS) $(libgnunettransporttesting_la_LIBADD) $(LIBS)
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p || test -f $$p1; \
+ then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-checkPROGRAMS:
+ @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+clean-noinstPROGRAMS:
+ @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+gnunet-helper-transport-wlan$(EXEEXT): $(gnunet_helper_transport_wlan_OBJECTS) $(gnunet_helper_transport_wlan_DEPENDENCIES)
+ @rm -f gnunet-helper-transport-wlan$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_helper_transport_wlan_OBJECTS) $(gnunet_helper_transport_wlan_LDADD) $(LIBS)
+gnunet-helper-transport-wlan-dummy$(EXEEXT): $(gnunet_helper_transport_wlan_dummy_OBJECTS) $(gnunet_helper_transport_wlan_dummy_DEPENDENCIES)
+ @rm -f gnunet-helper-transport-wlan-dummy$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_helper_transport_wlan_dummy_OBJECTS) $(gnunet_helper_transport_wlan_dummy_LDADD) $(LIBS)
+gnunet-service-transport$(EXEEXT): $(gnunet_service_transport_OBJECTS) $(gnunet_service_transport_DEPENDENCIES)
+ @rm -f gnunet-service-transport$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_service_transport_OBJECTS) $(gnunet_service_transport_LDADD) $(LIBS)
+gnunet-transport$(EXEEXT): $(gnunet_transport_OBJECTS) $(gnunet_transport_DEPENDENCIES)
+ @rm -f gnunet-transport$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_transport_OBJECTS) $(gnunet_transport_LDADD) $(LIBS)
+gnunet-transport-certificate-creation$(EXEEXT): $(gnunet_transport_certificate_creation_OBJECTS) $(gnunet_transport_certificate_creation_DEPENDENCIES)
+ @rm -f gnunet-transport-certificate-creation$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_transport_certificate_creation_OBJECTS) $(gnunet_transport_certificate_creation_LDADD) $(LIBS)
+gnunet-transport-wlan-sender$(EXEEXT): $(gnunet_transport_wlan_sender_OBJECTS) $(gnunet_transport_wlan_sender_DEPENDENCIES)
+ @rm -f gnunet-transport-wlan-sender$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(gnunet_transport_wlan_sender_OBJECTS) $(gnunet_transport_wlan_sender_LDADD) $(LIBS)
+test_quota_compliance_http$(EXEEXT): $(test_quota_compliance_http_OBJECTS) $(test_quota_compliance_http_DEPENDENCIES)
+ @rm -f test_quota_compliance_http$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_quota_compliance_http_OBJECTS) $(test_quota_compliance_http_LDADD) $(LIBS)
+test_quota_compliance_http_asymmetric$(EXEEXT): $(test_quota_compliance_http_asymmetric_OBJECTS) $(test_quota_compliance_http_asymmetric_DEPENDENCIES)
+ @rm -f test_quota_compliance_http_asymmetric$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_quota_compliance_http_asymmetric_OBJECTS) $(test_quota_compliance_http_asymmetric_LDADD) $(LIBS)
+test_quota_compliance_https$(EXEEXT): $(test_quota_compliance_https_OBJECTS) $(test_quota_compliance_https_DEPENDENCIES)
+ @rm -f test_quota_compliance_https$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_quota_compliance_https_OBJECTS) $(test_quota_compliance_https_LDADD) $(LIBS)
+test_quota_compliance_https_asymmetric$(EXEEXT): $(test_quota_compliance_https_asymmetric_OBJECTS) $(test_quota_compliance_https_asymmetric_DEPENDENCIES)
+ @rm -f test_quota_compliance_https_asymmetric$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_quota_compliance_https_asymmetric_OBJECTS) $(test_quota_compliance_https_asymmetric_LDADD) $(LIBS)
+test_quota_compliance_tcp$(EXEEXT): $(test_quota_compliance_tcp_OBJECTS) $(test_quota_compliance_tcp_DEPENDENCIES)
+ @rm -f test_quota_compliance_tcp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_quota_compliance_tcp_OBJECTS) $(test_quota_compliance_tcp_LDADD) $(LIBS)
+test_quota_compliance_tcp_asymmetric$(EXEEXT): $(test_quota_compliance_tcp_asymmetric_OBJECTS) $(test_quota_compliance_tcp_asymmetric_DEPENDENCIES)
+ @rm -f test_quota_compliance_tcp_asymmetric$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_quota_compliance_tcp_asymmetric_OBJECTS) $(test_quota_compliance_tcp_asymmetric_LDADD) $(LIBS)
+test_quota_compliance_udp$(EXEEXT): $(test_quota_compliance_udp_OBJECTS) $(test_quota_compliance_udp_DEPENDENCIES)
+ @rm -f test_quota_compliance_udp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_quota_compliance_udp_OBJECTS) $(test_quota_compliance_udp_LDADD) $(LIBS)
+test_quota_compliance_unix$(EXEEXT): $(test_quota_compliance_unix_OBJECTS) $(test_quota_compliance_unix_DEPENDENCIES)
+ @rm -f test_quota_compliance_unix$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_quota_compliance_unix_OBJECTS) $(test_quota_compliance_unix_LDADD) $(LIBS)
+test_quota_compliance_unix_asymmetric$(EXEEXT): $(test_quota_compliance_unix_asymmetric_OBJECTS) $(test_quota_compliance_unix_asymmetric_DEPENDENCIES)
+ @rm -f test_quota_compliance_unix_asymmetric$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_quota_compliance_unix_asymmetric_OBJECTS) $(test_quota_compliance_unix_asymmetric_LDADD) $(LIBS)
+test_transport_api_bidirectional_connect$(EXEEXT): $(test_transport_api_bidirectional_connect_OBJECTS) $(test_transport_api_bidirectional_connect_DEPENDENCIES)
+ @rm -f test_transport_api_bidirectional_connect$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_bidirectional_connect_OBJECTS) $(test_transport_api_bidirectional_connect_LDADD) $(LIBS)
+test_transport_api_blacklisting$(EXEEXT): $(test_transport_api_blacklisting_OBJECTS) $(test_transport_api_blacklisting_DEPENDENCIES)
+ @rm -f test_transport_api_blacklisting$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_blacklisting_OBJECTS) $(test_transport_api_blacklisting_LDADD) $(LIBS)
+test_transport_api_disconnect_tcp$(EXEEXT): $(test_transport_api_disconnect_tcp_OBJECTS) $(test_transport_api_disconnect_tcp_DEPENDENCIES)
+ @rm -f test_transport_api_disconnect_tcp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_disconnect_tcp_OBJECTS) $(test_transport_api_disconnect_tcp_LDADD) $(LIBS)
+test_transport_api_http$(EXEEXT): $(test_transport_api_http_OBJECTS) $(test_transport_api_http_DEPENDENCIES)
+ @rm -f test_transport_api_http$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_http_OBJECTS) $(test_transport_api_http_LDADD) $(LIBS)
+test_transport_api_http_nat$(EXEEXT): $(test_transport_api_http_nat_OBJECTS) $(test_transport_api_http_nat_DEPENDENCIES)
+ @rm -f test_transport_api_http_nat$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_http_nat_OBJECTS) $(test_transport_api_http_nat_LDADD) $(LIBS)
+test_transport_api_https$(EXEEXT): $(test_transport_api_https_OBJECTS) $(test_transport_api_https_DEPENDENCIES)
+ @rm -f test_transport_api_https$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_https_OBJECTS) $(test_transport_api_https_LDADD) $(LIBS)
+test_transport_api_https_nat$(EXEEXT): $(test_transport_api_https_nat_OBJECTS) $(test_transport_api_https_nat_DEPENDENCIES)
+ @rm -f test_transport_api_https_nat$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_https_nat_OBJECTS) $(test_transport_api_https_nat_LDADD) $(LIBS)
+test_transport_api_limited_sockets_tcp$(EXEEXT): $(test_transport_api_limited_sockets_tcp_OBJECTS) $(test_transport_api_limited_sockets_tcp_DEPENDENCIES)
+ @rm -f test_transport_api_limited_sockets_tcp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_limited_sockets_tcp_OBJECTS) $(test_transport_api_limited_sockets_tcp_LDADD) $(LIBS)
+test_transport_api_multi$(EXEEXT): $(test_transport_api_multi_OBJECTS) $(test_transport_api_multi_DEPENDENCIES)
+ @rm -f test_transport_api_multi$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_multi_OBJECTS) $(test_transport_api_multi_LDADD) $(LIBS)
+test_transport_api_reliability_http$(EXEEXT): $(test_transport_api_reliability_http_OBJECTS) $(test_transport_api_reliability_http_DEPENDENCIES)
+ @rm -f test_transport_api_reliability_http$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_http_OBJECTS) $(test_transport_api_reliability_http_LDADD) $(LIBS)
+test_transport_api_reliability_http_nat$(EXEEXT): $(test_transport_api_reliability_http_nat_OBJECTS) $(test_transport_api_reliability_http_nat_DEPENDENCIES)
+ @rm -f test_transport_api_reliability_http_nat$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_http_nat_OBJECTS) $(test_transport_api_reliability_http_nat_LDADD) $(LIBS)
+test_transport_api_reliability_https$(EXEEXT): $(test_transport_api_reliability_https_OBJECTS) $(test_transport_api_reliability_https_DEPENDENCIES)
+ @rm -f test_transport_api_reliability_https$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_https_OBJECTS) $(test_transport_api_reliability_https_LDADD) $(LIBS)
+test_transport_api_reliability_https_nat$(EXEEXT): $(test_transport_api_reliability_https_nat_OBJECTS) $(test_transport_api_reliability_https_nat_DEPENDENCIES)
+ @rm -f test_transport_api_reliability_https_nat$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_https_nat_OBJECTS) $(test_transport_api_reliability_https_nat_LDADD) $(LIBS)
+test_transport_api_reliability_tcp$(EXEEXT): $(test_transport_api_reliability_tcp_OBJECTS) $(test_transport_api_reliability_tcp_DEPENDENCIES)
+ @rm -f test_transport_api_reliability_tcp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_tcp_OBJECTS) $(test_transport_api_reliability_tcp_LDADD) $(LIBS)
+test_transport_api_reliability_tcp_nat$(EXEEXT): $(test_transport_api_reliability_tcp_nat_OBJECTS) $(test_transport_api_reliability_tcp_nat_DEPENDENCIES)
+ @rm -f test_transport_api_reliability_tcp_nat$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_tcp_nat_OBJECTS) $(test_transport_api_reliability_tcp_nat_LDADD) $(LIBS)
+test_transport_api_reliability_wlan$(EXEEXT): $(test_transport_api_reliability_wlan_OBJECTS) $(test_transport_api_reliability_wlan_DEPENDENCIES)
+ @rm -f test_transport_api_reliability_wlan$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_reliability_wlan_OBJECTS) $(test_transport_api_reliability_wlan_LDADD) $(LIBS)
+test_transport_api_restart_1peer$(EXEEXT): $(test_transport_api_restart_1peer_OBJECTS) $(test_transport_api_restart_1peer_DEPENDENCIES)
+ @rm -f test_transport_api_restart_1peer$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_restart_1peer_OBJECTS) $(test_transport_api_restart_1peer_LDADD) $(LIBS)
+test_transport_api_restart_2peers$(EXEEXT): $(test_transport_api_restart_2peers_OBJECTS) $(test_transport_api_restart_2peers_DEPENDENCIES)
+ @rm -f test_transport_api_restart_2peers$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_restart_2peers_OBJECTS) $(test_transport_api_restart_2peers_LDADD) $(LIBS)
+test_transport_api_tcp$(EXEEXT): $(test_transport_api_tcp_OBJECTS) $(test_transport_api_tcp_DEPENDENCIES)
+ @rm -f test_transport_api_tcp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_tcp_OBJECTS) $(test_transport_api_tcp_LDADD) $(LIBS)
+test_transport_api_tcp_nat$(EXEEXT): $(test_transport_api_tcp_nat_OBJECTS) $(test_transport_api_tcp_nat_DEPENDENCIES)
+ @rm -f test_transport_api_tcp_nat$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_tcp_nat_OBJECTS) $(test_transport_api_tcp_nat_LDADD) $(LIBS)
+test_transport_api_timeout_http$(EXEEXT): $(test_transport_api_timeout_http_OBJECTS) $(test_transport_api_timeout_http_DEPENDENCIES)
+ @rm -f test_transport_api_timeout_http$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_http_OBJECTS) $(test_transport_api_timeout_http_LDADD) $(LIBS)
+test_transport_api_timeout_https$(EXEEXT): $(test_transport_api_timeout_https_OBJECTS) $(test_transport_api_timeout_https_DEPENDENCIES)
+ @rm -f test_transport_api_timeout_https$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_https_OBJECTS) $(test_transport_api_timeout_https_LDADD) $(LIBS)
+test_transport_api_timeout_tcp$(EXEEXT): $(test_transport_api_timeout_tcp_OBJECTS) $(test_transport_api_timeout_tcp_DEPENDENCIES)
+ @rm -f test_transport_api_timeout_tcp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_tcp_OBJECTS) $(test_transport_api_timeout_tcp_LDADD) $(LIBS)
+test_transport_api_timeout_udp$(EXEEXT): $(test_transport_api_timeout_udp_OBJECTS) $(test_transport_api_timeout_udp_DEPENDENCIES)
+ @rm -f test_transport_api_timeout_udp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_udp_OBJECTS) $(test_transport_api_timeout_udp_LDADD) $(LIBS)
+test_transport_api_timeout_unix$(EXEEXT): $(test_transport_api_timeout_unix_OBJECTS) $(test_transport_api_timeout_unix_DEPENDENCIES)
+ @rm -f test_transport_api_timeout_unix$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_timeout_unix_OBJECTS) $(test_transport_api_timeout_unix_LDADD) $(LIBS)
+test_transport_api_udp$(EXEEXT): $(test_transport_api_udp_OBJECTS) $(test_transport_api_udp_DEPENDENCIES)
+ @rm -f test_transport_api_udp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_udp_OBJECTS) $(test_transport_api_udp_LDADD) $(LIBS)
+test_transport_api_udp_nat$(EXEEXT): $(test_transport_api_udp_nat_OBJECTS) $(test_transport_api_udp_nat_DEPENDENCIES)
+ @rm -f test_transport_api_udp_nat$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_udp_nat_OBJECTS) $(test_transport_api_udp_nat_LDADD) $(LIBS)
+test_transport_api_unix$(EXEEXT): $(test_transport_api_unix_OBJECTS) $(test_transport_api_unix_DEPENDENCIES)
+ @rm -f test_transport_api_unix$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_unix_OBJECTS) $(test_transport_api_unix_LDADD) $(LIBS)
+test_transport_api_unreliability_constant_udp$(EXEEXT): $(test_transport_api_unreliability_constant_udp_OBJECTS) $(test_transport_api_unreliability_constant_udp_DEPENDENCIES)
+ @rm -f test_transport_api_unreliability_constant_udp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_constant_udp_OBJECTS) $(test_transport_api_unreliability_constant_udp_LDADD) $(LIBS)
+test_transport_api_unreliability_udp$(EXEEXT): $(test_transport_api_unreliability_udp_OBJECTS) $(test_transport_api_unreliability_udp_DEPENDENCIES)
+ @rm -f test_transport_api_unreliability_udp$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_udp_OBJECTS) $(test_transport_api_unreliability_udp_LDADD) $(LIBS)
+test_transport_api_unreliability_unix$(EXEEXT): $(test_transport_api_unreliability_unix_OBJECTS) $(test_transport_api_unreliability_unix_DEPENDENCIES)
+ @rm -f test_transport_api_unreliability_unix$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_unix_OBJECTS) $(test_transport_api_unreliability_unix_LDADD) $(LIBS)
+test_transport_api_unreliability_wlan$(EXEEXT): $(test_transport_api_unreliability_wlan_OBJECTS) $(test_transport_api_unreliability_wlan_DEPENDENCIES)
+ @rm -f test_transport_api_unreliability_wlan$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_unreliability_wlan_OBJECTS) $(test_transport_api_unreliability_wlan_LDADD) $(LIBS)
+test_transport_api_wlan$(EXEEXT): $(test_transport_api_wlan_OBJECTS) $(test_transport_api_wlan_DEPENDENCIES)
+ @rm -f test_transport_api_wlan$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_api_wlan_OBJECTS) $(test_transport_api_wlan_LDADD) $(LIBS)
+test_transport_startonly$(EXEEXT): $(test_transport_startonly_OBJECTS) $(test_transport_startonly_DEPENDENCIES)
+ @rm -f test_transport_startonly$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_startonly_OBJECTS) $(test_transport_startonly_LDADD) $(LIBS)
+test_transport_testing$(EXEEXT): $(test_transport_testing_OBJECTS) $(test_transport_testing_DEPENDENCIES)
+ @rm -f test_transport_testing$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_transport_testing_OBJECTS) $(test_transport_testing_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-transport-wlan-dummy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-helper-transport-wlan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_blacklist.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_clients.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_hello.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_neighbours.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_plugins.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-service-transport_validation.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-transport-certificate-creation.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-transport-wlan-sender.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnunet-transport.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_tcp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_template.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_udp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_udp_broadcasting.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_unix.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/plugin_transport_wlan.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_quota_compliance.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_bidirectional_connect.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_blacklisting.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_disconnect.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_limited_sockets.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_reliability.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_restart_1peer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_restart_2peers.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_timeout.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_unreliability.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_api_unreliability_constant.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_startonly.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test_transport_testing.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport-testing.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api_address_lookup.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api_address_to_string.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/transport_api_blacklist.Plo@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libgnunet_plugin_transport_http_la-plugin_transport_http.lo: plugin_transport_http.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_http_la-plugin_transport_http.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Tpo -c -o libgnunet_plugin_transport_http_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Tpo $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http.c' object='libgnunet_plugin_transport_http_la-plugin_transport_http.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_http_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c
+
+libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo: plugin_transport_http_client.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Tpo -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Tpo $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_client.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_client.c' object='libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c
+
+libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo: plugin_transport_http_server.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Tpo -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Tpo $(DEPDIR)/libgnunet_plugin_transport_http_la-plugin_transport_http_server.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_server.c' object='libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_http_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_http_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_http_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c
+
+libgnunet_plugin_transport_https_la-plugin_transport_http.lo: plugin_transport_http.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_https_la-plugin_transport_http.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Tpo -c -o libgnunet_plugin_transport_https_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Tpo $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http.c' object='libgnunet_plugin_transport_https_la-plugin_transport_http.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_https_la-plugin_transport_http.lo `test -f 'plugin_transport_http.c' || echo '$(srcdir)/'`plugin_transport_http.c
+
+libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo: plugin_transport_http_client.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Tpo -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Tpo $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_client.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_client.c' object='libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_client.lo `test -f 'plugin_transport_http_client.c' || echo '$(srcdir)/'`plugin_transport_http_client.c
+
+libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo: plugin_transport_http_server.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -MT libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo -MD -MP -MF $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Tpo -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Tpo $(DEPDIR)/libgnunet_plugin_transport_https_la-plugin_transport_http_server.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='plugin_transport_http_server.c' object='libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libgnunet_plugin_transport_https_la_CPPFLAGS) $(CPPFLAGS) $(libgnunet_plugin_transport_https_la_CFLAGS) $(CFLAGS) -c -o libgnunet_plugin_transport_https_la-plugin_transport_http_server.lo `test -f 'plugin_transport_http_server.c' || echo '$(srcdir)/'`plugin_transport_http_server.c
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-pkgcfgDATA: $(pkgcfg_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(pkgcfgdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgcfgdir)"
+ @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pkgcfgdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(pkgcfgdir)" || exit $$?; \
+ done
+
+uninstall-pkgcfgDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkgcfg_DATA)'; test -n "$(pkgcfgdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(pkgcfgdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(pkgcfgdir)" && rm -f $$files
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: CTAGS
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ echo "$$grn$$dashes"; \
+ else \
+ echo "$$red$$dashes"; \
+ fi; \
+ echo "$$banner"; \
+ test -z "$$skipped" || echo "$$skipped"; \
+ test -z "$$report" || echo "$$report"; \
+ echo "$$dashes$$std"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(PROGRAMS) $(DATA)
+install-binPROGRAMS: install-libLTLIBRARIES
+
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(pkgcfgdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS \
+ clean-pluginLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-pkgcfgDATA install-pluginLTLIBRARIES
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-libLTLIBRARIES
+ @$(NORMAL_INSTALL)
+ $(MAKE) $(AM_MAKEFLAGS) install-exec-hook
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES
+
+.MAKE: check-am install-am install-exec-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-binPROGRAMS clean-checkPROGRAMS clean-generic \
+ clean-libLTLIBRARIES clean-libtool clean-noinstPROGRAMS \
+ clean-pluginLTLIBRARIES ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-binPROGRAMS install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-exec-hook \
+ install-html install-html-am install-info install-info-am \
+ install-libLTLIBRARIES install-man install-pdf install-pdf-am \
+ install-pkgcfgDATA install-pluginLTLIBRARIES install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags uninstall \
+ uninstall-am uninstall-binPROGRAMS uninstall-libLTLIBRARIES \
+ uninstall-pkgcfgDATA uninstall-pluginLTLIBRARIES
+
+
+@LINUX_TRUE@install-exec-hook:
+@LINUX_TRUE@ $(SUDO_BINARY) chown root:root $(bindir)/gnunet-helper-transport-wlan || true
+@LINUX_TRUE@ $(SUDO_BINARY) chmod u+s $(bindir)/gnunet-helper-transport-wlan || true
+@LINUX_FALSE@install-exec-hook:
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/src/transport/gnunet-helper-transport-wlan-dummy.c b/src/transport/gnunet-helper-transport-wlan-dummy.c
new file mode 100644
index 0000000..6fff758
--- /dev/null
+++ b/src/transport/gnunet-helper-transport-wlan-dummy.c
@@ -0,0 +1,439 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+/**
+ * @file transport/gnunet-helper-transport-wlan-dummy.c
+ * @brief helper for the testcases for plugin_transport_wlan.c
+ * @author David Brodski
+ */
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_util_lib.h"
+#include "plugin_transport_wlan.h"
+
+#define FIFO_FILE1 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_in"
+#define FIFO_FILE2 "/tmp/test-transport/api-wlan-p1/WLAN_FIFO_out"
+
+#define MAXLINE 4096
+
+struct sendbuf
+{
+ unsigned int pos;
+ unsigned int size;
+ char buf[MAXLINE * 2];
+};
+
+static int first;
+
+static int closeprog;
+
+static void
+sigfunc (int sig)
+{
+ closeprog = 1;
+ (void) unlink (FIFO_FILE1);
+ (void) unlink (FIFO_FILE2);
+}
+
+
+/**
+ * function to create GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL message for plugin
+ * @param buffer pointer to buffer for the message
+ * @param mac pointer to the mac address
+ * @return number of bytes written
+ */
+static int
+send_mac_to_plugin (char *buffer, struct GNUNET_TRANSPORT_WLAN_MacAddress *mac)
+{
+
+ struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
+
+ memcpy (&macmsg.mac, (char *) mac, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
+ macmsg.hdr.size = htons (sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage));
+ macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
+
+ memcpy (buffer, &macmsg, sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage));
+ return sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage);
+}
+
+static void
+stdin_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
+{
+ struct sendbuf *write_pout = cls;
+ int sendsize;
+ struct GNUNET_MessageHeader newheader;
+ char *to_data;
+ char *to_radiotap;
+ char *to_start;
+
+ sendsize =
+ ntohs (hdr->size) - sizeof (struct Radiotap_Send) +
+ sizeof (struct Radiotap_rx);
+
+ if (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA != ntohs (hdr->type))
+ {
+ fprintf (stderr, "Function stdin_send: wrong packet type\n");
+ exit (1);
+ }
+ if ((sendsize + write_pout->size) > MAXLINE * 2)
+ {
+ fprintf (stderr, "Function stdin_send: Packet too big for buffer\n");
+ exit (1);
+ }
+
+ newheader.size = htons (sendsize);
+ newheader.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
+
+ to_start = write_pout->buf + write_pout->size;
+ memcpy (to_start, &newheader, sizeof (struct GNUNET_MessageHeader));
+ write_pout->size += sizeof (struct GNUNET_MessageHeader);
+
+ to_radiotap = to_start + sizeof (struct GNUNET_MessageHeader);
+ memset (to_radiotap, 0, sizeof (struct Radiotap_rx));
+ write_pout->size += sizeof (struct Radiotap_rx);
+
+ to_data = to_radiotap + sizeof (struct Radiotap_rx);
+ memcpy (to_data,
+ ((char *) hdr) + sizeof (struct Radiotap_Send) +
+ sizeof (struct GNUNET_MessageHeader),
+ ntohs (hdr->size) - sizeof (struct Radiotap_Send) -
+ sizeof (struct GNUNET_MessageHeader));
+ write_pout->size +=
+ ntohs (hdr->size) - sizeof (struct Radiotap_Send) -
+ sizeof (struct GNUNET_MessageHeader);
+}
+
+
+static void
+file_in_send (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
+{
+ struct sendbuf *write_std = cls;
+ uint16_t sendsize;
+
+ sendsize = ntohs (hdr->size);
+
+ if (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA != ntohs (hdr->type))
+ {
+ fprintf (stderr, "Function file_in_send: wrong packet type\n");
+ exit (1);
+ }
+ if ((sendsize + write_std->size) > MAXLINE * 2)
+ {
+ fprintf (stderr, "Function file_in_send: Packet too big for buffer\n");
+ exit (1);
+ }
+
+ memcpy (write_std->buf + write_std->size, hdr, sendsize);
+ write_std->size += sendsize;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ struct stat st;
+ int erg;
+ FILE *fpin = NULL;
+ FILE *fpout = NULL;
+ int fdpin;
+ int fdpout;
+ char readbuf[MAXLINE];
+ int readsize = 0;
+ struct sendbuf write_std;
+ struct sendbuf write_pout;
+ int ret = 0;
+ int maxfd = 0;
+ fd_set rfds;
+ fd_set wfds;
+ struct timeval tv;
+ int retval;
+ struct GNUNET_SERVER_MessageStreamTokenizer *stdin_mst;
+ struct GNUNET_SERVER_MessageStreamTokenizer *file_in_mst;
+ struct GNUNET_TRANSPORT_WLAN_MacAddress macaddr;
+
+ if (2 != argc)
+ {
+ fprintf (stderr,
+ "This program must be started with the operating mode (1 or 2) as the only argument.\n");
+ return 1;
+ }
+ if ((0 != strstr (argv[1], "1")) && (0 != strstr (argv[1], "2")))
+ return 1;
+
+ //make the fifos if needed
+ if (0 != stat (FIFO_FILE1, &st))
+ {
+ if (0 == stat (FIFO_FILE2, &st))
+ {
+ fprintf (stderr, "FIFO_FILE2 exists, but FIFO_FILE1 not\n");
+ exit (1);
+ }
+ umask (0);
+ erg = mkfifo (FIFO_FILE1, 0666);
+ if (0 != erg)
+ {
+ fprintf (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE1,
+ strerror (errno));
+ //exit(1);
+ }
+ erg = mkfifo (FIFO_FILE2, 0666);
+ if (0 != erg)
+ {
+ fprintf (stderr, "Error in mkfifo(%s): %s\n", FIFO_FILE2,
+ strerror (errno));
+ //exit(1);
+ }
+
+ }
+ else
+ {
+ if (0 != stat (FIFO_FILE2, &st))
+ {
+ fprintf (stderr, "FIFO_FILE1 exists, but FIFO_FILE2 not\n");
+ exit (1);
+ }
+ }
+
+ if (strstr (argv[1], "1"))
+ {
+ //fprintf(stderr, "First\n");
+ first = 1;
+ fpin = fopen (FIFO_FILE1, "r");
+ if (NULL == fpin)
+ {
+ fprintf (stderr, "fopen of read FIFO_FILE1\n");
+ goto end;
+ }
+ fpout = fopen (FIFO_FILE2, "w");
+ if (NULL == fpout)
+ {
+ fprintf (stderr, "fopen of write FIFO_FILE2\n");
+ goto end;
+ }
+
+ }
+ else
+ {
+ first = 0;
+ //fprintf(stderr, "Second\n");
+ fpout = fopen (FIFO_FILE1, "w");
+ if (NULL == fpout)
+ {
+ fprintf (stderr, "fopen of write FIFO_FILE1\n");
+ goto end;
+ }
+ fpin = fopen (FIFO_FILE2, "r");
+ if (NULL == fpin)
+ {
+ fprintf (stderr, "fopen of read FIFO_FILE2\n");
+ goto end;
+ }
+
+ }
+
+ fdpin = fileno (fpin);
+ GNUNET_assert (fpin >= 0);
+
+ if (fdpin >= FD_SETSIZE)
+ {
+ fprintf (stderr, "File fdpin number too large (%d > %u)\n", fdpin,
+ (unsigned int) FD_SETSIZE);
+ goto end;
+ }
+
+ fdpout = fileno (fpout);
+ GNUNET_assert (fdpout >= 0);
+
+ if (fdpout >= FD_SETSIZE)
+ {
+ fprintf (stderr, "File fdpout number too large (%d > %u)\n", fdpout,
+ (unsigned int) FD_SETSIZE);
+ goto end;
+
+ }
+
+ signal (SIGINT, &sigfunc);
+ signal (SIGTERM, &sigfunc);
+
+ write_std.size = 0;
+ write_std.pos = 0;
+ write_pout.size = 0;
+ write_pout.pos = 0;
+ stdin_mst = GNUNET_SERVER_mst_create (&stdin_send, &write_pout);
+ file_in_mst = GNUNET_SERVER_mst_create (&file_in_send, &write_std);
+
+ //Send random mac address
+ macaddr.mac[0] = 0x13;
+ macaddr.mac[1] = 0x22;
+ macaddr.mac[2] = 0x33;
+ macaddr.mac[3] = 0x44;
+ macaddr.mac[4] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 256);
+ macaddr.mac[5] = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, 256);
+ write_std.size = send_mac_to_plugin (write_std.buf, &macaddr);
+
+ while (0 == closeprog)
+ {
+ maxfd = -1;
+ //set timeout
+ tv.tv_sec = 5;
+ tv.tv_usec = 0;
+
+ FD_ZERO (&rfds);
+ // if output queue is empty
+ if (0 == write_pout.size)
+ {
+ FD_SET (STDIN_FILENO, &rfds);
+ maxfd = MAX (STDIN_FILENO, maxfd);
+ }
+ if (0 == write_std.size)
+ {
+ FD_SET (fdpin, &rfds);
+ maxfd = MAX (fdpin, maxfd);
+ }
+ FD_ZERO (&wfds);
+ // if there is something to write
+ if (0 < write_std.size)
+ {
+ FD_SET (STDOUT_FILENO, &wfds);
+ maxfd = MAX (maxfd, STDOUT_FILENO);
+ }
+ if (0 < write_pout.size)
+ {
+ FD_SET (fdpout, &wfds);
+ maxfd = MAX (maxfd, fdpout);
+ }
+
+ retval = select (maxfd + 1, &rfds, &wfds, NULL, &tv);
+ if ((-1 == retval) && (EINTR == errno))
+ continue;
+ if (0 > retval)
+ {
+ fprintf (stderr, "select failed: %s\n", strerror (errno));
+ closeprog = 1;
+ break;
+ }
+
+ if (FD_ISSET (STDOUT_FILENO, &wfds))
+ {
+ ret =
+ write (STDOUT_FILENO, write_std.buf + write_std.pos,
+ write_std.size - write_std.pos);
+ if (0 > ret)
+ {
+ closeprog = 1;
+ fprintf (stderr, "Write ERROR to STDOUT_FILENO: %s\n",
+ strerror (errno));
+ break;
+ }
+ else
+ {
+ write_std.pos += ret;
+ // check if finished
+ if (write_std.pos == write_std.size)
+ {
+ write_std.pos = 0;
+ write_std.size = 0;
+ }
+ }
+ }
+
+ if (FD_ISSET (fdpout, &wfds))
+ {
+ ret =
+ write (fdpout, write_pout.buf + write_pout.pos,
+ write_pout.size - write_pout.pos);
+
+ if (0 > ret)
+ {
+ closeprog = 1;
+ fprintf (stderr, "Write ERROR to fdpout: %s\n", strerror (errno));
+ }
+ else
+ {
+ write_pout.pos += ret;
+ // check if finished
+ if (write_pout.pos == write_pout.size)
+ {
+ write_pout.pos = 0;
+ write_pout.size = 0;
+ }
+ }
+ }
+
+ if (FD_ISSET (STDIN_FILENO, &rfds))
+ {
+ readsize = read (STDIN_FILENO, readbuf, sizeof (readbuf));
+
+ if (0 > readsize)
+ {
+ closeprog = 1;
+ fprintf (stderr, "Error reading from STDIN_FILENO: %s\n",
+ strerror (errno));
+ }
+ else if (0 < readsize)
+ {
+ GNUNET_SERVER_mst_receive (stdin_mst, NULL, readbuf, readsize,
+ GNUNET_NO, GNUNET_NO);
+
+ }
+ else
+ {
+ //eof
+ closeprog = 1;
+ }
+ }
+
+ if (FD_ISSET (fdpin, &rfds))
+ {
+ readsize = read (fdpin, readbuf, sizeof (readbuf));
+ if (0 > readsize)
+ {
+ closeprog = 1;
+ fprintf (stderr, "Error reading from fdpin: %s\n", strerror (errno));
+ break;
+ }
+ else if (0 < readsize)
+ {
+ GNUNET_SERVER_mst_receive (file_in_mst, NULL, readbuf, readsize,
+ GNUNET_NO, GNUNET_NO);
+ }
+ else
+ {
+ //eof
+ closeprog = 1;
+ }
+ }
+ }
+
+ //clean up
+ GNUNET_SERVER_mst_destroy (stdin_mst);
+ GNUNET_SERVER_mst_destroy (file_in_mst);
+
+end:
+ if (fpout != NULL)
+ fclose (fpout);
+ if (fpin != NULL)
+ fclose (fpin);
+ if (1 == first)
+ {
+ (void) unlink (FIFO_FILE1);
+ (void) unlink (FIFO_FILE2);
+ }
+ return 0;
+}
diff --git a/src/transport/gnunet-helper-transport-wlan.c b/src/transport/gnunet-helper-transport-wlan.c
new file mode 100644
index 0000000..582df7c
--- /dev/null
+++ b/src/transport/gnunet-helper-transport-wlan.c
@@ -0,0 +1,1758 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010, 2011 Christian Grothoff (and other contributing authors)
+ Copyright (c) 2007, 2008, Andy Green <andy@warmcat.com>
+ Copyright (C) 2009 Thomas d'Otreppe
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file src/transport/gnunet-helper-transport-wlan.c
+ * @brief wlan layer two server; must run as root (SUID will do)
+ * This code will work under GNU/Linux only.
+ * @author David Brodski
+ *
+ * This program serves as the mediator between the wlan interface and
+ * gnunet
+ */
+
+/*-
+ * we use our local copy of ieee80211_radiotap.h
+ *
+ * - since we can't support extensions we don't understand
+ * - since linux does not include it in userspace headers
+ *
+ * Portions of this code were taken from the ieee80211_radiotap.h header,
+ * which is
+ *
+ * Copyright (c) 2003, 2004 David Young. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of David Young may not be used to endorse or promote
+ * products derived from this software without specific prior
+ * written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY DAVID YOUNG ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL DAVID
+ * YOUNG BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
+ * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
+ * OF SUCH DAMAGE.
+ */
+
+/*
+ * Modifications to fit into the linux IEEE 802.11 stack,
+ * Mike Kershaw (dragorn@kismetwireless.net)
+ */
+
+/**
+ * parts taken from aircrack-ng, parts changend.
+ */
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/wait.h>
+#include <sys/time.h>
+#include <sys/stat.h>
+#include <netpacket/packet.h>
+#include <linux/if_ether.h>
+#include <linux/if.h>
+#include <linux/wireless.h>
+#include <netinet/in.h>
+#include <linux/if_tun.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <dirent.h>
+#include <sys/param.h>
+#include <unistd.h>
+#include <stdint.h>
+
+#include "gnunet_protocols.h"
+#include "plugin_transport_wlan.h"
+
+#define ARPHRD_IEEE80211 801
+#define ARPHRD_IEEE80211_PRISM 802
+#define ARPHRD_IEEE80211_FULL 803
+
+/**
+ * size of 802.11 address
+ */
+#define IEEE80211_ADDR_LEN 6
+
+/**
+ * Maximum size of a message allowed in either direction.
+ */
+#define MAXLINE 4096
+
+
+#define IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK 0x80000000
+
+
+/* Name Data type Units
+ * ---- --------- -----
+ *
+ * IEEE80211_RADIOTAP_TSFT __le64 microseconds
+ *
+ * Value in microseconds of the MAC's 64-bit 802.11 Time
+ * Synchronization Function timer when the first bit of the
+ * MPDU arrived at the MAC. For received frames, only.
+ *
+ * IEEE80211_RADIOTAP_CHANNEL 2 x __le16 MHz, bitmap
+ *
+ * Tx/Rx frequency in MHz, followed by flags (see below).
+ *
+ * IEEE80211_RADIOTAP_FHSS __le16 see below
+ *
+ * For frequency-hopping radios, the hop set (first byte)
+ * and pattern (second byte).
+ *
+ * IEEE80211_RADIOTAP_RATE uint8_t 500kb/s
+ *
+ * Tx/Rx data rate
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTSIGNAL s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * RF signal power at the antenna, decibel difference from
+ * one milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DBM_ANTNOISE s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * RF noise power at the antenna, decibel difference from one
+ * milliwatt.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTSIGNAL uint8_t decibel (dB)
+ *
+ * RF signal power at the antenna, decibel difference from an
+ * arbitrary, fixed reference.
+ *
+ * IEEE80211_RADIOTAP_DB_ANTNOISE uint8_t decibel (dB)
+ *
+ * RF noise power at the antenna, decibel difference from an
+ * arbitrary, fixed reference point.
+ *
+ * IEEE80211_RADIOTAP_LOCK_QUALITY __le16 unitless
+ *
+ * Quality of Barker code lock. Unitless. Monotonically
+ * nondecreasing with "better" lock strength. Called "Signal
+ * Quality" in datasheets. (Is there a standard way to measure
+ * this?)
+ *
+ * IEEE80211_RADIOTAP_TX_ATTENUATION __le16 unitless
+ *
+ * Transmit power expressed as unitless distance from max
+ * power set at factory calibration. 0 is max power.
+ * Monotonically nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DB_TX_ATTENUATION __le16 decibels (dB)
+ *
+ * Transmit power expressed as decibel distance from max power
+ * set at factory calibration. 0 is max power. Monotonically
+ * nondecreasing with lower power levels.
+ *
+ * IEEE80211_RADIOTAP_DBM_TX_POWER s8 decibels from
+ * one milliwatt (dBm)
+ *
+ * Transmit power expressed as dBm (decibels from a 1 milliwatt
+ * reference). This is the absolute power level measured at
+ * the antenna port.
+ *
+ * IEEE80211_RADIOTAP_FLAGS uint8_t bitmap
+ *
+ * Properties of transmitted and received frames. See flags
+ * defined below.
+ *
+ * IEEE80211_RADIOTAP_ANTENNA uint8_t antenna index
+ *
+ * Unitless indication of the Rx/Tx antenna for this packet.
+ * The first antenna is antenna 0.
+ *
+ * IEEE80211_RADIOTAP_RX_FLAGS __le16 bitmap
+ *
+ * Properties of received frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_TX_FLAGS __le16 bitmap
+ *
+ * Properties of transmitted frames. See flags defined below.
+ *
+ * IEEE80211_RADIOTAP_RTS_RETRIES uint8_t data
+ *
+ * Number of rts retries a transmitted frame used.
+ *
+ * IEEE80211_RADIOTAP_DATA_RETRIES uint8_t data
+ *
+ * Number of unicast retries a transmitted frame used.
+ *
+ */
+enum RadiotapType
+{
+ IEEE80211_RADIOTAP_TSFT = 0,
+ IEEE80211_RADIOTAP_FLAGS = 1,
+ IEEE80211_RADIOTAP_RATE = 2,
+ IEEE80211_RADIOTAP_CHANNEL = 3,
+ IEEE80211_RADIOTAP_FHSS = 4,
+ IEEE80211_RADIOTAP_DBM_ANTSIGNAL = 5,
+ IEEE80211_RADIOTAP_DBM_ANTNOISE = 6,
+ IEEE80211_RADIOTAP_LOCK_QUALITY = 7,
+ IEEE80211_RADIOTAP_TX_ATTENUATION = 8,
+ IEEE80211_RADIOTAP_DB_TX_ATTENUATION = 9,
+ IEEE80211_RADIOTAP_DBM_TX_POWER = 10,
+ IEEE80211_RADIOTAP_ANTENNA = 11,
+ IEEE80211_RADIOTAP_DB_ANTSIGNAL = 12,
+ IEEE80211_RADIOTAP_DB_ANTNOISE = 13,
+ IEEE80211_RADIOTAP_RX_FLAGS = 14,
+ IEEE80211_RADIOTAP_TX_FLAGS = 15,
+ IEEE80211_RADIOTAP_RTS_RETRIES = 16,
+ IEEE80211_RADIOTAP_DATA_RETRIES = 17,
+ IEEE80211_RADIOTAP_EXT = 31
+};
+
+/* For IEEE80211_RADIOTAP_FLAGS */
+#define IEEE80211_RADIOTAP_F_CFP 0x01 /* sent/received
+ * during CFP
+ */
+#define IEEE80211_RADIOTAP_F_SHORTPRE 0x02 /* sent/received
+ * with short
+ * preamble
+ */
+#define IEEE80211_RADIOTAP_F_WEP 0x04 /* sent/received
+ * with WEP encryption
+ */
+#define IEEE80211_RADIOTAP_F_FRAG 0x08 /* sent/received
+ * with fragmentation
+ */
+#define IEEE80211_RADIOTAP_F_FCS 0x10 /* frame includes FCS */
+#define IEEE80211_RADIOTAP_F_DATAPAD 0x20 /* frame has padding between
+ * 802.11 header and payload
+ * (to 32-bit boundary)
+ */
+/* For IEEE80211_RADIOTAP_RX_FLAGS */
+#define IEEE80211_RADIOTAP_F_RX_BADFCS 0x0001 /* frame failed crc check */
+
+/* For IEEE80211_RADIOTAP_TX_FLAGS */
+#define IEEE80211_RADIOTAP_F_TX_FAIL 0x0001 /* failed due to excessive
+ * retries */
+#define IEEE80211_RADIOTAP_F_TX_CTS 0x0002 /* used cts 'protection' */
+#define IEEE80211_RADIOTAP_F_TX_RTS 0x0004 /* used rts/cts handshake */
+#define IEEE80211_RADIOTAP_F_TX_NOACK 0x0008 /* frame should not be ACKed */
+#define IEEE80211_RADIOTAP_F_TX_NOSEQ 0x0010 /* sequence number handled
+ * by userspace */
+
+
+/**
+ * A generic radio capture format is desirable. There is one for
+ * Linux, but it is neither rigidly defined (there were not even
+ * units given for some fields) nor easily extensible.
+ *
+ * I suggest the following extensible radio capture format. It is
+ * based on a bitmap indicating which fields are present.
+ *
+ * I am trying to describe precisely what the application programmer
+ * should expect in the following, and for that reason I tell the
+ * units and origin of each measurement (where it applies), or else I
+ * use sufficiently weaselly language ("is a monotonically nondecreasing
+ * function of...") that I cannot set false expectations for lawyerly
+ * readers.
+ *
+ * The radio capture header precedes the 802.11 header.
+ * All data in the header is little endian on all platforms.
+ */
+struct ieee80211_radiotap_header
+{
+ /**
+ * Version 0. Only increases for drastic changes, introduction of
+ * compatible new fields does not count.
+ */
+ uint8_t it_version;
+ uint8_t it_pad;
+
+ /**
+ * length of the whole header in bytes, including it_version,
+ * it_pad, it_len, and data fields.
+ */
+ uint16_t it_len;
+
+ /**
+ * A bitmap telling which fields are present. Set bit 31
+ * (0x80000000) to extend the bitmap by another 32 bits. Additional
+ * extensions are made by setting bit 31.
+ */
+ uint32_t it_present;
+};
+
+/**
+ *
+ */
+struct RadioTapheader
+{
+ /**
+ *
+ */
+ struct ieee80211_radiotap_header header;
+
+ /**
+ *
+ */
+ uint8_t rate;
+
+ /**
+ *
+ */
+ uint8_t pad1;
+
+ /**
+ *
+ */
+ uint16_t txflags;
+};
+
+
+/**
+ * IO buffer used for buffering data in transit (to wireless or to stdout).
+ */
+struct SendBuffer
+{
+ /**
+ * How many bytes of data are stored in 'buf' for transmission right now?
+ * Data always starts at offset 0 and extends to 'size'.
+ */
+ size_t size;
+
+ /**
+ * How many bytes that were stored in 'buf' did we already write to the
+ * destination? Always smaller than 'size'.
+ */
+ size_t pos;
+
+ /**
+ * Buffered data; twice the maximum allowed message size as we add some
+ * headers.
+ */
+ char buf[MAXLINE * 2];
+};
+
+/**
+ * Buffer for data read from stdin to be transmitted to the wirless card.
+ */
+static struct SendBuffer write_pout;
+
+/**
+ * Buffer for data read from the wireless card to be transmitted to stdout.
+ */
+static struct SendBuffer write_std;
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * generic definitions for IEEE 802.11 frames
+ */
+struct ieee80211_frame
+{
+ uint8_t i_fc[2];
+ uint8_t i_dur[2];
+ uint8_t i_addr1[IEEE80211_ADDR_LEN];
+ uint8_t i_addr2[IEEE80211_ADDR_LEN];
+ uint8_t i_addr3[IEEE80211_ADDR_LEN];
+ uint8_t i_seq[2];
+ /* possibly followed by addr4[IEEE80211_ADDR_LEN]; */
+ /* see below */
+} GNUNET_PACKED;
+GNUNET_NETWORK_STRUCT_END
+
+
+/**
+ * struct for storing the information of the hardware
+ */
+struct HardwareInfos
+{
+
+ /**
+ * file descriptor for the raw socket
+ */
+ int fd_raw;
+
+ /**
+ * Which format has the header that we're getting when receiving packets?
+ * Some ARPHRD_IEEE80211_XXX-value.
+ */
+ int arptype_in;
+
+ /**
+ * Name of the interface, not necessarily 0-terminated (!).
+ */
+ char iface[IFNAMSIZ];
+
+ /**
+ * MAC address of our own WLAN interface.
+ */
+ struct GNUNET_TRANSPORT_WLAN_MacAddress pl_mac;
+};
+
+
+/**
+ * struct ieee80211_radiotap_iterator - tracks walk through present radiotap arguments
+ * in the radiotap header.
+ */
+struct ieee80211_radiotap_iterator
+{
+ /**
+ * pointer to the radiotap header we are walking through
+ */
+ const struct ieee80211_radiotap_header *rtheader;
+
+ /**
+ * length of radiotap header in cpu byte ordering
+ */
+ size_t max_length;
+
+ /**
+ * IEEE80211_RADIOTAP_... index of current arg
+ */
+ unsigned int this_arg_index;
+
+ /**
+ * pointer to current radiotap arg
+ */
+ uint8_t *this_arg;
+
+ /**
+ * internal next argument index
+ */
+ unsigned int arg_index;
+
+ /**
+ * internal next argument pointer
+ */
+ uint8_t *arg;
+
+ /**
+ * internal pointer to next present uint32_t
+ */
+ uint32_t *next_bitmap;
+
+ /**
+ * internal shifter for curr uint32_t bitmap, b0 set == arg present
+ */
+ uint32_t bitmap_shifter;
+};
+
+
+
+/* specialized version of server_mst.c begins here */
+
+#define ALIGN_FACTOR 8
+
+/**
+ * Smallest supported message.
+ */
+#define MIN_BUFFER_SIZE sizeof (struct GNUNET_MessageHeader)
+
+
+/**
+ * Functions with this signature are called whenever a
+ * complete message is received by the tokenizer.
+ *
+ * @param cls closure
+ * @param message the actual message
+ */
+typedef void (*MessageTokenizerCallback) (void *cls,
+ const struct
+ GNUNET_MessageHeader *
+ message);
+
+/**
+ * Handle to a message stream tokenizer.
+ */
+struct MessageStreamTokenizer
+{
+
+ /**
+ * Function to call on completed messages.
+ */
+ MessageTokenizerCallback cb;
+
+ /**
+ * Closure for cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Size of the buffer (starting at 'hdr').
+ */
+ size_t curr_buf;
+
+ /**
+ * How many bytes in buffer have we already processed?
+ */
+ size_t off;
+
+ /**
+ * How many bytes in buffer are valid right now?
+ */
+ size_t pos;
+
+ /**
+ * Beginning of the buffer. Typed like this to force alignment.
+ */
+ struct GNUNET_MessageHeader *hdr;
+
+};
+
+
+
+/**
+ * Create a message stream tokenizer.
+ *
+ * @param cb function to call on completed messages
+ * @param cb_cls closure for cb
+ * @return handle to tokenizer
+ */
+static struct MessageStreamTokenizer *
+mst_create (MessageTokenizerCallback cb,
+ void *cb_cls)
+{
+ struct MessageStreamTokenizer *ret;
+
+ ret = malloc (sizeof (struct MessageStreamTokenizer));
+ if (NULL == ret)
+ exit (1);
+ ret->hdr = malloc (MIN_BUFFER_SIZE);
+ if (NULL == ret->hdr)
+ exit (2);
+ ret->curr_buf = MIN_BUFFER_SIZE;
+ ret->cb = cb;
+ ret->cb_cls = cb_cls;
+ return ret;
+}
+
+
+/**
+ * Add incoming data to the receive buffer and call the
+ * callback for all complete messages.
+ *
+ * @param mst tokenizer to use
+ * @param buf input data to add
+ * @param size number of bytes in buf
+ * @return GNUNET_OK if we are done processing (need more data)
+ * GNUNET_SYSERR if the data stream is corrupt
+ */
+static int
+mst_receive (struct MessageStreamTokenizer *mst,
+ const char *buf, size_t size)
+{
+ const struct GNUNET_MessageHeader *hdr;
+ size_t delta;
+ uint16_t want;
+ char *ibuf;
+ int need_align;
+ unsigned long offset;
+ int ret;
+
+ ret = GNUNET_OK;
+ ibuf = (char *) mst->hdr;
+ while (mst->pos > 0)
+ {
+do_align:
+ if ((mst->curr_buf - mst->off < sizeof (struct GNUNET_MessageHeader)) ||
+ (0 != (mst->off % ALIGN_FACTOR)))
+ {
+ /* need to align or need more space */
+ mst->pos -= mst->off;
+ memmove (ibuf, &ibuf[mst->off], mst->pos);
+ mst->off = 0;
+ }
+ if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
+ {
+ delta =
+ GNUNET_MIN (sizeof (struct GNUNET_MessageHeader) -
+ (mst->pos - mst->off), size);
+ memcpy (&ibuf[mst->pos], buf, delta);
+ mst->pos += delta;
+ buf += delta;
+ size -= delta;
+ }
+ if (mst->pos - mst->off < sizeof (struct GNUNET_MessageHeader))
+ {
+ return GNUNET_OK;
+ }
+ hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
+ want = ntohs (hdr->size);
+ if (want < sizeof (struct GNUNET_MessageHeader))
+ {
+ // GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (mst->curr_buf - mst->off < want)
+ {
+ /* need more space */
+ mst->pos -= mst->off;
+ memmove (ibuf, &ibuf[mst->off], mst->pos);
+ mst->off = 0;
+ }
+ if (want > mst->curr_buf)
+ {
+ mst->hdr = realloc (mst->hdr, want);
+ if (NULL == mst->hdr)
+ exit (3);
+ ibuf = (char *) mst->hdr;
+ mst->curr_buf = want;
+ }
+ hdr = (const struct GNUNET_MessageHeader *) &ibuf[mst->off];
+ if (mst->pos - mst->off < want)
+ {
+ delta = GNUNET_MIN (want - (mst->pos - mst->off), size);
+ memcpy (&ibuf[mst->pos], buf, delta);
+ mst->pos += delta;
+ buf += delta;
+ size -= delta;
+ }
+ if (mst->pos - mst->off < want)
+ {
+ return GNUNET_OK;
+ }
+ mst->cb (mst->cb_cls, hdr);
+ mst->off += want;
+ if (mst->off == mst->pos)
+ {
+ /* reset to beginning of buffer, it's free right now! */
+ mst->off = 0;
+ mst->pos = 0;
+ }
+ }
+ while (size > 0)
+ {
+ if (size < sizeof (struct GNUNET_MessageHeader))
+ break;
+ offset = (unsigned long) buf;
+ need_align = (0 != offset % ALIGN_FACTOR) ? GNUNET_YES : GNUNET_NO;
+ if (GNUNET_NO == need_align)
+ {
+ /* can try to do zero-copy and process directly from original buffer */
+ hdr = (const struct GNUNET_MessageHeader *) buf;
+ want = ntohs (hdr->size);
+ if (want < sizeof (struct GNUNET_MessageHeader))
+ {
+ // GNUNET_break_op (0);
+ mst->off = 0;
+ return GNUNET_SYSERR;
+ }
+ if (size < want)
+ break; /* or not, buffer incomplete, so copy to private buffer... */
+ mst->cb (mst->cb_cls, hdr);
+ buf += want;
+ size -= want;
+ }
+ else
+ {
+ /* need to copy to private buffer to align;
+ * yes, we go a bit more spagetti than usual here */
+ goto do_align;
+ }
+ }
+ if (size > 0)
+ {
+ if (size + mst->pos > mst->curr_buf)
+ {
+ mst->hdr = realloc (mst->hdr, size + mst->pos);
+ if (NULL == mst->hdr)
+ exit (4);
+ ibuf = (char *) mst->hdr;
+ mst->curr_buf = size + mst->pos;
+ }
+ // GNUNET_assert (mst->pos + size <= mst->curr_buf);
+ memcpy (&ibuf[mst->pos], buf, size);
+ mst->pos += size;
+ }
+ return ret;
+}
+
+
+/**
+ * Destroys a tokenizer.
+ *
+ * @param mst tokenizer to destroy
+ */
+static void
+mst_destroy (struct MessageStreamTokenizer *mst)
+{
+ free (mst->hdr);
+ free (mst);
+}
+
+/* end of server_mst.c copy */
+
+
+
+
+/**
+ * Radiotap header iteration
+ *
+ * call __ieee80211_radiotap_iterator_init() to init a semi-opaque iterator
+ * struct ieee80211_radiotap_iterator (no need to init the struct beforehand)
+ * then loop calling __ieee80211_radiotap_iterator_next()... it returns -1
+ * if there are no more args in the header, or the next argument type index
+ * that is present. The iterator's this_arg member points to the start of the
+ * argument associated with the current argument index that is present,
+ * which can be found in the iterator's this_arg_index member. This arg
+ * index corresponds to the IEEE80211_RADIOTAP_... defines.
+ *
+ * @param iterator iterator to initialize
+ * @param radiotap_header message to parse
+ * @param max_length number of valid bytes in radiotap_header
+ * @return 0 on success, -1 on error
+ */
+static int
+ieee80211_radiotap_iterator_init (struct ieee80211_radiotap_iterator *iterator,
+ const struct ieee80211_radiotap_header
+ *radiotap_header,
+ size_t max_length)
+{
+ if ( (iterator == NULL) ||
+ (radiotap_header == NULL) )
+ return -1;
+
+ /* Linux only supports version 0 radiotap format */
+ if (0 != radiotap_header->it_version)
+ return -1;
+
+ /* sanity check for allowed length and radiotap length field */
+ if ( (max_length < sizeof (struct ieee80211_radiotap_header)) ||
+ (max_length < (GNUNET_le16toh (radiotap_header->it_len))) )
+ return -1;
+
+ iterator->rtheader = radiotap_header;
+ iterator->max_length = GNUNET_le16toh (radiotap_header->it_len);
+ iterator->arg_index = 0;
+ iterator->bitmap_shifter = GNUNET_le32toh (radiotap_header->it_present);
+ iterator->arg =
+ ((uint8_t *) radiotap_header) + sizeof (struct ieee80211_radiotap_header);
+ iterator->this_arg = 0;
+
+ /* find payload start allowing for extended bitmap(s) */
+ if ((iterator->bitmap_shifter & IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK))
+ {
+ while (GNUNET_le32toh (*((uint32_t *) iterator->arg)) &
+ IEEE80211_RADIOTAP_PRESENT_EXTEND_MASK)
+ {
+ iterator->arg += sizeof (uint32_t);
+
+ /*
+ * check for insanity where the present bitmaps
+ * keep claiming to extend up to or even beyond the
+ * stated radiotap header length
+ */
+ if (iterator->arg - ((uint8_t*) iterator->rtheader) > iterator->max_length)
+ return -1;
+ }
+ iterator->arg += sizeof (uint32_t);
+ /*
+ * no need to check again for blowing past stated radiotap
+ * header length, becuase ieee80211_radiotap_iterator_next
+ * checks it before it is dereferenced
+ */
+ }
+ /* we are all initialized happily */
+ return 0;
+}
+
+
+/**
+ * @brief ieee80211_radiotap_iterator_next - return next radiotap parser iterator arg
+ *
+ * This function returns the next radiotap arg index (IEEE80211_RADIOTAP_...)
+ * and sets iterator->this_arg to point to the payload for the arg. It takes
+ * care of alignment handling and extended present fields. interator->this_arg
+ * can be changed by the caller. The args pointed to are in little-endian
+ * format.
+ *
+ * @param iterator: radiotap_iterator to move to next arg (if any)
+ *
+ * @return next present arg index on success or -1 if no more or error
+ */
+static int
+ieee80211_radiotap_iterator_next (struct ieee80211_radiotap_iterator *iterator)
+{
+
+ /*
+ * small length lookup table for all radiotap types we heard of
+ * starting from b0 in the bitmap, so we can walk the payload
+ * area of the radiotap header
+ *
+ * There is a requirement to pad args, so that args
+ * of a given length must begin at a boundary of that length
+ * -- but note that compound args are allowed (eg, 2 x uint16_t
+ * for IEEE80211_RADIOTAP_CHANNEL) so total arg length is not
+ * a reliable indicator of alignment requirement.
+ *
+ * upper nybble: content alignment for arg
+ * lower nybble: content length for arg
+ */
+
+ static const uint8_t rt_sizes[] = {
+ [IEEE80211_RADIOTAP_TSFT] = 0x88,
+ [IEEE80211_RADIOTAP_FLAGS] = 0x11,
+ [IEEE80211_RADIOTAP_RATE] = 0x11,
+ [IEEE80211_RADIOTAP_CHANNEL] = 0x24,
+ [IEEE80211_RADIOTAP_FHSS] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DBM_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_LOCK_QUALITY] = 0x22,
+ [IEEE80211_RADIOTAP_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DB_TX_ATTENUATION] = 0x22,
+ [IEEE80211_RADIOTAP_DBM_TX_POWER] = 0x11,
+ [IEEE80211_RADIOTAP_ANTENNA] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTSIGNAL] = 0x11,
+ [IEEE80211_RADIOTAP_DB_ANTNOISE] = 0x11,
+ [IEEE80211_RADIOTAP_TX_FLAGS] = 0x22,
+ [IEEE80211_RADIOTAP_RX_FLAGS] = 0x22,
+ [IEEE80211_RADIOTAP_RTS_RETRIES] = 0x11,
+ [IEEE80211_RADIOTAP_DATA_RETRIES] = 0x11
+ /*
+ * add more here as they are defined in
+ * include/net/ieee80211_radiotap.h
+ */
+ };
+
+ /*
+ * for every radiotap entry we can at
+ * least skip (by knowing the length)...
+ */
+
+ while (iterator->arg_index < sizeof (rt_sizes))
+ {
+ int hit = 0;
+
+ if (!(iterator->bitmap_shifter & 1))
+ goto next_entry; /* arg not present */
+
+ /*
+ * arg is present, account for alignment padding
+ * 8-bit args can be at any alignment
+ * 16-bit args must start on 16-bit boundary
+ * 32-bit args must start on 32-bit boundary
+ * 64-bit args must start on 64-bit boundary
+ *
+ * note that total arg size can differ from alignment of
+ * elements inside arg, so we use upper nybble of length
+ * table to base alignment on
+ *
+ * also note: these alignments are ** relative to the
+ * start of the radiotap header **. There is no guarantee
+ * that the radiotap header itself is aligned on any
+ * kind of boundary.
+ */
+
+ if ((((void *) iterator->arg) -
+ ((void *) iterator->rtheader)) & ((rt_sizes[iterator->arg_index] >> 4)
+ - 1))
+ iterator->arg_index +=
+ (rt_sizes[iterator->arg_index] >> 4) -
+ ((((void *) iterator->arg) -
+ ((void *) iterator->rtheader)) & ((rt_sizes[iterator->arg_index] >>
+ 4) - 1));
+
+ /*
+ * this is what we will return to user, but we need to
+ * move on first so next call has something fresh to test
+ */
+
+ iterator->this_arg_index = iterator->arg_index;
+ iterator->this_arg = iterator->arg;
+ hit = 1;
+
+ /* internally move on the size of this arg */
+
+ iterator->arg += rt_sizes[iterator->arg_index] & 0x0f;
+
+ /*
+ * check for insanity where we are given a bitmap that
+ * claims to have more arg content than the length of the
+ * radiotap section. We will normally end up equalling this
+ * max_length on the last arg, never exceeding it.
+ */
+
+ if ((((void *) iterator->arg) - ((void *) iterator->rtheader)) >
+ iterator->max_length)
+ return -1;
+
+next_entry:
+
+ iterator->arg_index++;
+ if (((iterator->arg_index & 31) == 0))
+ {
+ /* completed current uint32_t bitmap */
+ if (iterator->bitmap_shifter & 1)
+ {
+ /* b31 was set, there is more */
+ /* move to next uint32_t bitmap */
+ iterator->bitmap_shifter = GNUNET_le32toh (*iterator->next_bitmap);
+ iterator->next_bitmap++;
+ }
+ else
+ {
+ /* no more bitmaps: end */
+ iterator->arg_index = sizeof (rt_sizes);
+ }
+ }
+ else
+ { /* just try the next bit */
+ iterator->bitmap_shifter >>= 1;
+ }
+
+ /* if we found a valid arg earlier, return it now */
+
+ if (hit)
+ return iterator->this_arg_index;
+
+ }
+
+ /* we don't know how to handle any more args, we're done */
+ return -1;
+}
+
+
+/**
+ * Return the channel from the frequency (in Mhz)
+ * @param frequency of the channel
+ * @return number of the channel
+ */
+static int
+get_channel_from_frequency (int frequency)
+{
+ if (frequency >= 2412 && frequency <= 2472)
+ return (frequency - 2407) / 5;
+ if (frequency == 2484)
+ return 14;
+ if (frequency >= 5000 && frequency <= 6100)
+ return (frequency - 5000) / 5;
+ return -1;
+}
+
+
+/**
+ * function to calculate the crc, the start of the calculation
+ *
+ * @param buf buffer to calc the crc
+ * @param len len of the buffer
+ * @return crc sum
+ */
+static unsigned long
+calc_crc_osdep (const unsigned char *buf, size_t len)
+{
+ static const unsigned long int crc_tbl_osdep[256] = {
+ 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F,
+ 0xE963A535, 0x9E6495A3,
+ 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
+ 0xE7B82D07, 0x90BF1D91,
+ 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D, 0x6DDDE4EB,
+ 0xF4D4B551, 0x83D385C7,
+ 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
+ 0xFA0F3D63, 0x8D080DF5,
+ 0x3B6E20C8, 0x4C69105E, 0xD56041E4, 0xA2677172, 0x3C03E4D1, 0x4B04D447,
+ 0xD20D85FD, 0xA50AB56B,
+ 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75,
+ 0xDCD60DCF, 0xABD13D59,
+ 0x26D930AC, 0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423,
+ 0xCFBA9599, 0xB8BDA50F,
+ 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11,
+ 0xC1611DAB, 0xB6662D3D,
+ 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
+ 0x9FBFE4A5, 0xE8B8D433,
+ 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D,
+ 0x91646C97, 0xE6635C01,
+ 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, 0x1B01A57B,
+ 0x8208F4C1, 0xF50FC457,
+ 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49,
+ 0x8CD37CF3, 0xFBD44C65,
+ 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7,
+ 0xA4D1C46D, 0xD3D6F4FB,
+ 0x4369E96A, 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
+ 0xAA0A4C5F, 0xDD0D7CC9,
+ 0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3,
+ 0xB966D409, 0xCE61E49F,
+ 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+ 0xB7BD5C3B, 0xC0BA6CAD,
+ 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF,
+ 0x04DB2615, 0x73DC1683,
+ 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, 0xE40ECF0B, 0x9309FF9D,
+ 0x0A00AE27, 0x7D079EB1,
+ 0xF00F9344, 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
+ 0x196C3671, 0x6E6B06E7,
+ 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9,
+ 0x17B7BE43, 0x60B08ED5,
+ 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767,
+ 0x3FB506DD, 0x48B2364B,
+ 0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55,
+ 0x316E8EEF, 0x4669BE79,
+ 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
+ 0x220216B9, 0x5505262F,
+ 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
+ 0x2CD99E8B, 0x5BDEAE1D,
+ 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A, 0x9C0906A9, 0xEB0E363F,
+ 0x72076785, 0x05005713,
+ 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D,
+ 0x7CDCEFB7, 0x0BDBDF21,
+ 0x86D3D2D4, 0xF1D4E242, 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B,
+ 0x6FB077E1, 0x18B74777,
+ 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69,
+ 0x616BFFD3, 0x166CCF45,
+ 0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
+ 0x4969474D, 0x3E6E77DB,
+ 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
+ 0x47B2CF7F, 0x30B5FFE9,
+ 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, 0xCDD70693,
+ 0x54DE5729, 0x23D967BF,
+ 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1,
+ 0x5A05DF1B, 0x2D02EF8D
+ };
+
+ unsigned long crc = 0xFFFFFFFF;
+
+ for (; len > 0; len--, buf++)
+ crc = crc_tbl_osdep[(crc ^ *buf) & 0xFF] ^ (crc >> 8);
+ return (~crc);
+}
+
+
+/**
+ * Function to calculate and check crc of the wlan packet
+ *
+ * @param buf buffer of the packet, with len + 4 bytes of data,
+ * the last 4 bytes being the checksum
+ * @param len length of the payload in data
+ * @return 0 on success (checksum matches), 1 on error
+ */
+static int
+check_crc_buf_osdep (const unsigned char *buf, size_t len)
+{
+ unsigned long crc;
+
+ crc = calc_crc_osdep (buf, len);
+ buf += len;
+ if (((crc) & 0xFF) == buf[0] && ((crc >> 8) & 0xFF) == buf[1] &&
+ ((crc >> 16) & 0xFF) == buf[2] && ((crc >> 24) & 0xFF) == buf[3])
+ return 0;
+ return 1;
+}
+
+
+/**
+ * Get the channel used by our WLAN interface.
+ *
+ * @param dev pointer to the dev struct of the card
+ * @return channel number, -1 on error
+ */
+static int
+linux_get_channel (const struct HardwareInfos *dev)
+{
+ struct iwreq wrq;
+ int fd;
+ int frequency;
+ int chan;
+
+ memset (&wrq, 0, sizeof (struct iwreq));
+ strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ);
+ fd = dev->fd_raw;
+ if (0 > ioctl (fd, SIOCGIWFREQ, &wrq))
+ return -1;
+
+ frequency = wrq.u.freq.m;
+ if (100000000 < frequency)
+ frequency /= 100000;
+ else if (1000000 < frequency)
+ frequency /= 1000;
+ if (1000 < frequency)
+ chan = get_channel_from_frequency (frequency);
+ else
+ chan = frequency;
+ return chan;
+}
+
+
+/**
+ * function to read from a wlan card
+ * @param dev pointer to the struct of the wlan card
+ * @param buf buffer to read to
+ * @param buf_size size of the buffer
+ * @param ri radiotap_rx info
+ * @return size read from the buffer
+ */
+static ssize_t
+linux_read (struct HardwareInfos *dev, unsigned char *buf, size_t buf_size,
+ struct Radiotap_rx *ri)
+{
+ unsigned char tmpbuf[buf_size];
+ ssize_t caplen;
+ int n, got_signal, got_noise, got_channel, fcs_removed;
+
+ n = got_signal = got_noise = got_channel = fcs_removed = 0;
+
+ caplen = read (dev->fd_raw, tmpbuf, buf_size);
+ if (0 > caplen)
+ {
+ if (EAGAIN == errno)
+ return 0;
+ fprintf (stderr, "Failed to read from RAW socket: %s\n", strerror (errno));
+ return -1;
+ }
+
+ memset (buf, 0, buf_size);
+ memset (ri, 0, sizeof (*ri));
+
+ switch (dev->arptype_in)
+ {
+ case ARPHRD_IEEE80211_PRISM:
+ {
+ /* skip the prism header */
+ if (tmpbuf[7] == 0x40)
+ {
+ /* prism54 uses a different format */
+ ri->ri_power = tmpbuf[0x33];
+ ri->ri_noise = *(unsigned int *) (tmpbuf + 0x33 + 12);
+ ri->ri_rate = (*(unsigned int *) (tmpbuf + 0x33 + 24)) * 500000;
+ got_signal = 1;
+ got_noise = 1;
+ n = 0x40;
+ }
+ else
+ {
+ ri->ri_mactime = *(uint64_t *) (tmpbuf + 0x5C - 48);
+ ri->ri_channel = *(unsigned int *) (tmpbuf + 0x5C - 36);
+ ri->ri_power = *(unsigned int *) (tmpbuf + 0x5C);
+ ri->ri_noise = *(unsigned int *) (tmpbuf + 0x5C + 12);
+ ri->ri_rate = (*(unsigned int *) (tmpbuf + 0x5C + 24)) * 500000;
+ got_channel = 1;
+ got_signal = 1;
+ got_noise = 1;
+ n = *(int *) (tmpbuf + 4);
+ }
+
+ if ( (n < 8) || (n >= caplen) )
+ return 0;
+ }
+ break;
+
+ case ARPHRD_IEEE80211_FULL:
+ {
+ struct ieee80211_radiotap_iterator iterator;
+ struct ieee80211_radiotap_header *rthdr;
+
+ rthdr = (struct ieee80211_radiotap_header *) tmpbuf;
+
+ if (0 != ieee80211_radiotap_iterator_init (&iterator, rthdr, caplen))
+ return 0;
+
+ /* go through the radiotap arguments we have been given
+ * by the driver
+ */
+
+ while (ieee80211_radiotap_iterator_next (&iterator) >= 0)
+ {
+
+ switch (iterator.this_arg_index)
+ {
+
+ case IEEE80211_RADIOTAP_TSFT:
+ ri->ri_mactime = GNUNET_le64toh (*((uint64_t *) iterator.this_arg));
+ break;
+
+ case IEEE80211_RADIOTAP_DBM_ANTSIGNAL:
+ if (!got_signal)
+ {
+ if (*iterator.this_arg < 127)
+ ri->ri_power = *iterator.this_arg;
+ else
+ ri->ri_power = *iterator.this_arg - 255;
+
+ got_signal = 1;
+ }
+ break;
+
+ case IEEE80211_RADIOTAP_DB_ANTSIGNAL:
+ if (!got_signal)
+ {
+ if (*iterator.this_arg < 127)
+ ri->ri_power = *iterator.this_arg;
+ else
+ ri->ri_power = *iterator.this_arg - 255;
+
+ got_signal = 1;
+ }
+ break;
+
+ case IEEE80211_RADIOTAP_DBM_ANTNOISE:
+ if (!got_noise)
+ {
+ if (*iterator.this_arg < 127)
+ ri->ri_noise = *iterator.this_arg;
+ else
+ ri->ri_noise = *iterator.this_arg - 255;
+
+ got_noise = 1;
+ }
+ break;
+
+ case IEEE80211_RADIOTAP_DB_ANTNOISE:
+ if (!got_noise)
+ {
+ if (*iterator.this_arg < 127)
+ ri->ri_noise = *iterator.this_arg;
+ else
+ ri->ri_noise = *iterator.this_arg - 255;
+
+ got_noise = 1;
+ }
+ break;
+
+ case IEEE80211_RADIOTAP_ANTENNA:
+ ri->ri_antenna = *iterator.this_arg;
+ break;
+
+ case IEEE80211_RADIOTAP_CHANNEL:
+ ri->ri_channel = *iterator.this_arg;
+ got_channel = 1;
+ break;
+
+ case IEEE80211_RADIOTAP_RATE:
+ ri->ri_rate = (*iterator.this_arg) * 500000;
+ break;
+
+ case IEEE80211_RADIOTAP_FLAGS:
+ /* is the CRC visible at the end?
+ * remove
+ */
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_FCS)
+ {
+ fcs_removed = 1;
+ caplen -= 4;
+ }
+
+ if (*iterator.this_arg & IEEE80211_RADIOTAP_F_RX_BADFCS)
+ return (0);
+
+ break;
+ }
+ }
+ n = GNUNET_le16toh (rthdr->it_len);
+ if (n <= 0 || n >= caplen)
+ return 0;
+ }
+ break;
+ case ARPHRD_IEEE80211:
+ /* do nothing? */
+ break;
+ default:
+ errno = ENOTSUP;
+ return -1;
+ }
+
+ caplen -= n;
+
+ //detect fcs at the end, even if the flag wasn't set and remove it
+ if ((0 == fcs_removed) && (0 == check_crc_buf_osdep (tmpbuf + n, caplen - 4)))
+ {
+ caplen -= 4;
+ }
+ memcpy (buf, tmpbuf + n, caplen);
+ if (!got_channel)
+ ri->ri_channel = linux_get_channel (dev);
+
+ return caplen;
+}
+
+
+/**
+ * Open the wireless network interface for reading/writing.
+ *
+ * @param dev pointer to the device struct
+ * @return 0 on success
+ */
+static int
+open_device_raw (struct HardwareInfos *dev)
+{
+ struct ifreq ifr;
+ struct iwreq wrq;
+ struct packet_mreq mr;
+ struct sockaddr_ll sll;
+
+ /* find the interface index */
+ memset (&ifr, 0, sizeof (ifr));
+ strncpy (ifr.ifr_name, dev->iface, IFNAMSIZ);
+ if (-1 == ioctl (dev->fd_raw, SIOCGIFINDEX, &ifr))
+ {
+ fprintf (stderr, "ioctl(SIOCGIFINDEX) on interface `%.*s' failed: %s\n",
+ IFNAMSIZ, dev->iface, strerror (errno));
+ return 1;
+ }
+
+ /* lookup the hardware type */
+ memset (&sll, 0, sizeof (sll));
+ sll.sll_family = AF_PACKET;
+ sll.sll_ifindex = ifr.ifr_ifindex;
+ sll.sll_protocol = htons (ETH_P_ALL);
+ if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr))
+ {
+ fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n",
+ IFNAMSIZ, dev->iface, strerror (errno));
+ return 1;
+ }
+
+ /* lookup iw mode */
+ memset (&wrq, 0, sizeof (struct iwreq));
+ strncpy (wrq.ifr_name, dev->iface, IFNAMSIZ);
+ if (-1 == ioctl (dev->fd_raw, SIOCGIWMODE, &wrq))
+ {
+ /* most probably not supported (ie for rtap ipw interface) *
+ * so just assume its correctly set... */
+ wrq.u.mode = IW_MODE_MONITOR;
+ }
+
+ if (((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
+ (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
+ (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL)) ||
+ (wrq.u.mode != IW_MODE_MONITOR))
+ {
+ fprintf (stderr, "Error: interface `%.*s' is not in monitor mode\n",
+ IFNAMSIZ, dev->iface);
+ return 1;
+ }
+
+ /* Is interface st to up, broadcast & running ? */
+ if ((ifr.ifr_flags | IFF_UP | IFF_BROADCAST | IFF_RUNNING) != ifr.ifr_flags)
+ {
+ /* Bring interface up */
+ ifr.ifr_flags |= IFF_UP | IFF_BROADCAST | IFF_RUNNING;
+
+ if (-1 == ioctl (dev->fd_raw, SIOCSIFFLAGS, &ifr))
+ {
+ fprintf (stderr, "ioctl(SIOCSIFFLAGS) on interface `%.*s' failed: %s\n",
+ IFNAMSIZ, dev->iface, strerror (errno));
+ return 1;
+ }
+ }
+
+ /* bind the raw socket to the interface */
+ if (-1 == bind (dev->fd_raw, (struct sockaddr *) &sll, sizeof (sll)))
+ {
+ fprintf (stderr, "Failed to bind interface `%.*s': %s\n", IFNAMSIZ,
+ dev->iface, strerror (errno));
+ return 1;
+ }
+
+ /* lookup the hardware type */
+ if (-1 == ioctl (dev->fd_raw, SIOCGIFHWADDR, &ifr))
+ {
+ fprintf (stderr, "ioctl(SIOCGIFHWADDR) on interface `%.*s' failed: %s\n",
+ IFNAMSIZ, dev->iface, strerror (errno));
+ return 1;
+ }
+
+ memcpy (&dev->pl_mac, ifr.ifr_hwaddr.sa_data, MAC_ADDR_SIZE);
+ dev->arptype_in = ifr.ifr_hwaddr.sa_family;
+ if ((ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211) &&
+ (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_PRISM) &&
+ (ifr.ifr_hwaddr.sa_family != ARPHRD_IEEE80211_FULL))
+ {
+ fprintf (stderr, "Unsupported hardware link type %d on interface `%.*s'\n",
+ ifr.ifr_hwaddr.sa_family, IFNAMSIZ, dev->iface);
+ return 1;
+ }
+
+ /* enable promiscuous mode */
+ memset (&mr, 0, sizeof (mr));
+ mr.mr_ifindex = sll.sll_ifindex;
+ mr.mr_type = PACKET_MR_PROMISC;
+ if (0 !=
+ setsockopt (dev->fd_raw, SOL_PACKET, PACKET_ADD_MEMBERSHIP, &mr,
+ sizeof (mr)))
+ {
+ fprintf (stderr, "Failed to enable promiscuous mode on interface `%.*s'\n",
+ IFNAMSIZ, dev->iface);
+ return 1;
+ }
+
+ return 0;
+}
+
+
+/**
+ * Test if the given interface name really corresponds to a wireless
+ * device.
+ *
+ * @param iface name of the interface
+ * @return 0 on success, 1 on error
+ */
+static int
+test_wlan_interface (const char *iface)
+{
+ char strbuf[512];
+ struct stat sbuf;
+ int ret;
+
+ /* mac80211 stack detection */
+ ret =
+ snprintf (strbuf, sizeof (strbuf), "/sys/class/net/%s/phy80211/subsystem",
+ iface);
+ if ((ret < 0) || (ret >= sizeof (strbuf)) || (0 != stat (strbuf, &sbuf)))
+ {
+ fprintf (stderr, "Did not find 802.11 interface `%s'. Exiting.\n", iface);
+ return 1;
+ }
+ return 0;
+}
+
+
+/**
+ * Function to test incoming packets mac for being our own.
+ *
+ * @param uint8_taIeeeHeader buffer of the packet
+ * @param dev the Hardware_Infos struct
+ * @return 0 if mac belongs to us, 1 if mac is for another target
+ */
+static int
+mac_test (const struct ieee80211_frame *uint8_taIeeeHeader,
+ const struct HardwareInfos *dev)
+{
+ if (0 != memcmp (uint8_taIeeeHeader->i_addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE))
+ return 1;
+ if (0 == memcmp (uint8_taIeeeHeader->i_addr1, &dev->pl_mac, MAC_ADDR_SIZE))
+ return 0;
+ if (0 == memcmp (uint8_taIeeeHeader->i_addr1, &bc_all_mac, MAC_ADDR_SIZE))
+ return 0;
+ return 1;
+}
+
+
+/**
+ * function to set the wlan header to make attacks more difficult
+ * @param uint8_taIeeeHeader pointer to the header of the packet
+ * @param dev pointer to the Hardware_Infos struct
+ */
+static void
+mac_set (struct ieee80211_frame *uint8_taIeeeHeader,
+ const struct HardwareInfos *dev)
+{
+ uint8_taIeeeHeader->i_fc[0] = 0x08;
+ uint8_taIeeeHeader->i_fc[1] = 0x00;
+ memcpy (uint8_taIeeeHeader->i_addr2, &dev->pl_mac, MAC_ADDR_SIZE);
+ memcpy (uint8_taIeeeHeader->i_addr3, &mac_bssid_gnunet, MAC_ADDR_SIZE);
+}
+
+
+/**
+ * function to process the data from the stdin
+ * @param cls pointer to the device struct
+ * @param hdr pointer to the start of the packet
+ */
+static void
+stdin_send_hw (void *cls, const struct GNUNET_MessageHeader *hdr)
+{
+ struct HardwareInfos *dev = cls;
+ struct Radiotap_Send *header = (struct Radiotap_Send *) &hdr[1];
+ struct ieee80211_frame *wlanheader;
+ size_t sendsize;
+ struct RadioTapheader rtheader;
+
+ rtheader.header.it_version = 0; /* radiotap version */
+ rtheader.header.it_len = GNUNET_htole16 (0x0c); /* radiotap header length */
+ rtheader.header.it_present = GNUNET_le16toh (0x00008004); /* our bitmap */
+ rtheader.rate = 0x00;
+ rtheader.pad1 = 0x00;
+ rtheader.txflags =
+ GNUNET_htole16 (IEEE80211_RADIOTAP_F_TX_NOACK | IEEE80211_RADIOTAP_F_TX_NOSEQ);
+
+ sendsize = ntohs (hdr->size);
+ if (sendsize <
+ sizeof (struct Radiotap_Send) + sizeof (struct GNUNET_MessageHeader))
+ {
+ fprintf (stderr, "Function stdin_send_hw: malformed packet (too small)\n");
+ exit (1);
+ }
+ sendsize -=
+ sizeof (struct Radiotap_Send) + sizeof (struct GNUNET_MessageHeader);
+
+ if (MAXLINE < sendsize)
+ {
+ fprintf (stderr, "Function stdin_send_hw: Packet too big for buffer\n");
+ exit (1);
+ }
+ if (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA != ntohs (hdr->type))
+ {
+ fprintf (stderr, "Function stdin_send_hw: wrong packet type\n");
+ exit (1);
+ }
+
+ rtheader.header.it_len = GNUNET_htole16 (sizeof (rtheader));
+ rtheader.rate = header->rate;
+ memcpy (write_pout.buf, &rtheader, sizeof (rtheader));
+ memcpy (write_pout.buf + sizeof (rtheader), &header[1], sendsize);
+ /* payload contains MAC address, but we don't trust it, so we'll
+ * overwrite it with OUR MAC address again to prevent mischief */
+ wlanheader = (struct ieee80211_frame *) (write_pout.buf + sizeof (rtheader));
+ mac_set (wlanheader, dev);
+ write_pout.size = sendsize + sizeof (rtheader);
+}
+
+
+/**
+ * Main function of the helper. This code accesses a WLAN interface
+ * in monitoring mode (layer 2) and then forwards traffic in both
+ * directions between the WLAN interface and stdin/stdout of this
+ * process. Error messages are written to stdout.
+ *
+ * @param argc number of arguments, must be 2
+ * @param argv arguments only argument is the name of the interface (i.e. 'mon0')
+ * @return 0 on success (never happens, as we don't return unless aborted), 1 on error
+ */
+int
+main (int argc, char *argv[])
+{
+ struct HardwareInfos dev;
+ char readbuf[MAXLINE];
+ int maxfd;
+ fd_set rfds;
+ fd_set wfds;
+ int stdin_open;
+ struct MessageStreamTokenizer *stdin_mst;
+ int raw_eno;
+
+ memset (&dev, 0, sizeof (dev));
+ dev.fd_raw = socket (PF_PACKET, SOCK_RAW, htons (ETH_P_ALL));
+ raw_eno = errno; /* remember for later */
+
+ /* drop privs */
+ {
+ uid_t uid = getuid ();
+#ifdef HAVE_SETRESUID
+ if (0 != setresuid (uid, uid, uid))
+ {
+ fprintf (stderr, "Failed to setresuid: %s\n", strerror (errno));
+ if (-1 != dev.fd_raw)
+ (void) close (dev.fd_raw);
+ return 1;
+ }
+#else
+ if (0 != (setuid (uid) | seteuid (uid)))
+ {
+ fprintf (stderr, "Failed to setuid: %s\n", strerror (errno));
+ if (-1 != dev.fd_raw)
+ (void) close (dev.fd_raw);
+ return 1;
+ }
+ }
+#endif
+
+ /* now that we've dropped root rights, we can do error checking */
+ if (2 != argc)
+ {
+ fprintf (stderr,
+ "You must specify the name of the interface as the first and only argument to this program.\n");
+ if (-1 != dev.fd_raw)
+ (void) close (dev.fd_raw);
+ return 1;
+ }
+
+ if (-1 == dev.fd_raw)
+ {
+ fprintf (stderr, "Failed to create raw socket: %s\n", strerror (raw_eno));
+ return 1;
+ }
+ if (dev.fd_raw >= FD_SETSIZE)
+ {
+ fprintf (stderr, "File descriptor too large for select (%d > %d)\n",
+ dev.fd_raw, FD_SETSIZE);
+ (void) close (dev.fd_raw);
+ return 1;
+ }
+ if (0 != test_wlan_interface (argv[1]))
+ {
+ (void) close (dev.fd_raw);
+ return 1;
+ }
+ strncpy (dev.iface, argv[1], IFNAMSIZ);
+ if (0 != open_device_raw (&dev))
+ {
+ (void) close (dev.fd_raw);
+ return 1;
+ }
+
+ /* send MAC address of the WLAN interface to STDOUT first */
+ {
+ struct GNUNET_TRANSPORT_WLAN_HelperControlMessage macmsg;
+
+ macmsg.hdr.size = htons (sizeof (macmsg));
+ macmsg.hdr.type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL);
+ memcpy (&macmsg.mac, &dev.pl_mac, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
+ memcpy (write_std.buf, &macmsg, sizeof (macmsg));
+ write_std.size = sizeof (macmsg);
+ }
+
+ stdin_mst = mst_create (&stdin_send_hw, &dev);
+ stdin_open = 1;
+ while (1)
+ {
+ maxfd = -1;
+ FD_ZERO (&rfds);
+ if ((0 == write_pout.size) && (1 == stdin_open))
+ {
+ FD_SET (STDIN_FILENO, &rfds);
+ maxfd = MAX (maxfd, STDIN_FILENO);
+ }
+ if (0 == write_std.size)
+ {
+ FD_SET (dev.fd_raw, &rfds);
+ maxfd = MAX (maxfd, dev.fd_raw);
+ }
+ FD_ZERO (&wfds);
+ if (0 < write_std.size)
+ {
+ FD_SET (STDOUT_FILENO, &wfds);
+ maxfd = MAX (maxfd, STDOUT_FILENO);
+ }
+ if (0 < write_pout.size)
+ {
+ FD_SET (dev.fd_raw, &wfds);
+ maxfd = MAX (maxfd, dev.fd_raw);
+ }
+ {
+ int retval = select (maxfd + 1, &rfds, &wfds, NULL, NULL);
+ if ((-1 == retval) && (EINTR == errno))
+ continue;
+ if (0 > retval)
+ {
+ fprintf (stderr, "select failed: %s\n", strerror (errno));
+ break;
+ }
+ }
+ if (FD_ISSET (STDOUT_FILENO, &wfds))
+ {
+ ssize_t ret =
+ write (STDOUT_FILENO, write_std.buf + write_std.pos,
+ write_std.size - write_std.pos);
+ if (0 > ret)
+ {
+ fprintf (stderr, "Failed to write to STDOUT: %s\n", strerror (errno));
+ break;
+ }
+ write_std.pos += ret;
+ if (write_std.pos == write_std.size)
+ {
+ write_std.pos = 0;
+ write_std.size = 0;
+ }
+ }
+ if (FD_ISSET (dev.fd_raw, &wfds))
+ {
+ ssize_t ret =
+ write (dev.fd_raw, write_pout.buf + write_std.pos,
+ write_pout.size - write_pout.pos);
+ if (0 > ret)
+ {
+ fprintf (stderr, "Failed to write to WLAN device: %s\n",
+ strerror (errno));
+ break;
+ }
+ write_pout.pos += ret;
+ if ((write_pout.pos != write_pout.size) && (0 != ret))
+ {
+ /* we should not get partial sends with packet-oriented devices... */
+ fprintf (stderr, "Write error, partial send: %u/%u\n",
+ (unsigned int) write_pout.pos,
+ (unsigned int) write_pout.size);
+ break;
+ }
+ if (write_pout.pos == write_pout.size)
+ {
+ write_pout.pos = 0;
+ write_pout.size = 0;
+ }
+ }
+
+ if (FD_ISSET (STDIN_FILENO, &rfds))
+ {
+ ssize_t ret =
+ read (STDIN_FILENO, readbuf, sizeof (readbuf));
+ if (0 > ret)
+ {
+ fprintf (stderr, "Read error from STDIN: %s\n", strerror (errno));
+ break;
+ }
+ if (0 == ret)
+ {
+ /* stop reading... */
+ stdin_open = 0;
+ }
+ mst_receive (stdin_mst, readbuf, ret);
+ }
+
+ if (FD_ISSET (dev.fd_raw, &rfds))
+ {
+ struct GNUNET_MessageHeader *header;
+ struct Radiotap_rx *rxinfo;
+ struct ieee80211_frame *datastart;
+ ssize_t ret;
+
+ header = (struct GNUNET_MessageHeader *) write_std.buf;
+ rxinfo = (struct Radiotap_rx *) &header[1];
+ datastart = (struct ieee80211_frame *) &rxinfo[1];
+ ret =
+ linux_read (&dev, (unsigned char *) datastart,
+ sizeof (write_std.buf) - sizeof (struct Radiotap_rx) -
+ sizeof (struct GNUNET_MessageHeader), rxinfo);
+ if (0 > ret)
+ {
+ fprintf (stderr, "Read error from raw socket: %s\n", strerror (errno));
+ break;
+ }
+ if ((0 < ret) && (0 == mac_test (datastart, &dev)))
+ {
+ write_std.size =
+ ret + sizeof (struct GNUNET_MessageHeader) +
+ sizeof (struct Radiotap_rx);
+ header->size = htons (write_std.size);
+ header->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
+ }
+ }
+
+ }
+ /* Error handling, try to clean up a bit at least */
+ mst_destroy (stdin_mst);
+ (void) close (dev.fd_raw);
+ return 1; /* we never exit 'normally' */
+}
+
+/* end of gnunet-helper-transport-wlan.c */
diff --git a/src/transport/gnunet-service-transport.c b/src/transport/gnunet-service-transport.c
new file mode 100644
index 0000000..cd9bb5c
--- /dev/null
+++ b/src/transport/gnunet-service-transport.c
@@ -0,0 +1,633 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport.c
+ * @brief
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_peerinfo_service.h"
+#include "gnunet_ats_service.h"
+#include "gnunet-service-transport.h"
+#include "gnunet-service-transport_blacklist.h"
+#include "gnunet-service-transport_clients.h"
+#include "gnunet-service-transport_hello.h"
+#include "gnunet-service-transport_neighbours.h"
+#include "gnunet-service-transport_plugins.h"
+#include "gnunet-service-transport_validation.h"
+#include "transport.h"
+
+/* globals */
+
+/**
+ * Statistics handle.
+ */
+struct GNUNET_STATISTICS_Handle *GST_stats;
+
+/**
+ * Configuration handle.
+ */
+const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
+
+/**
+ * Configuration handle.
+ */
+struct GNUNET_PeerIdentity GST_my_identity;
+
+/**
+ * Handle to peerinfo service.
+ */
+struct GNUNET_PEERINFO_Handle *GST_peerinfo;
+
+/**
+ * Our public key.
+ */
+struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key;
+
+/**
+ * Our private key.
+ */
+struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key;
+
+/**
+ * ATS handle.
+ */
+struct GNUNET_ATS_SchedulingHandle *GST_ats;
+
+
+/**
+ * Transmit our HELLO message to the given (connected) neighbour.
+ *
+ * @param cls the 'HELLO' message
+ * @param target a connected neighbour
+ * @param ats performance information (unused)
+ * @param ats_count number of records in ats (unused)
+ * @param address the address
+ */
+static void
+transmit_our_hello (void *cls, const struct GNUNET_PeerIdentity *target,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count,
+ const struct GNUNET_HELLO_Address *address)
+{
+ const struct GNUNET_MessageHeader *hello = cls;
+
+ GST_neighbours_send (target, (const char *) hello, ntohs (hello->size),
+ GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION, NULL, NULL);
+}
+
+
+/**
+ * My HELLO has changed. Tell everyone who should know.
+ *
+ * @param cls unused
+ * @param hello new HELLO
+ */
+static void
+process_hello_update (void *cls, const struct GNUNET_MessageHeader *hello)
+{
+ GST_clients_broadcast (hello, GNUNET_NO);
+ GST_neighbours_iterate (&transmit_our_hello, (void *) hello);
+}
+
+
+
+/**
+ * We received some payload. Prepare to pass it on to our clients.
+ *
+ * @param peer (claimed) identity of the other peer
+ * @param address the address
+ * @param session session used
+ * @param message the message to process
+ * @param ats performance information
+ * @param ats_count number of records in ats
+ * @return how long the plugin should wait until receiving more data
+ */
+static struct GNUNET_TIME_Relative
+process_payload (const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ struct GNUNET_TIME_Relative ret;
+ int do_forward;
+ struct InboundMessage *im;
+ size_t msg_size = ntohs (message->size);
+ size_t size =
+ sizeof (struct InboundMessage) + msg_size +
+ sizeof (struct GNUNET_ATS_Information) * (ats_count + 1);
+ char buf[size];
+ struct GNUNET_ATS_Information *ap;
+
+ ret = GNUNET_TIME_UNIT_ZERO;
+ do_forward = GNUNET_SYSERR;
+ ret = GST_neighbours_calculate_receive_delay (peer, msg_size, &do_forward);
+
+ if (!GST_neighbours_test_connected (peer))
+ {
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Discarded %u bytes type %u payload from peer `%s'\n", msg_size,
+ ntohs (message->type), GNUNET_i2s (peer));
+
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# bytes payload discarded due to not connected peer "),
+ msg_size, GNUNET_NO);
+ return ret;
+ }
+
+ if (do_forward != GNUNET_YES)
+ return ret;
+ im = (struct InboundMessage *) buf;
+ im->header.size = htons (size);
+ im->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_RECV);
+ im->ats_count = htonl (ats_count + 1);
+ im->peer = *peer;
+ ap = (struct GNUNET_ATS_Information *) &im[1];
+ memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
+ ap[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
+ ap[ats_count].value =
+ htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value);
+ memcpy (&ap[ats_count + 1], message, ntohs (message->size));
+
+ GNUNET_ATS_address_update (GST_ats, address, session, ap, ats_count + 1);
+ GST_clients_broadcast (&im->header, GNUNET_YES);
+
+ return ret;
+}
+
+
+/**
+ * Function called by the transport for each received message.
+ * This function should also be called with "NULL" for the
+ * message to signal that the other peer disconnected.
+ *
+ * @param cls closure, const char* with the name of the plugin we received the message from
+ * @param peer (claimed) identity of the other peer
+ * @param message the message, NULL if we only care about
+ * learning about the delay until we should receive again -- FIXME!
+ * @param ats performance information
+ * @param ats_count number of records in ats
+ * @param session identifier used for this session (NULL for plugins
+ * that do not offer bi-directional communication to the sender
+ * using the same "connection")
+ * @param sender_address binary address of the sender (if we established the
+ * connection or are otherwise sure of it; should be NULL
+ * for inbound TCP/UDP connections since it it not clear
+ * that we could establish ourselves a connection to that
+ * IP address and get the same system)
+ * @param sender_address_len number of bytes in sender_address
+ * @return how long the plugin should wait until receiving more data
+ * (plugins that do not support this, can ignore the return value)
+ */
+static struct GNUNET_TIME_Relative
+plugin_env_receive_callback (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count, struct Session *session,
+ const char *sender_address,
+ uint16_t sender_address_len)
+{
+ const char *plugin_name = cls;
+ struct GNUNET_TIME_Relative ret;
+ struct GNUNET_HELLO_Address address;
+ uint16_t type;
+
+ address.peer = *peer;
+ address.address = sender_address;
+ address.address_length = sender_address_len;
+ address.transport_name = plugin_name;
+ ret = GNUNET_TIME_UNIT_ZERO;
+ if (NULL == message)
+ goto end;
+ type = ntohs (message->type);
+#if DEBUG_TRANSPORT
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received Message with type %u\n", type);
+#endif
+
+ switch (type)
+ {
+ case GNUNET_MESSAGE_TYPE_HELLO:
+ GST_validation_handle_hello (message);
+ return ret;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_PING:
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Processing `%s' from `%s'\n", "PING",
+ (sender_address !=
+ NULL) ? GST_plugins_a2s (&address) : "<inbound>");
+#endif
+ GST_validation_handle_ping (peer, message, &address, session);
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_PONG:
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Processing `%s' from `%s'\n", "PONG",
+ (sender_address !=
+ NULL) ? GST_plugins_a2s (&address) : "<inbound>");
+#endif
+ GST_validation_handle_pong (peer, message);
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT:
+ GST_neighbours_handle_connect (message, peer, &address, session, ats,
+ ats_count);
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK:
+ GST_neighbours_handle_connect_ack (message, peer, &address, session, ats,
+ ats_count);
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK:
+ GST_neighbours_handle_ack (message, peer, &address, session, ats,
+ ats_count);
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT:
+ GST_neighbours_handle_disconnect_message (peer, message);
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE:
+ GST_neighbours_keepalive (peer);
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE:
+ GST_neighbours_keepalive_response (peer, ats, ats_count);
+ break;
+ default:
+ /* should be payload */
+ ret = process_payload (peer, &address, session, message, ats, ats_count);
+ break;
+ }
+end:
+#if 1
+ /* FIXME: this should not be needed, and not sure it's good to have it, but without
+ * this connections seem to go extra-slow */
+ GNUNET_ATS_address_update (GST_ats, &address, session, ats, ats_count);
+#endif
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Allowing receive from peer %s to continue in %llu ms\n",
+ GNUNET_i2s (peer), (unsigned long long) ret.rel_value);
+#endif
+ return ret;
+}
+
+
+/**
+ * Function that will be called for each address the transport
+ * is aware that it might be reachable under. Update our HELLO.
+ *
+ * @param cls name of the plugin (const char*)
+ * @param add_remove should the address added (YES) or removed (NO) from the
+ * set of valid addresses?
+ * @param addr one of the addresses of the host
+ * the specific address format depends on the transport
+ * @param addrlen length of the address
+ */
+static void
+plugin_env_address_change_notification (void *cls, int add_remove,
+ const void *addr, size_t addrlen)
+{
+ const char *plugin_name = cls;
+ struct GNUNET_HELLO_Address address;
+
+ address.peer = GST_my_identity;
+ address.transport_name = plugin_name;
+ address.address = addr;
+ address.address_length = addrlen;
+ GST_hello_modify_addresses (add_remove, &address);
+}
+
+
+/**
+ * Function that will be called whenever the plugin internally
+ * cleans up a session pointer and hence the service needs to
+ * discard all of those sessions as well. Plugins that do not
+ * use sessions can simply omit calling this function and always
+ * use NULL wherever a session pointer is needed. This function
+ * should be called BEFORE a potential "TransmitContinuation"
+ * from the "TransmitFunction".
+ *
+ * @param cls closure
+ * @param peer which peer was the session for
+ * @param session which session is being destoyed
+ */
+static void
+plugin_env_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
+ struct Session *session)
+{
+ const char *transport_name = cls;
+ struct GNUNET_HELLO_Address address;
+
+ GNUNET_assert (strlen (transport_name) > 0);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %X to peer `%s' ended \n",
+ session, GNUNET_i2s (peer));
+#endif
+ if (NULL != session)
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO | GNUNET_ERROR_TYPE_BULK,
+ "transport-ats",
+ "Telling ATS to destroy session %p from peer %s\n",
+ session, GNUNET_i2s (peer));
+ address.peer = *peer;
+ address.address = NULL;
+ address.address_length = 0;
+ address.transport_name = transport_name;
+ GST_neighbours_session_terminated (peer, session);
+ GNUNET_ATS_address_destroyed (GST_ats, &address, session);
+}
+
+
+/**
+ * Function that will be called to figure if an address is an loopback,
+ * LAN, WAN etc. address
+ *
+ * @param cls closure
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return ATS Information containing the network type
+ */
+static const struct GNUNET_ATS_Information
+plugin_env_address_to_type (void *cls,
+ const struct sockaddr *addr,
+ size_t addrlen)
+{
+ struct GNUNET_ATS_Information ats;
+ ats.type = htonl (GNUNET_ATS_NETWORK_TYPE);
+ ats.value = htonl (GNUNET_ATS_NET_UNSPECIFIED);
+ if (GST_ats == NULL)
+ {
+ GNUNET_break (0);
+ return ats;
+ }
+ if (((addr->sa_family != AF_INET) && (addrlen != sizeof (struct sockaddr_in))) &&
+ ((addr->sa_family != AF_INET6) && (addrlen != sizeof (struct sockaddr_in6))) &&
+ (addr->sa_family != AF_UNIX))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Malformed address with length %u `%s'\n",
+ addrlen,
+ GNUNET_a2s(addr, addrlen));
+ GNUNET_break (0);
+ return (const struct GNUNET_ATS_Information) ats;
+ }
+ return GNUNET_ATS_address_get_type(GST_ats, addr, addrlen);
+}
+
+
+/**
+ * Function called by ATS to notify the callee that the
+ * assigned bandwidth or address for a given peer was changed. If the
+ * callback is called with address/bandwidth assignments of zero, the
+ * ATS disconnect function will still be called once the disconnect
+ * actually happened.
+ *
+ * @param cls closure
+ * @param address address to use (for peer given in address)
+ * @param session session to use (if available)
+ * @param bandwidth_out assigned outbound bandwidth for the connection, 0 to disconnect from peer
+ * @param bandwidth_in assigned inbound bandwidth for the connection, 0 to disconnect from peer
+ * @param ats ATS information
+ * @param ats_count number of ATS elements
+ */
+static void
+ats_request_address_change (void *cls,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out,
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ uint32_t bw_in = ntohl (bandwidth_in.value__);
+ uint32_t bw_out = ntohl (bandwidth_out.value__);
+
+ /* ATS tells me to disconnect from peer */
+ if ((bw_in == 0) && (bw_out == 0))
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "ATS tells me to disconnect from peer `%s'\n",
+ GNUNET_i2s (&address->peer));
+#endif
+ GST_neighbours_force_disconnect (&address->peer);
+ return;
+ }
+ /* will never return GNUNET_YES since connection is to be established */
+ GST_neighbours_switch_to_address (&address->peer, address, session, ats,
+ ats_count, bandwidth_in,
+ bandwidth_out);
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer connected to us.
+ *
+ * @param cls closure
+ * @param peer the peer that connected
+ * @param ats performance data
+ * @param ats_count number of entries in ats
+ */
+static void
+neighbours_connect_notification (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ size_t len =
+ sizeof (struct ConnectInfoMessage) +
+ ats_count * sizeof (struct GNUNET_ATS_Information);
+ char buf[len];
+ struct ConnectInfoMessage *connect_msg = (struct ConnectInfoMessage *) buf;
+ struct GNUNET_ATS_Information *ap;
+
+ connect_msg->header.size = htons (sizeof (buf));
+ connect_msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
+ connect_msg->ats_count = htonl (ats_count);
+ connect_msg->id = *peer;
+ ap = (struct GNUNET_ATS_Information *) &connect_msg[1];
+ memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
+ GST_clients_broadcast (&connect_msg->header, GNUNET_NO);
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer disconnected from us.
+ *
+ * @param cls closure
+ * @param peer the peer that disconnected
+ */
+static void
+neighbours_disconnect_notification (void *cls,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct DisconnectInfoMessage disconnect_msg;
+
+ disconnect_msg.header.size = htons (sizeof (struct DisconnectInfoMessage));
+ disconnect_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT);
+ disconnect_msg.reserved = htonl (0);
+ disconnect_msg.peer = *peer;
+ GST_clients_broadcast (&disconnect_msg.header, GNUNET_NO);
+}
+
+
+/**
+ * Function called to notify transport users that a neighbour peer changed its
+ * active address.
+ *
+ * @param cls closure
+ * @param peer peer this update is about (never NULL)
+ * @param address address, NULL on disconnect
+ */
+static void
+neighbours_address_notification (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address)
+{
+ GST_clients_broadcast_address_notification (peer, address);
+}
+
+
+/**
+ * Function called when the service shuts down. Unloads our plugins
+ * and cancels pending validations.
+ *
+ * @param cls closure, unused
+ * @param tc task context (unused)
+ */
+static void
+shutdown_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GST_neighbours_stop ();
+ GST_validation_stop ();
+ GST_plugins_unload ();
+
+ GNUNET_ATS_scheduling_done (GST_ats);
+ GST_ats = NULL;
+ GST_clients_stop ();
+ GST_blacklist_stop ();
+ GST_hello_stop ();
+
+ if (GST_peerinfo != NULL)
+ {
+ GNUNET_PEERINFO_disconnect (GST_peerinfo);
+ GST_peerinfo = NULL;
+ }
+ if (GST_stats != NULL)
+ {
+ GNUNET_STATISTICS_destroy (GST_stats, GNUNET_NO);
+ GST_stats = NULL;
+ }
+ if (GST_my_private_key != NULL)
+ {
+ GNUNET_CRYPTO_rsa_key_free (GST_my_private_key);
+ GST_my_private_key = NULL;
+ }
+}
+
+
+/**
+ * Initiate transport service.
+ *
+ * @param cls closure
+ * @param server the initialized server
+ * @param c configuration to use
+ */
+static void
+run (void *cls, struct GNUNET_SERVER_Handle *server,
+ const struct GNUNET_CONFIGURATION_Handle *c)
+{
+ char *keyfile;
+
+ /* setup globals */
+ GST_cfg = c;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (c, "GNUNETD", "HOSTKEY",
+ &keyfile))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _
+ ("Transport service is lacking key configuration settings. Exiting.\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GST_my_private_key = GNUNET_CRYPTO_rsa_key_create_from_file (keyfile);
+ GNUNET_free (keyfile);
+ if (GST_my_private_key == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Transport service could not access hostkey. Exiting.\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+ GST_stats = GNUNET_STATISTICS_create ("transport", c);
+ GST_peerinfo = GNUNET_PEERINFO_connect (c);
+ GNUNET_CRYPTO_rsa_key_get_public (GST_my_private_key, &GST_my_public_key);
+ GNUNET_CRYPTO_hash (&GST_my_public_key, sizeof (GST_my_public_key),
+ &GST_my_identity.hashPubKey);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL, &shutdown_task,
+ NULL);
+ if (GST_peerinfo == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not access PEERINFO service. Exiting.\n"));
+ GNUNET_SCHEDULER_shutdown ();
+ return;
+ }
+
+ /* start subsystems */
+ GST_hello_start (&process_hello_update, NULL);
+ GST_blacklist_start (server);
+ GST_ats =
+ GNUNET_ATS_scheduling_init (GST_cfg, &ats_request_address_change, NULL);
+ GST_plugins_load (&plugin_env_receive_callback,
+ &plugin_env_address_change_notification,
+ &plugin_env_session_end,
+ &plugin_env_address_to_type);
+ GST_neighbours_start (NULL,
+ &neighbours_connect_notification,
+ &neighbours_disconnect_notification,
+ &neighbours_address_notification);
+ GST_clients_start (server);
+ GST_validation_start ();
+}
+
+
+/**
+ * The main function for the transport service.
+ *
+ * @param argc number of arguments from the command line
+ * @param argv command line arguments
+ * @return 0 ok, 1 on error
+ */
+int
+main (int argc, char *const *argv)
+{
+ return (GNUNET_OK ==
+ GNUNET_SERVICE_run (argc, argv, "transport",
+ GNUNET_SERVICE_OPTION_NONE, &run, NULL)) ? 0 : 1;
+}
+
+/* end of file gnunet-service-transport-new.c */
diff --git a/src/transport/gnunet-service-transport.h b/src/transport/gnunet-service-transport.h
new file mode 100644
index 0000000..adc28ba
--- /dev/null
+++ b/src/transport/gnunet-service-transport.h
@@ -0,0 +1,72 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport.h
+ * @brief globals
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_TRANSPORT_H
+#define GNUNET_SERVICE_TRANSPORT_H
+
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_util_lib.h"
+
+#define VERBOSE_VALIDATION GNUNET_YES
+
+/**
+ * Statistics handle.
+ */
+extern struct GNUNET_STATISTICS_Handle *GST_stats;
+
+/**
+ * Configuration handle.
+ */
+extern const struct GNUNET_CONFIGURATION_Handle *GST_cfg;
+
+/**
+ * Configuration handle.
+ */
+extern struct GNUNET_PeerIdentity GST_my_identity;
+
+/**
+ * Handle to peerinfo service.
+ */
+extern struct GNUNET_PEERINFO_Handle *GST_peerinfo;
+
+/**
+ * Our public key.
+ */
+extern struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded GST_my_public_key;
+
+/**
+ * Our private key.
+ */
+extern struct GNUNET_CRYPTO_RsaPrivateKey *GST_my_private_key;
+
+/**
+ * ATS handle.
+ */
+extern struct GNUNET_ATS_SchedulingHandle *GST_ats;
+
+
+#endif
+/* end of file gnunet-service-transport_plugins.h */
diff --git a/src/transport/gnunet-service-transport_blacklist.c b/src/transport/gnunet-service-transport_blacklist.c
new file mode 100644
index 0000000..2089949
--- /dev/null
+++ b/src/transport/gnunet-service-transport_blacklist.c
@@ -0,0 +1,822 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_blacklist.c
+ * @brief blacklisting implementation
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-transport.h"
+#include "gnunet-service-transport_blacklist.h"
+#include "gnunet-service-transport_neighbours.h"
+#include "transport.h"
+
+
+/**
+ * Size of the blacklist hash map.
+ */
+#define TRANSPORT_BLACKLIST_HT_SIZE 64
+
+
+/**
+ * Context we use when performing a blacklist check.
+ */
+struct GST_BlacklistCheck;
+
+
+/**
+ * Information kept for each client registered to perform
+ * blacklisting.
+ */
+struct Blacklisters
+{
+ /**
+ * This is a linked list.
+ */
+ struct Blacklisters *next;
+
+ /**
+ * This is a linked list.
+ */
+ struct Blacklisters *prev;
+
+ /**
+ * Client responsible for this entry.
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Blacklist check that we're currently performing (or NULL
+ * if we're performing one that has been cancelled).
+ */
+ struct GST_BlacklistCheck *bc;
+
+ /**
+ * Set to GNUNET_YES if we're currently waiting for a reply.
+ */
+ int waiting_for_reply;
+
+};
+
+
+
+/**
+ * Context we use when performing a blacklist check.
+ */
+struct GST_BlacklistCheck
+{
+
+ /**
+ * This is a linked list.
+ */
+ struct GST_BlacklistCheck *next;
+
+ /**
+ * This is a linked list.
+ */
+ struct GST_BlacklistCheck *prev;
+
+ /**
+ * Peer being checked.
+ */
+ struct GNUNET_PeerIdentity peer;
+
+ /**
+ * Continuation to call with the result.
+ */
+ GST_BlacklistTestContinuation cont;
+
+ /**
+ * Closure for cont.
+ */
+ void *cont_cls;
+
+ /**
+ * Current transmission request handle for this client, or NULL if no
+ * request is pending.
+ */
+ struct GNUNET_CONNECTION_TransmitHandle *th;
+
+ /**
+ * Our current position in the blacklisters list.
+ */
+ struct Blacklisters *bl_pos;
+
+ /**
+ * Current task performing the check.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier task;
+
+};
+
+
+/**
+ * Head of DLL of active blacklisting queries.
+ */
+static struct GST_BlacklistCheck *bc_head;
+
+/**
+ * Tail of DLL of active blacklisting queries.
+ */
+static struct GST_BlacklistCheck *bc_tail;
+
+/**
+ * Head of DLL of blacklisting clients.
+ */
+static struct Blacklisters *bl_head;
+
+/**
+ * Tail of DLL of blacklisting clients.
+ */
+static struct Blacklisters *bl_tail;
+
+/**
+ * Hashmap of blacklisted peers. Values are of type 'char *' (transport names),
+ * can be NULL if we have no static blacklist.
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *blacklist;
+
+
+/**
+ * Perform next action in the blacklist check.
+ *
+ * @param cls the 'struct BlacklistCheck*'
+ * @param tc unused
+ */
+static void
+do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * Called whenever a client is disconnected. Frees our
+ * resources associated with that client.
+ *
+ * @param cls closure (unused)
+ * @param client identification of the client
+ */
+static void
+client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ struct Blacklisters *bl;
+ struct GST_BlacklistCheck *bc;
+
+ if (client == NULL)
+ return;
+ for (bl = bl_head; bl != NULL; bl = bl->next)
+ {
+ if (bl->client != client)
+ continue;
+ for (bc = bc_head; bc != NULL; bc = bc->next)
+ {
+ if (bc->bl_pos != bl)
+ continue;
+ bc->bl_pos = bl->next;
+ if (bc->th != NULL)
+ {
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
+ bc->th = NULL;
+ }
+ if (bc->task == GNUNET_SCHEDULER_NO_TASK)
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+ break;
+ }
+ GNUNET_CONTAINER_DLL_remove (bl_head, bl_tail, bl);
+ GNUNET_SERVER_client_drop (bl->client);
+ GNUNET_free (bl);
+ break;
+ }
+}
+
+
+/**
+ * Read the blacklist file, containing transport:peer entries.
+ * Provided the transport is loaded, set up hashmap with these
+ * entries to blacklist peers by transport.
+ *
+ */
+static void
+read_blacklist_file ()
+{
+ char *fn;
+ char *data;
+ size_t pos;
+ size_t colon_pos;
+ int tsize;
+ struct GNUNET_PeerIdentity pid;
+ struct stat frstat;
+ struct GNUNET_CRYPTO_HashAsciiEncoded enc;
+ unsigned int entries_found;
+ char *transport_name;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (GST_cfg, "TRANSPORT",
+ "BLACKLIST_FILE", &fn))
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Option `%s' in section `%s' not specified!\n",
+ "BLACKLIST_FILE", "TRANSPORT");
+#endif
+ return;
+ }
+ if (GNUNET_OK != GNUNET_DISK_file_test (fn))
+ GNUNET_DISK_fn_write (fn, NULL, 0,
+ GNUNET_DISK_PERM_USER_READ |
+ GNUNET_DISK_PERM_USER_WRITE);
+ if (0 != STAT (fn, &frstat))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Could not read blacklist file `%s'\n"), fn);
+ GNUNET_free (fn);
+ return;
+ }
+ if (frstat.st_size == 0)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Blacklist file `%s' is empty.\n"),
+ fn);
+#endif
+ GNUNET_free (fn);
+ return;
+ }
+ /* FIXME: use mmap */
+ data = GNUNET_malloc_large (frstat.st_size);
+ GNUNET_assert (data != NULL);
+ if (frstat.st_size != GNUNET_DISK_fn_read (fn, data, frstat.st_size))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to read blacklist from `%s'\n"), fn);
+ GNUNET_free (fn);
+ GNUNET_free (data);
+ return;
+ }
+ entries_found = 0;
+ pos = 0;
+ while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos]))
+ pos++;
+ while ((frstat.st_size >= sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)) &&
+ (pos <=
+ frstat.st_size - sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded)))
+ {
+ colon_pos = pos;
+ while ((colon_pos < frstat.st_size) && (data[colon_pos] != ':') &&
+ (!isspace ((unsigned char) data[colon_pos])))
+ colon_pos++;
+ if (colon_pos >= frstat.st_size)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("Syntax error in blacklist file at offset %llu, giving up!\n"),
+ (unsigned long long) colon_pos);
+ GNUNET_free (fn);
+ GNUNET_free (data);
+ return;
+ }
+
+ if (isspace ((unsigned char) data[colon_pos]))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
+ (unsigned long long) colon_pos);
+ pos = colon_pos;
+ while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos]))
+ pos++;
+ continue;
+ }
+ tsize = colon_pos - pos;
+ if ((pos >= frstat.st_size) || (pos + tsize >= frstat.st_size) ||
+ (tsize == 0))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("Syntax error in blacklist file at offset %llu, giving up!\n"),
+ (unsigned long long) colon_pos);
+ GNUNET_free (fn);
+ GNUNET_free (data);
+ return;
+ }
+
+ if (tsize < 1)
+ continue;
+
+ transport_name = GNUNET_malloc (tsize + 1);
+ memcpy (transport_name, &data[pos], tsize);
+ pos = colon_pos + 1;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Read transport name `%s' in blacklist file.\n",
+ transport_name);
+#endif
+ memcpy (&enc, &data[pos], sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded));
+ if (!isspace
+ ((unsigned char)
+ enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1]))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("Syntax error in blacklist file at offset %llu, skipping bytes.\n"),
+ (unsigned long long) pos);
+ pos++;
+ while ((pos < frstat.st_size) && (!isspace ((unsigned char) data[pos])))
+ pos++;
+ GNUNET_free_non_null (transport_name);
+ continue;
+ }
+ enc.encoding[sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded) - 1] = '\0';
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_hash_from_string ((char *) &enc, &pid.hashPubKey))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("Syntax error in blacklist file at offset %llu, skipping bytes `%s'.\n"),
+ (unsigned long long) pos, &enc);
+ }
+ else
+ {
+ if (0 !=
+ memcmp (&pid, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ entries_found++;
+ GST_blacklist_add_peer (&pid, transport_name);
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ _("Found myself `%s' in blacklist (useless, ignored)\n"),
+ GNUNET_i2s (&pid));
+ }
+ }
+ pos = pos + sizeof (struct GNUNET_CRYPTO_HashAsciiEncoded);
+ GNUNET_free_non_null (transport_name);
+ while ((pos < frstat.st_size) && isspace ((unsigned char) data[pos]))
+ pos++;
+ }
+ GNUNET_STATISTICS_update (GST_stats, "# Transport entries blacklisted",
+ entries_found, GNUNET_NO);
+ GNUNET_free (data);
+ GNUNET_free (fn);
+}
+
+
+/**
+ * Start blacklist subsystem.
+ *
+ * @param server server used to accept clients from
+ */
+void
+GST_blacklist_start (struct GNUNET_SERVER_Handle *server)
+{
+ read_blacklist_file ();
+ GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification,
+ NULL);
+}
+
+
+/**
+ * Free the given entry in the blacklist.
+ *
+ * @param cls unused
+ * @param key host identity (unused)
+ * @param value the blacklist entry
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+free_blacklist_entry (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ char *be = value;
+
+ GNUNET_free (be);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Stop blacklist subsystem.
+ */
+void
+GST_blacklist_stop ()
+{
+ if (NULL != blacklist)
+ {
+ GNUNET_CONTAINER_multihashmap_iterate (blacklist, &free_blacklist_entry,
+ NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (blacklist);
+ blacklist = NULL;
+ }
+}
+
+
+/**
+ * Transmit blacklist query to the client.
+ *
+ * @param cls the 'struct GST_BlacklistCheck'
+ * @param size number of bytes allowed
+ * @param buf where to copy the message
+ * @return number of bytes copied to buf
+ */
+static size_t
+transmit_blacklist_message (void *cls, size_t size, void *buf)
+{
+ struct GST_BlacklistCheck *bc = cls;
+ struct Blacklisters *bl;
+ struct BlacklistMessage bm;
+
+ bc->th = NULL;
+ if (size == 0)
+ {
+ GNUNET_assert (bc->task == GNUNET_SCHEDULER_NO_TASK);
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to send blacklist test for peer `%s' to client\n",
+ GNUNET_i2s (&bc->peer));
+ return 0;
+ }
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending blacklist test for peer `%s' to client\n",
+ GNUNET_i2s (&bc->peer));
+#endif
+ bl = bc->bl_pos;
+ bm.header.size = htons (sizeof (struct BlacklistMessage));
+ bm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY);
+ bm.is_allowed = htonl (0);
+ bm.peer = bc->peer;
+ memcpy (buf, &bm, sizeof (bm));
+ GNUNET_SERVER_receive_done (bl->client, GNUNET_OK);
+ bl->waiting_for_reply = GNUNET_YES;
+ return sizeof (bm);
+}
+
+
+/**
+ * Perform next action in the blacklist check.
+ *
+ * @param cls the 'struct GST_BlacklistCheck*'
+ * @param tc unused
+ */
+static void
+do_blacklist_check (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GST_BlacklistCheck *bc = cls;
+ struct Blacklisters *bl;
+
+ bc->task = GNUNET_SCHEDULER_NO_TASK;
+ bl = bc->bl_pos;
+ if (bl == NULL)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "No other blacklist clients active, will allow neighbour `%s'\n",
+ GNUNET_i2s (&bc->peer));
+#endif
+ bc->cont (bc->cont_cls, &bc->peer, GNUNET_OK);
+ GNUNET_CONTAINER_DLL_remove(bc_head, bc_tail, bc);
+ GNUNET_free (bc);
+ return;
+ }
+ if ((bl->bc != NULL) || (bl->waiting_for_reply != GNUNET_NO))
+ return; /* someone else busy with this client */
+ bl->bc = bc;
+ bc->th =
+ GNUNET_SERVER_notify_transmit_ready (bl->client,
+ sizeof (struct BlacklistMessage),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_blacklist_message, bc);
+}
+
+
+/**
+ * Got the result about an existing connection from a new blacklister.
+ * Shutdown the neighbour if necessary.
+ *
+ * @param cls unused
+ * @param peer the neighbour that was investigated
+ * @param allowed GNUNET_OK if we can keep it,
+ * GNUNET_NO if we must shutdown the connection
+ */
+static void
+confirm_or_drop_neighbour (void *cls, const struct GNUNET_PeerIdentity *peer,
+ int allowed)
+{
+ if (GNUNET_OK == allowed)
+ return; /* we're done */
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# disconnects due to blacklist"), 1,
+ GNUNET_NO);
+ GST_neighbours_force_disconnect (peer);
+}
+
+
+/**
+ * Closure for 'test_connection_ok'.
+ */
+struct TestConnectionContext
+{
+ /**
+ * Is this the first neighbour we're checking?
+ */
+ int first;
+
+ /**
+ * Handle to the blacklisting client we need to ask.
+ */
+ struct Blacklisters *bl;
+};
+
+
+/**
+ * Test if an existing connection is still acceptable given a new
+ * blacklisting client.
+ *
+ * @param cls the 'struct TestConnectionContest'
+ * @param neighbour neighbour's identity
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ * @param address the address
+ */
+static void
+test_connection_ok (void *cls, const struct GNUNET_PeerIdentity *neighbour,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct TestConnectionContext *tcc = cls;
+ struct GST_BlacklistCheck *bc;
+
+ bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck));
+ GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
+ bc->peer = *neighbour;
+ bc->cont = &confirm_or_drop_neighbour;
+ bc->cont_cls = NULL;
+ bc->bl_pos = tcc->bl;
+ if (GNUNET_YES == tcc->first)
+ {
+ /* all would wait for the same client, no need to
+ * create more than just the first task right now */
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+ tcc->first = GNUNET_NO;
+ }
+}
+
+
+
+/**
+ * Initialize a blacklisting client. We got a blacklist-init
+ * message from this client, add him to the list of clients
+ * to query for blacklisting.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the blacklist-init message that was sent
+ */
+void
+GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct Blacklisters *bl;
+ struct TestConnectionContext tcc;
+
+ bl = bl_head;
+ while (bl != NULL)
+ {
+ if (bl->client == client)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ bl = bl->next;
+ }
+ bl = GNUNET_malloc (sizeof (struct Blacklisters));
+ bl->client = client;
+ GNUNET_SERVER_client_keep (client);
+ GNUNET_CONTAINER_DLL_insert_after (bl_head, bl_tail, bl_tail, bl);
+
+ /* confirm that all existing connections are OK! */
+ tcc.bl = bl;
+ tcc.first = GNUNET_YES;
+ GST_neighbours_iterate (&test_connection_ok, &tcc);
+}
+
+
+/**
+ * A blacklisting client has sent us reply. Process it.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the blacklist-init message that was sent
+ */
+void
+GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct BlacklistMessage *msg =
+ (const struct BlacklistMessage *) message;
+ struct Blacklisters *bl;
+ struct GST_BlacklistCheck *bc;
+
+ bl = bl_head;
+ while ((bl != NULL) && (bl->client != client))
+ bl = bl->next;
+ if (bl == NULL)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Blacklist client disconnected\n");
+#endif
+ /* FIXME: other error handling here!? */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ bc = bl->bc;
+ bl->bc = NULL;
+ bl->waiting_for_reply = GNUNET_NO;
+ if (NULL != bc)
+ {
+ /* only run this if the blacklist check has not been
+ * cancelled in the meantime... */
+ if (ntohl (msg->is_allowed) == GNUNET_SYSERR)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Blacklist check failed, peer not allowed\n");
+#endif
+ bc->cont (bc->cont_cls, &bc->peer, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
+ GNUNET_free (bc);
+ }
+ else
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Blacklist check succeeded, continuing with checks\n");
+#endif
+ bc->bl_pos = bc->bl_pos->next;
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+ }
+ }
+ /* check if any other bc's are waiting for this blacklister */
+ bc = bc_head;
+ for (bc = bc_head; bc != NULL; bc = bc->next)
+ if ((bc->bl_pos == bl) && (GNUNET_SCHEDULER_NO_TASK == bc->task))
+ {
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+ break;
+ }
+}
+
+
+/**
+ * Add the given peer to the blacklist (for the given transport).
+ *
+ * @param peer peer to blacklist
+ * @param transport_name transport to blacklist for this peer, NULL for all
+ */
+void
+GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
+ const char *transport_name)
+{
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Adding peer `%s' with plugin `%s' to blacklist\n",
+ GNUNET_i2s (peer), transport_name);
+#endif
+ if (blacklist == NULL)
+ blacklist =
+ GNUNET_CONTAINER_multihashmap_create (TRANSPORT_BLACKLIST_HT_SIZE);
+ GNUNET_CONTAINER_multihashmap_put (blacklist, &peer->hashPubKey,
+ GNUNET_strdup (transport_name),
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+}
+
+
+/**
+ * Test if the given blacklist entry matches. If so,
+ * abort the iteration.
+ *
+ * @param cls the transport name to match (const char*)
+ * @param key the key (unused)
+ * @param value the 'char *' (name of a blacklisted transport)
+ * @return GNUNET_OK if the entry does not match, GNUNET_NO if it matches
+ */
+static int
+test_blacklisted (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ const char *transport_name = cls;
+ char *be = value;
+
+ /* blacklist check for specific no specific transport*/
+ if (transport_name == NULL)
+ return GNUNET_NO;
+
+ /* blacklist check for specific transport */
+ if (0 == strcmp (transport_name, be))
+ return GNUNET_NO; /* abort iteration! */
+ return GNUNET_OK;
+}
+
+
+/**
+ * Test if a peer/transport combination is blacklisted.
+ *
+ * @param peer the identity of the peer to test
+ * @param transport_name name of the transport to test, never NULL
+ * @param cont function to call with result
+ * @param cont_cls closure for 'cont'
+ * @return handle to the blacklist check, NULL if the decision
+ * was made instantly and 'cont' was already called
+ */
+struct GST_BlacklistCheck *
+GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
+ const char *transport_name,
+ GST_BlacklistTestContinuation cont, void *cont_cls)
+{
+ struct GST_BlacklistCheck *bc;
+
+ GNUNET_assert (peer != NULL);
+
+ if ((blacklist != NULL) &&
+ (GNUNET_SYSERR ==
+ GNUNET_CONTAINER_multihashmap_get_multiple (blacklist, &peer->hashPubKey,
+ &test_blacklisted,
+ (void *) transport_name)))
+ {
+ /* disallowed by config, disapprove instantly */
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# disconnects due to blacklist"),
+ 1, GNUNET_NO);
+ if (cont != NULL)
+ cont (cont_cls, peer, GNUNET_NO);
+ return NULL;
+ }
+
+ if (bl_head == NULL)
+ {
+ /* no blacklist clients, approve instantly */
+ if (cont != NULL)
+ cont (cont_cls, peer, GNUNET_OK);
+ return NULL;
+ }
+
+ /* need to query blacklist clients */
+ bc = GNUNET_malloc (sizeof (struct GST_BlacklistCheck));
+ GNUNET_CONTAINER_DLL_insert (bc_head, bc_tail, bc);
+ bc->peer = *peer;
+ bc->cont = cont;
+ bc->cont_cls = cont_cls;
+ bc->bl_pos = bl_head;
+ bc->task = GNUNET_SCHEDULER_add_now (&do_blacklist_check, bc);
+ return bc;
+}
+
+
+/**
+ * Cancel a blacklist check.
+ *
+ * @param bc check to cancel
+ */
+void
+GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc)
+{
+ GNUNET_CONTAINER_DLL_remove (bc_head, bc_tail, bc);
+ if (bc->bl_pos != NULL)
+ {
+ if (bc->bl_pos->bc == bc)
+ {
+ /* we're at the head of the queue, remove us! */
+ bc->bl_pos->bc = NULL;
+ }
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != bc->task)
+ {
+ GNUNET_SCHEDULER_cancel (bc->task);
+ bc->task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != bc->th)
+ {
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (bc->th);
+ bc->th = NULL;
+ }
+ GNUNET_free (bc);
+}
+
+
+/* end of file gnunet-service-transport_blacklist.c */
diff --git a/src/transport/gnunet-service-transport_blacklist.h b/src/transport/gnunet-service-transport_blacklist.h
new file mode 100644
index 0000000..68da7e4
--- /dev/null
+++ b/src/transport/gnunet-service-transport_blacklist.h
@@ -0,0 +1,127 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_blacklist.h
+ * @brief blacklisting API
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_TRANSPORT_BLACKLIST_H
+#define GNUNET_SERVICE_TRANSPORT_BLACKLIST_H
+
+#include "gnunet_statistics_service.h"
+#include "gnunet_util_lib.h"
+
+/**
+ * Start blacklist subsystem.
+ *
+ * @param server server used to accept clients from
+ */
+void
+GST_blacklist_start (struct GNUNET_SERVER_Handle *server);
+
+
+/**
+ * Stop blacklist subsystem.
+ */
+void
+GST_blacklist_stop (void);
+
+
+/**
+ * Initialize a blacklisting client. We got a blacklist-init
+ * message from this client, add him to the list of clients
+ * to query for blacklisting.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the blacklist-init message that was sent
+ */
+void
+GST_blacklist_handle_init (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * A blacklisting client has sent us reply. Process it.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the blacklist-init message that was sent
+ */
+void
+GST_blacklist_handle_reply (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message);
+
+/**
+ * Add the given peer to the blacklist (for the given transport).
+ *
+ * @param peer peer to blacklist
+ * @param transport_name transport to blacklist for this peer, NULL for all
+ */
+void
+GST_blacklist_add_peer (const struct GNUNET_PeerIdentity *peer,
+ const char *transport_name);
+
+
+/**
+ * Handle to an active blacklist check.
+ */
+struct GST_BlacklistCheck;
+
+
+/**
+ * Continuation called from a blacklist test.
+ *
+ * @param cls closure
+ * @param peer identity of peer that was tested
+ * @param result GNUNET_OK if the connection is allowed,
+ * GNUNET_NO if not
+ */
+typedef void (*GST_BlacklistTestContinuation) (void *cls,
+ const struct GNUNET_PeerIdentity
+ * peer, int result);
+
+
+/**
+ * Test if a peer/transport combination is blacklisted.
+ *
+ * @param peer the identity of the peer to test
+ * @param transport_name name of the transport to test, never NULL
+ * @param cont function to call with result
+ * @param cont_cls closure for 'cont'
+ * @return handle to the blacklist check, NULL if the decision
+ * was made instantly and 'cont' was already called
+ */
+struct GST_BlacklistCheck *
+GST_blacklist_test_allowed (const struct GNUNET_PeerIdentity *peer,
+ const char *transport_name,
+ GST_BlacklistTestContinuation cont, void *cont_cls);
+
+
+/**
+ * Cancel a blacklist check.
+ *
+ * @param bc check to cancel
+ */
+void
+GST_blacklist_test_cancel (struct GST_BlacklistCheck *bc);
+
+#endif
+/* end of file gnunet-service-transport_blacklist.h */
diff --git a/src/transport/gnunet-service-transport_clients.c b/src/transport/gnunet-service-transport_clients.c
new file mode 100644
index 0000000..d6ff554
--- /dev/null
+++ b/src/transport/gnunet-service-transport_clients.c
@@ -0,0 +1,1057 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_clients.c
+ * @brief plugin management API
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-transport_blacklist.h"
+#include "gnunet-service-transport_clients.h"
+#include "gnunet-service-transport_hello.h"
+#include "gnunet-service-transport_neighbours.h"
+#include "gnunet-service-transport_plugins.h"
+#include "gnunet-service-transport_validation.h"
+#include "gnunet-service-transport.h"
+#include "transport.h"
+
+/**
+ * How many messages can we have pending for a given client process
+ * before we start to drop incoming messages? We typically should
+ * have only one client and so this would be the primary buffer for
+ * messages, so the number should be chosen rather generously.
+ *
+ * The expectation here is that most of the time the queue is large
+ * enough so that a drop is virtually never required. Note that
+ * this value must be about as large as 'TOTAL_MSGS' in the
+ * 'test_transport_api_reliability.c', otherwise that testcase may
+ * fail.
+ */
+#define MAX_PENDING (128 * 1024)
+
+
+/**
+ * Linked list of messages to be transmitted to the client. Each
+ * entry is followed by the actual message.
+ */
+struct ClientMessageQueueEntry
+{
+ /**
+ * This is a doubly-linked list.
+ */
+ struct ClientMessageQueueEntry *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct ClientMessageQueueEntry *prev;
+};
+
+
+/**
+ * Client connected to the transport service.
+ */
+struct TransportClient
+{
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct TransportClient *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct TransportClient *prev;
+
+ /**
+ * Handle to the client.
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Linked list of messages yet to be transmitted to
+ * the client.
+ */
+ struct ClientMessageQueueEntry *message_queue_head;
+
+ /**
+ * Tail of linked list of messages yet to be transmitted to the
+ * client.
+ */
+ struct ClientMessageQueueEntry *message_queue_tail;
+
+ /**
+ * Current transmit request handle.
+ */
+ struct GNUNET_CONNECTION_TransmitHandle *th;
+
+ /**
+ * Length of the list of messages pending for this client.
+ */
+ unsigned int message_count;
+
+ /**
+ * Is this client interested in payload messages?
+ */
+ int send_payload;
+};
+
+
+/**
+ * Client monitoring changes of active addresses of our neighbours.
+ */
+struct MonitoringClient
+{
+ /**
+ * This is a doubly-linked list.
+ */
+ struct MonitoringClient *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct MonitoringClient *prev;
+
+ /**
+ * Handle to the client.
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Peer identity to monitor the addresses of.
+ * Zero to monitor all neighrours.
+ */
+ struct GNUNET_PeerIdentity peer;
+
+};
+
+
+/**
+ * Head of linked list of all clients to this service.
+ */
+static struct TransportClient *clients_head;
+
+/**
+ * Tail of linked list of all clients to this service.
+ */
+static struct TransportClient *clients_tail;
+
+/**
+ * Head of linked list of monitoring clients.
+ */
+static struct MonitoringClient *monitoring_clients_head;
+
+/**
+ * Tail of linked list of monitoring clients.
+ */
+static struct MonitoringClient *monitoring_clients_tail;
+
+/**
+ * Notification context, to send updates on changes to active addresses
+ * of our neighbours.
+ */
+struct GNUNET_SERVER_NotificationContext *nc = NULL;
+
+
+/**
+ * Find the internal handle associated with the given client handle
+ *
+ * @param client server's client handle to look up
+ * @return internal client handle
+ */
+static struct TransportClient *
+lookup_client (struct GNUNET_SERVER_Client *client)
+{
+ struct TransportClient *tc;
+
+ tc = clients_head;
+ while (tc != NULL)
+ {
+ if (tc->client == client)
+ return tc;
+ tc = tc->next;
+ }
+ return NULL;
+}
+
+
+/**
+ * Create the internal handle for the given server client handle
+ *
+ * @param client server's client handle to create our internal handle for
+ * @return fresh internal client handle
+ */
+static struct TransportClient *
+setup_client (struct GNUNET_SERVER_Client *client)
+{
+ struct TransportClient *tc;
+
+ GNUNET_assert (lookup_client (client) == NULL);
+ tc = GNUNET_malloc (sizeof (struct TransportClient));
+ tc->client = client;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Client %p connected\n", tc);
+#endif
+ return tc;
+}
+
+
+/**
+ * Find the handle to the monitoring client associated with the given
+ * client handle
+ *
+ * @param client server's client handle to look up
+ * @return handle to the monitoring client
+ */
+static struct MonitoringClient *
+lookup_monitoring_client (struct GNUNET_SERVER_Client *client)
+{
+ struct MonitoringClient *mc;
+
+ mc = monitoring_clients_head;
+ while (mc != NULL)
+ {
+ if (mc->client == client)
+ return mc;
+ mc = mc->next;
+ }
+ return NULL;
+}
+
+
+/**
+ * Setup a new monitoring client using the given server client handle and
+ * the peer identity.
+ *
+ * @param client server's client handle to create our internal handle for
+ * @param peer identity of the peer to monitor the addresses of,
+ * zero to monitor all neighrours.
+ * @return handle to the new monitoring client
+ */
+static struct MonitoringClient *
+setup_monitoring_client (struct GNUNET_SERVER_Client *client,
+ struct GNUNET_PeerIdentity *peer)
+{
+ struct MonitoringClient *mc;
+
+ GNUNET_assert (lookup_monitoring_client (client) == NULL);
+ mc = GNUNET_malloc (sizeof (struct MonitoringClient));
+ mc->client = client;
+ mc->peer = *peer;
+ GNUNET_CONTAINER_DLL_insert (monitoring_clients_head,
+ monitoring_clients_tail,
+ mc);
+ GNUNET_SERVER_notification_context_add (nc, client);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Client %p started monitoring of the peer `%s'\n",
+ mc, GNUNET_i2s (peer));
+ return mc;
+}
+
+
+/**
+ * Function called to notify a client about the socket being ready to
+ * queue more data. "buf" will be NULL and "size" zero if the socket
+ * was closed for writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_to_client_callback (void *cls, size_t size, void *buf)
+{
+ struct TransportClient *tc = cls;
+ struct ClientMessageQueueEntry *q;
+ const struct GNUNET_MessageHeader *msg;
+ char *cbuf;
+ uint16_t msize;
+ size_t tsize;
+
+ tc->th = NULL;
+ if (buf == NULL)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmission to client failed, closing connection.\n");
+#endif
+ return 0;
+ }
+ cbuf = buf;
+ tsize = 0;
+ while (NULL != (q = tc->message_queue_head))
+ {
+ msg = (const struct GNUNET_MessageHeader *) &q[1];
+ msize = ntohs (msg->size);
+ if (msize + tsize > size)
+ break;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting message of type %u to client %p.\n",
+ ntohs (msg->type), tc);
+#endif
+ GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, tc->message_queue_tail,
+ q);
+ tc->message_count--;
+ memcpy (&cbuf[tsize], msg, msize);
+ GNUNET_free (q);
+ tsize += msize;
+ }
+ if (NULL != q)
+ {
+ GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
+ tc->th =
+ GNUNET_SERVER_notify_transmit_ready (tc->client, msize,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_to_client_callback, tc);
+ GNUNET_assert (tc->th != NULL);
+ }
+ return tsize;
+}
+
+
+/**
+ * Queue the given message for transmission to the given client
+ *
+ * @param tc target of the message
+ * @param msg message to transmit
+ * @param may_drop GNUNET_YES if the message can be dropped
+ */
+static void
+unicast (struct TransportClient *tc, const struct GNUNET_MessageHeader *msg,
+ int may_drop)
+{
+ struct ClientMessageQueueEntry *q;
+ uint16_t msize;
+
+ if ((tc->message_count >= MAX_PENDING) && (GNUNET_YES == may_drop))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Dropping message of type %u and size %u, have %u/%u messages pending\n"),
+ ntohs (msg->type), ntohs (msg->size), tc->message_count,
+ MAX_PENDING);
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# messages dropped due to slow client"), 1,
+ GNUNET_NO);
+ return;
+ }
+ msize = ntohs (msg->size);
+ GNUNET_assert (msize >= sizeof (struct GNUNET_MessageHeader));
+ q = GNUNET_malloc (sizeof (struct ClientMessageQueueEntry) + msize);
+ memcpy (&q[1], msg, msize);
+ GNUNET_CONTAINER_DLL_insert_tail (tc->message_queue_head,
+ tc->message_queue_tail, q);
+ tc->message_count++;
+ if (tc->th != NULL)
+ return;
+ tc->th =
+ GNUNET_SERVER_notify_transmit_ready (tc->client, msize,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_to_client_callback, tc);
+ GNUNET_assert (tc->th != NULL);
+}
+
+
+/**
+ * Called whenever a client is disconnected. Frees our
+ * resources associated with that client.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ */
+static void
+client_disconnect_notification (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ struct TransportClient *tc;
+ struct MonitoringClient *mc;
+ struct ClientMessageQueueEntry *mqe;
+
+ if (client == NULL)
+ return;
+ mc = lookup_monitoring_client (client);
+ if (mc != NULL)
+ {
+ GNUNET_CONTAINER_DLL_remove (monitoring_clients_head,
+ monitoring_clients_tail,
+ mc);
+ GNUNET_free (mc);
+ }
+ tc = lookup_client (client);
+ if (tc == NULL)
+ return;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Client %p disconnected, cleaning up.\n", tc);
+#endif
+ while (NULL != (mqe = tc->message_queue_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (tc->message_queue_head, tc->message_queue_tail,
+ mqe);
+ tc->message_count--;
+ GNUNET_free (mqe);
+ }
+ GNUNET_CONTAINER_DLL_remove (clients_head, clients_tail, tc);
+ if (tc->th != NULL)
+ {
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (tc->th);
+ tc->th = NULL;
+ }
+ GNUNET_break (0 == tc->message_count);
+ GNUNET_free (tc);
+}
+
+
+/**
+ * Function called for each of our connected neighbours. Notify the
+ * client about the existing neighbour.
+ *
+ * @param cls the 'struct TransportClient' to notify
+ * @param peer identity of the neighbour
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ * @param address the address
+ */
+static void
+notify_client_about_neighbour (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct TransportClient *tc = cls;
+ struct ConnectInfoMessage *cim;
+ struct GNUNET_ATS_Information *ap;
+ size_t size =
+ sizeof (struct ConnectInfoMessage) +
+ ats_count * sizeof (struct GNUNET_ATS_Information);
+ char buf[size];
+
+ GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ cim = (struct ConnectInfoMessage *) buf;
+ cim->header.size = htons (size);
+ cim->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT);
+ cim->ats_count = htonl (ats_count);
+ cim->id = *peer;
+ ap = (struct GNUNET_ATS_Information *) &cim[1];
+ memcpy (ap, ats, ats_count * sizeof (struct GNUNET_ATS_Information));
+ unicast (tc, &cim->header, GNUNET_NO);
+}
+
+
+/**
+ * Initialize a normal client. We got a start message from this
+ * client, add him to the list of clients for broadcasting of inbound
+ * messages.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the start message that was sent
+ */
+static void
+clients_handle_start (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct StartMessage *start;
+ struct TransportClient *tc;
+ uint32_t options;
+
+ tc = lookup_client (client);
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Client %p sent START\n", tc);
+#endif
+ if (tc != NULL)
+ {
+ /* got 'start' twice from the same client, not allowed */
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "TransportClient %p ServerClient %p sent multiple START messages\n",
+ tc, tc->client);
+#endif
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ start = (const struct StartMessage *) message;
+ options = ntohl (start->options);
+ if ((0 != (1 & options)) &&
+ (0 !=
+ memcmp (&start->self, &GST_my_identity,
+ sizeof (struct GNUNET_PeerIdentity))))
+ {
+ /* client thinks this is a different peer, reject */
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _
+ ("Rejecting control connection from peer `%s', which is not me!\n"),
+ GNUNET_i2s (&start->self));
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ tc = setup_client (client);
+ tc->send_payload = (0 != (2 & options));
+ unicast (tc, GST_hello_get (), GNUNET_NO);
+ GST_neighbours_iterate (&notify_client_about_neighbour, tc);
+ GNUNET_CONTAINER_DLL_insert (clients_head, clients_tail, tc);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Client sent us a HELLO. Process the request.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the HELLO message
+ */
+static void
+clients_handle_hello (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ GST_validation_handle_hello (message);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Closure for 'handle_send_transmit_continuation'
+ */
+struct SendTransmitContinuationContext
+{
+ /**
+ * Client that made the request.
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Peer that was the target.
+ */
+ struct GNUNET_PeerIdentity target;
+};
+
+
+/**
+ * Function called after the transmission is done. Notify the client that it is
+ * OK to send the next message.
+ *
+ * @param cls closure
+ * @param success GNUNET_OK on success, GNUNET_NO on failure, GNUNET_SYSERR if we're not connected
+ */
+static void
+handle_send_transmit_continuation (void *cls, int success)
+{
+ struct SendTransmitContinuationContext *stcc = cls;
+ struct SendOkMessage send_ok_msg;
+
+ send_ok_msg.header.size = htons (sizeof (send_ok_msg));
+ send_ok_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK);
+ send_ok_msg.success = htonl (success);
+ send_ok_msg.latency =
+ GNUNET_TIME_relative_hton (GNUNET_TIME_UNIT_FOREVER_REL);
+ send_ok_msg.peer = stcc->target;
+ GST_clients_unicast (stcc->client, &send_ok_msg.header, GNUNET_NO);
+ GNUNET_SERVER_client_drop (stcc->client);
+ GNUNET_free (stcc);
+}
+
+
+/**
+ * Client asked for transmission to a peer. Process the request.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the send message that was sent
+ */
+static void
+clients_handle_send (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct OutboundMessage *obm;
+ const struct GNUNET_MessageHeader *obmm;
+ struct SendTransmitContinuationContext *stcc;
+ uint16_t size;
+ uint16_t msize;
+ struct TransportClient *tc;
+
+ tc = lookup_client (client);
+ if (NULL == tc)
+ {
+ /* client asked for transmission before 'START' */
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ size = ntohs (message->size);
+ if (size <
+ sizeof (struct OutboundMessage) + sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ obm = (const struct OutboundMessage *) message;
+ obmm = (const struct GNUNET_MessageHeader *) &obm[1];
+ msize = size - sizeof (struct OutboundMessage);
+ if (msize < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# bytes payload received for other peers"), msize,
+ GNUNET_NO);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received `%s' request from client with target `%4s' and first message of type %u and total size %u\n",
+ "SEND", GNUNET_i2s (&obm->peer), ntohs (obmm->type), msize);
+#endif
+ if (GNUNET_NO == GST_neighbours_test_connected (&obm->peer))
+ {
+ /* not connected, not allowed to send; can happen due to asynchronous operations */
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Could not send message to peer `%s': not connected\n",
+ GNUNET_i2s (&obm->peer));
+#endif
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# bytes payload dropped (other peer was not connected)"),
+ msize, GNUNET_NO);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ stcc = GNUNET_malloc (sizeof (struct SendTransmitContinuationContext));
+ stcc->target = obm->peer;
+ stcc->client = client;
+ GNUNET_SERVER_client_keep (client);
+ GST_neighbours_send (&obm->peer, obmm, msize,
+ GNUNET_TIME_relative_ntoh (obm->timeout),
+ &handle_send_transmit_continuation, stcc);
+}
+
+
+/**
+ * Try to initiate a connection to the given peer if the blacklist
+ * allowed it.
+ *
+ * @param cls closure (unused, NULL)
+ * @param peer identity of peer that was tested
+ * @param result GNUNET_OK if the connection is allowed,
+ * GNUNET_NO if not
+ */
+static void
+try_connect_if_allowed (void *cls, const struct GNUNET_PeerIdentity *peer,
+ int result)
+{
+ if (GNUNET_OK != result)
+ return; /* not allowed */
+ GST_neighbours_try_connect (peer);
+}
+
+
+/**
+ * Handle request connect message
+ *
+ * @param cls closure (always NULL)
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+clients_handle_request_connect (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct TransportRequestConnectMessage *trcm =
+ (const struct TransportRequestConnectMessage *) message;
+
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# REQUEST CONNECT messages received"), 1,
+ GNUNET_NO);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received a request connect message for peer `%s'\n",
+ GNUNET_i2s (&trcm->peer));
+#endif
+ (void) GST_blacklist_test_allowed (&trcm->peer, NULL, &try_connect_if_allowed,
+ NULL);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Take the given address and append it to the set of results sent back to
+ * the client.
+ *
+ * @param cls the transmission context used ('struct GNUNET_SERVER_TransmitContext*')
+ * @param buf text to transmit
+ */
+static void
+transmit_address_to_client (void *cls, const char *buf)
+{
+ struct GNUNET_SERVER_TransmitContext *tc = cls;
+
+ if (NULL == buf)
+ {
+ GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
+ GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+ return;
+ }
+ GNUNET_SERVER_transmit_context_append_data (tc, buf, strlen (buf) + 1,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
+}
+
+
+/**
+ * Client asked to resolve an address. Process the request.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the resolution request
+ */
+static void
+clients_handle_address_to_string (void *cls,
+ struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ const struct AddressLookupMessage *alum;
+ struct GNUNET_TRANSPORT_PluginFunctions *papi;
+ const char *plugin_name;
+ const char *address;
+ uint32_t address_len;
+ uint16_t size;
+ struct GNUNET_SERVER_TransmitContext *tc;
+ struct GNUNET_TIME_Relative rtimeout;
+ int32_t numeric;
+
+ size = ntohs (message->size);
+ if (size < sizeof (struct AddressLookupMessage))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ alum = (const struct AddressLookupMessage *) message;
+ address_len = ntohs (alum->addrlen);
+ if (size <= sizeof (struct AddressLookupMessage) + address_len)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ address = (const char *) &alum[1];
+ plugin_name = (const char *) &address[address_len];
+ if (plugin_name[size - sizeof (struct AddressLookupMessage) - address_len - 1]
+ != '\0')
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ rtimeout = GNUNET_TIME_relative_ntoh (alum->timeout);
+ numeric = ntohs (alum->numeric_only);
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ papi = GST_plugins_find (plugin_name);
+ if (NULL == papi)
+ {
+ GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
+ GNUNET_SERVER_transmit_context_run (tc, rtimeout);
+ return;
+ }
+ GNUNET_SERVER_disable_receive_done_warning (client);
+ papi->address_pretty_printer (papi->cls, plugin_name, address, address_len,
+ numeric, rtimeout, &transmit_address_to_client,
+ tc);
+}
+
+
+/**
+ * Compose AddressIterateResponseMessage using the given peer and address.
+ *
+ * @param peer identity of the peer
+ * @param address the address, NULL on disconnect
+ * @return composed message
+ */
+static struct AddressIterateResponseMessage *
+compose_address_iterate_response_message (const struct GNUNET_PeerIdentity
+ *peer,
+ const struct GNUNET_HELLO_Address
+ *address)
+{
+ struct AddressIterateResponseMessage *msg;
+ size_t size;
+ size_t tlen;
+ size_t alen;
+ char *addr;
+
+ GNUNET_assert (NULL != peer);
+ if (NULL != address)
+ {
+ tlen = strlen (address->transport_name) + 1;
+ alen = address->address_length;
+ }
+ else
+ tlen = alen = 0;
+ size = (sizeof (struct AddressIterateResponseMessage) + alen + tlen);
+ msg = GNUNET_malloc (size);
+ msg->header.size = htons (size);
+ msg->header.type =
+ htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE);
+ msg->reserved = htonl (0);
+ msg->peer = *peer;
+ msg->addrlen = htonl (alen);
+ msg->pluginlen = htonl (tlen);
+ if (NULL != address)
+ {
+ addr = (char *) &msg[1];
+ memcpy (addr, address->address, alen);
+ memcpy (&addr[alen], address->transport_name, tlen);
+ }
+ return msg;
+}
+
+
+/**
+ * Output the active address of connected neighbours to the given client.
+ *
+ * @param cls the 'struct GNUNET_SERVER_TransmitContext' for transmission to the client
+ * @param peer identity of the neighbour
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ * @param address the address
+ */
+static void
+output_address (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct GNUNET_SERVER_TransmitContext *tc = cls;
+ struct AddressIterateResponseMessage *msg;
+
+ msg = compose_address_iterate_response_message (peer, address);
+ GNUNET_SERVER_transmit_context_append_message (tc, &msg->header);
+ GNUNET_free (msg);
+}
+
+
+/**
+ * Client asked to obtain information about all actively used addresses
+ * of connected peers
+ * Process the request.
+ *
+ * @param cls unused
+ * @param client the client
+ * @param message the peer address information request
+ */
+static void
+clients_handle_address_iterate (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ static struct GNUNET_PeerIdentity all_zeros;
+ struct GNUNET_SERVER_TransmitContext *tc;
+ struct AddressIterateMessage *msg;
+ struct GNUNET_HELLO_Address *address;
+
+ if (ntohs (message->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE)
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ if (ntohs (message->size) != sizeof (struct AddressIterateMessage))
+ {
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ msg = (struct AddressIterateMessage *) message;
+ if ( (GNUNET_YES != ntohl (msg->one_shot)) &&
+ (NULL != lookup_monitoring_client (client)) )
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "ServerClient %p tried to start monitoring twice\n",
+ client);
+ GNUNET_break (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_SERVER_disable_receive_done_warning (client);
+ tc = GNUNET_SERVER_transmit_context_create (client);
+ if (0 == memcmp (&msg->peer, &all_zeros, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ /* iterate over all neighbours */
+ GST_neighbours_iterate (&output_address, tc);
+ }
+ else
+ {
+ /* just return one neighbour */
+ address = GST_neighbour_get_current_address (&msg->peer);
+ if (address != NULL)
+ output_address (tc, &msg->peer, NULL, 0, address);
+ }
+ if (GNUNET_YES != ntohl (msg->one_shot))
+ setup_monitoring_client (client, &msg->peer);
+ else
+ GNUNET_SERVER_transmit_context_append_data (tc, NULL, 0,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE);
+ GNUNET_SERVER_transmit_context_run (tc, GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+/**
+ * Start handling requests from clients.
+ *
+ * @param server server used to accept clients from.
+ */
+void
+GST_clients_start (struct GNUNET_SERVER_Handle *server)
+{
+ static const struct GNUNET_SERVER_MessageHandler handlers[] = {
+ {&clients_handle_start, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_START, sizeof (struct StartMessage)},
+ {&clients_handle_hello, NULL,
+ GNUNET_MESSAGE_TYPE_HELLO, 0},
+ {&clients_handle_send, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_SEND, 0},
+ {&clients_handle_request_connect, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT,
+ sizeof (struct TransportRequestConnectMessage)},
+ {&clients_handle_address_to_string, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING, 0},
+ {&clients_handle_address_iterate, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE,
+ sizeof (struct AddressIterateMessage)},
+ {&GST_blacklist_handle_init, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT,
+ sizeof (struct GNUNET_MessageHeader)},
+ {&GST_blacklist_handle_reply, NULL,
+ GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY,
+ sizeof (struct BlacklistMessage)},
+ {NULL, NULL, 0, 0}
+ };
+ nc = GNUNET_SERVER_notification_context_create (server, 0);
+ GNUNET_SERVER_add_handlers (server, handlers);
+ GNUNET_SERVER_disconnect_notify (server, &client_disconnect_notification,
+ NULL);
+}
+
+
+/**
+ * Stop processing clients.
+ */
+void
+GST_clients_stop ()
+{
+ if (NULL != nc)
+ {
+ GNUNET_SERVER_notification_context_destroy (nc);
+ nc = NULL;
+ }
+}
+
+
+/**
+ * Broadcast the given message to all of our clients.
+ *
+ * @param msg message to broadcast
+ * @param may_drop GNUNET_YES if the message can be dropped / is payload
+ */
+void
+GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, int may_drop)
+{
+ struct TransportClient *tc;
+
+ for (tc = clients_head; tc != NULL; tc = tc->next)
+ {
+ if ((GNUNET_YES == may_drop) && (GNUNET_YES != tc->send_payload))
+ continue; /* skip, this client does not care about payload */
+ unicast (tc, msg, may_drop);
+ }
+}
+
+
+/**
+ * Send the given message to a particular client
+ *
+ * @param client target of the message
+ * @param msg message to transmit
+ * @param may_drop GNUNET_YES if the message can be dropped
+ */
+void
+GST_clients_unicast (struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *msg, int may_drop)
+{
+ struct TransportClient *tc;
+
+ tc = lookup_client (client);
+ if (NULL == tc)
+ return; /* client got disconnected in the meantime, drop message */
+ unicast (tc, msg, may_drop);
+}
+
+
+/**
+ * Broadcast the new active address to all clients monitoring the peer.
+ *
+ * @param peer peer this update is about (never NULL)
+ * @param address address, NULL on disconnect
+ */
+void
+GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity
+ *peer,
+ const struct GNUNET_HELLO_Address
+ *address)
+{
+ struct AddressIterateResponseMessage *msg;
+ struct MonitoringClient *mc;
+ static struct GNUNET_PeerIdentity all_zeros;
+
+ msg = compose_address_iterate_response_message (peer, address);
+ mc = monitoring_clients_head;
+ while (mc != NULL)
+ {
+ if ((0 == memcmp (&mc->peer, &all_zeros,
+ sizeof (struct GNUNET_PeerIdentity))) ||
+ (0 == memcmp (&mc->peer, peer,
+ sizeof (struct GNUNET_PeerIdentity))))
+ {
+ GNUNET_SERVER_notification_context_unicast (nc, mc->client,
+ &msg->header, GNUNET_NO);
+ }
+
+ mc = mc->next;
+ }
+ GNUNET_free (msg);
+}
+
+
+/* end of file gnunet-service-transport_clients.c */
diff --git a/src/transport/gnunet-service-transport_clients.h b/src/transport/gnunet-service-transport_clients.h
new file mode 100644
index 0000000..9556620
--- /dev/null
+++ b/src/transport/gnunet-service-transport_clients.h
@@ -0,0 +1,86 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_clients.h
+ * @brief plugin management API
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_TRANSPORT_CLIENTS_H
+#define GNUNET_SERVICE_TRANSPORT_CLIENTS_H
+
+#include "gnunet_statistics_service.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
+
+
+/**
+ * Start handling requests from clients.
+ *
+ * @param server server used to accept clients from.
+ */
+void
+GST_clients_start (struct GNUNET_SERVER_Handle *server);
+
+
+/**
+ * Stop processing clients.
+ */
+void
+GST_clients_stop (void);
+
+
+/**
+ * Broadcast the given message to all of our clients.
+ *
+ * @param msg message to broadcast
+ * @param may_drop GNUNET_YES if the message can be dropped / is payload
+ */
+void
+GST_clients_broadcast (const struct GNUNET_MessageHeader *msg, int may_drop);
+
+
+/**
+ * Send the given message to a particular client
+ *
+ * @param client target of the message
+ * @param msg message to transmit
+ * @param may_drop GNUNET_YES if the message can be dropped
+ */
+void
+GST_clients_unicast (struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *msg, int may_drop);
+
+
+/**
+ * Broadcast the new active address to all clients monitoring the peer.
+ *
+ * @param peer peer this update is about (never NULL)
+ * @param address address, NULL on disconnect
+ */
+void
+GST_clients_broadcast_address_notification (const struct GNUNET_PeerIdentity
+ *peer,
+ const struct GNUNET_HELLO_Address
+ *address);
+
+
+#endif
+/* end of file gnunet-service-transport_clients.h */
diff --git a/src/transport/gnunet-service-transport_hello.c b/src/transport/gnunet-service-transport_hello.c
new file mode 100644
index 0000000..120f176
--- /dev/null
+++ b/src/transport/gnunet-service-transport_hello.c
@@ -0,0 +1,318 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_hello.c
+ * @brief hello management implementation
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_constants.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_peerinfo_service.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet-service-transport_hello.h"
+#include "gnunet-service-transport.h"
+#include "gnunet-service-transport_plugins.h"
+
+
+/**
+ * How often do we refresh our HELLO (due to expiration concerns)?
+ */
+#define HELLO_REFRESH_PERIOD GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
+
+
+/**
+ * Entry in linked list of network addresses for ourselves. Also
+ * includes a cached signature for 'struct TransportPongMessage's.
+ */
+struct OwnAddressList
+{
+ /**
+ * This is a doubly-linked list.
+ */
+ struct OwnAddressList *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct OwnAddressList *prev;
+
+ /**
+ * The address.
+ */
+ struct GNUNET_HELLO_Address *address;
+
+ /**
+ * How long until the current signature expires? (ZERO if the
+ * signature was never created).
+ */
+ struct GNUNET_TIME_Absolute pong_sig_expires;
+
+ /**
+ * Signature for a 'struct TransportPongMessage' for this address.
+ */
+ struct GNUNET_CRYPTO_RsaSignature pong_signature;
+
+};
+
+
+/**
+ * Our HELLO message.
+ */
+static struct GNUNET_HELLO_Message *our_hello;
+
+/**
+ * Function to call on HELLO changes.
+ */
+static GST_HelloCallback hello_cb;
+
+/**
+ * Closure for 'hello_cb'.
+ */
+static void *hello_cb_cls;
+
+/**
+ * Head of my addresses.
+ */
+struct OwnAddressList *oal_head;
+
+/**
+ * Tail of my addresses.
+ */
+struct OwnAddressList *oal_tail;
+
+/**
+ * Identifier of 'refresh_hello' task.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier hello_task;
+
+
+/**
+ * Closure for 'address_generator'.
+ */
+struct GeneratorContext
+{
+ /**
+ * Where are we in the DLL?
+ */
+ struct OwnAddressList *addr_pos;
+
+ /**
+ * When do addresses expire?
+ */
+ struct GNUNET_TIME_Absolute expiration;
+};
+
+
+/**
+ * Add an address from the 'OwnAddressList' to the buffer.
+ *
+ * @param cls the 'struct GeneratorContext'
+ * @param max maximum number of bytes left
+ * @param buf where to write the address
+ */
+static size_t
+address_generator (void *cls, size_t max, void *buf)
+{
+ struct GeneratorContext *gc = cls;
+ size_t ret;
+
+ if (NULL == gc->addr_pos)
+ return 0;
+ ret =
+ GNUNET_HELLO_add_address (gc->addr_pos->address, gc->expiration, buf,
+ max);
+ gc->addr_pos = gc->addr_pos->next;
+ return ret;
+}
+
+
+/**
+ * Construct our HELLO message from all of the addresses of
+ * all of the transports.
+ *
+ * @param cls unused
+ * @param tc scheduler context
+ */
+static void
+refresh_hello_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GeneratorContext gc;
+
+ hello_task = GNUNET_SCHEDULER_NO_TASK;
+ gc.addr_pos = oal_head;
+ gc.expiration =
+ GNUNET_TIME_relative_to_absolute
+ (GNUNET_CONSTANTS_HELLO_ADDRESS_EXPIRATION);
+ GNUNET_free (our_hello);
+ our_hello = GNUNET_HELLO_create (&GST_my_public_key, &address_generator, &gc);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "Refreshed my `%s', new size is %d\n", "HELLO",
+ GNUNET_HELLO_size (our_hello));
+#endif
+ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# refreshed my HELLO"), 1,
+ GNUNET_NO);
+ if (NULL != hello_cb)
+ hello_cb (hello_cb_cls, GST_hello_get ());
+ GNUNET_PEERINFO_add_peer (GST_peerinfo, our_hello);
+ hello_task =
+ GNUNET_SCHEDULER_add_delayed (HELLO_REFRESH_PERIOD, &refresh_hello_task,
+ NULL);
+
+}
+
+
+/**
+ * Schedule task to refresh hello (unless such a
+ * task exists already).
+ */
+static void
+refresh_hello ()
+{
+ if (hello_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (hello_task);
+ hello_task = GNUNET_SCHEDULER_add_now (&refresh_hello_task, NULL);
+}
+
+
+/**
+ * Initialize the HELLO module.
+ *
+ * @param cb function to call whenever our HELLO changes
+ * @param cb_cls closure for cb
+ */
+void
+GST_hello_start (GST_HelloCallback cb, void *cb_cls)
+{
+ hello_cb = cb;
+ hello_cb_cls = cb_cls;
+ our_hello = GNUNET_HELLO_create (&GST_my_public_key, NULL, NULL);
+ refresh_hello ();
+}
+
+
+/**
+ * Shutdown the HELLO module.
+ */
+void
+GST_hello_stop ()
+{
+ hello_cb = NULL;
+ hello_cb_cls = NULL;
+ if (GNUNET_SCHEDULER_NO_TASK != hello_task)
+ {
+ GNUNET_SCHEDULER_cancel (hello_task);
+ hello_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != our_hello)
+ {
+ GNUNET_free (our_hello);
+ our_hello = NULL;
+ }
+}
+
+
+/**
+ * Obtain this peers HELLO message.
+ *
+ * @return our HELLO message
+ */
+const struct GNUNET_MessageHeader *
+GST_hello_get ()
+{
+ return (struct GNUNET_MessageHeader *) our_hello;
+}
+
+
+/**
+ * Add or remove an address from this peer's HELLO message.
+ *
+ * @param addremove GNUNET_YES to add, GNUNET_NO to remove
+ * @param address address to add or remove
+ */
+void
+GST_hello_modify_addresses (int addremove,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct OwnAddressList *al;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ (add_remove ==
+ GNUNET_YES) ? "Adding `%s':%s to the set of our addresses\n" :
+ "Removing `%s':%s from the set of our addresses\n",
+ GST_plugins_a2s (address), p->short_name);
+#endif
+ GNUNET_assert (address != NULL);
+ if (GNUNET_NO == addremove)
+ {
+ for (al = oal_head; al != NULL; al = al->next)
+ if (0 == GNUNET_HELLO_address_cmp (address, al->address))
+ {
+ GNUNET_CONTAINER_DLL_remove (oal_head, oal_tail, al);
+ GNUNET_HELLO_address_free (al->address);
+ GNUNET_free (al);
+ refresh_hello ();
+ return;
+ }
+ /* address to be removed not found!? */
+ GNUNET_break (0);
+ return;
+ }
+ al = GNUNET_malloc (sizeof (struct OwnAddressList));
+ GNUNET_CONTAINER_DLL_insert (oal_head, oal_tail, al);
+ al->address = GNUNET_HELLO_address_copy (address);
+ refresh_hello ();
+}
+
+
+/**
+ * Test if a particular address is one of ours.
+ *
+ * @param address address to test
+ * @param sig location where to cache PONG signatures for this address [set]
+ * @param sig_expiration how long until the current 'sig' expires?
+ * (ZERO if sig was never created) [set]
+ * @return GNUNET_YES if this is one of our addresses,
+ * GNUNET_NO if not
+ */
+int
+GST_hello_test_address (const struct GNUNET_HELLO_Address *address,
+ struct GNUNET_CRYPTO_RsaSignature **sig,
+ struct GNUNET_TIME_Absolute **sig_expiration)
+{
+ struct OwnAddressList *al;
+
+ for (al = oal_head; al != NULL; al = al->next)
+ if (0 == GNUNET_HELLO_address_cmp (address, al->address))
+ {
+ *sig = &al->pong_signature;
+ *sig_expiration = &al->pong_sig_expires;
+ return GNUNET_YES;
+ }
+ *sig = NULL;
+ *sig_expiration = NULL;
+ return GNUNET_NO;
+}
+
+
+/* end of file gnunet-service-transport_hello.c */
diff --git a/src/transport/gnunet-service-transport_hello.h b/src/transport/gnunet-service-transport_hello.h
new file mode 100644
index 0000000..605d198
--- /dev/null
+++ b/src/transport/gnunet-service-transport_hello.h
@@ -0,0 +1,100 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_hello.h
+ * @brief hello API
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_TRANSPORT_HELLO_H
+#define GNUNET_SERVICE_TRANSPORT_HELLO_H
+
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
+
+
+
+/**
+ * Signature of a function to call whenever our hello changes.
+ *
+ * @param cls closure
+ * @param hello updated HELLO
+ */
+typedef void (*GST_HelloCallback) (void *cls,
+ const struct GNUNET_MessageHeader * hello);
+
+
+/**
+ * Initialize the HELLO module.
+ *
+ * @param cb function to call whenever our HELLO changes
+ * @param cb_cls closure for cb
+ */
+void
+GST_hello_start (GST_HelloCallback cb, void *cb_cls);
+
+
+/**
+ * Shutdown the HELLO module.
+ */
+void
+GST_hello_stop (void);
+
+
+/**
+ * Obtain this peers HELLO message.
+ *
+ * @return our HELLO message
+ */
+const struct GNUNET_MessageHeader *
+GST_hello_get (void);
+
+
+/**
+ * Add or remove an address from this peer's HELLO message.
+ *
+ * @param addremove GNUNET_YES to add, GNUNET_NO to remove
+ * @param address address to add or remove
+ */
+void
+GST_hello_modify_addresses (int addremove,
+ const struct GNUNET_HELLO_Address *address);
+
+
+/**
+ * Test if a particular address is one of ours.
+ *
+ * @param address the address to test
+ * @param sig location where to cache PONG signatures for this address [set]
+ * @param sig_expiration how long until the current 'sig' expires?
+ * (ZERO if sig was never created) [set]
+ * @return GNUNET_YES if this is one of our addresses,
+ * GNUNET_NO if not
+ */
+int
+GST_hello_test_address (const struct GNUNET_HELLO_Address *address,
+ struct GNUNET_CRYPTO_RsaSignature **sig,
+ struct GNUNET_TIME_Absolute **sig_expiration);
+
+
+#endif
+/* end of file gnunet-service-transport_hello.h */
diff --git a/src/transport/gnunet-service-transport_neighbours.c b/src/transport/gnunet-service-transport_neighbours.c
new file mode 100644
index 0000000..3e8ef5a
--- /dev/null
+++ b/src/transport/gnunet-service-transport_neighbours.c
@@ -0,0 +1,2721 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_neighbours.c
+ * @brief neighbour management
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_ats_service.h"
+#include "gnunet-service-transport_neighbours.h"
+#include "gnunet-service-transport_plugins.h"
+#include "gnunet-service-transport_validation.h"
+#include "gnunet-service-transport_clients.h"
+#include "gnunet-service-transport.h"
+#include "gnunet_peerinfo_service.h"
+#include "gnunet-service-transport_blacklist.h"
+#include "gnunet_constants.h"
+#include "transport.h"
+
+
+/**
+ * Size of the neighbour hash map.
+ */
+#define NEIGHBOUR_TABLE_SIZE 256
+
+/**
+ * How often must a peer violate bandwidth quotas before we start
+ * to simply drop its messages?
+ */
+#define QUOTA_VIOLATION_DROP_THRESHOLD 10
+
+/**
+ * How often do we send KEEPALIVE messages to each of our neighbours and measure
+ * the latency with this neighbour?
+ * (idle timeout is 5 minutes or 300 seconds, so with 30s interval we
+ * send 10 keepalives in each interval, so 10 messages would need to be
+ * lost in a row for a disconnect).
+ */
+#define KEEPALIVE_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
+
+
+#define ATS_RESPONSE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+#define FAST_RECONNECT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
+
+#define SETUP_CONNECTION_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+#define TEST_NEW_CODE GNUNET_NO
+
+/**
+ * Entry in neighbours.
+ */
+struct NeighbourMapEntry;
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Message a peer sends to another to indicate its
+ * preference for communicating via a particular
+ * session (and the desire to establish a real
+ * connection).
+ */
+struct SessionConnectMessage
+{
+ /**
+ * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT'
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Always zero.
+ */
+ uint32_t reserved GNUNET_PACKED;
+
+ /**
+ * Absolute time at the sender. Only the most recent connect
+ * message implies which session is preferred by the sender.
+ */
+ struct GNUNET_TIME_AbsoluteNBO timestamp;
+
+};
+
+
+struct SessionDisconnectMessage
+{
+ /**
+ * Header of type 'GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT'
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Always zero.
+ */
+ uint32_t reserved GNUNET_PACKED;
+
+ /**
+ * Purpose of the signature. Extends over the timestamp.
+ * Purpose should be GNUNET_SIGNATURE_PURPOSE_TRANSPORT_DISCONNECT.
+ */
+ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
+
+ /**
+ * Absolute time at the sender. Only the most recent connect
+ * message implies which session is preferred by the sender.
+ */
+ struct GNUNET_TIME_AbsoluteNBO timestamp;
+
+ /**
+ * Public key of the sender.
+ */
+ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
+
+ /**
+ * Signature of the peer that sends us the disconnect. Only
+ * valid if the timestamp is AFTER the timestamp from the
+ * corresponding 'CONNECT' message.
+ */
+ struct GNUNET_CRYPTO_RsaSignature signature;
+
+};
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * For each neighbour we keep a list of messages
+ * that we still want to transmit to the neighbour.
+ */
+struct MessageQueue
+{
+
+ /**
+ * This is a doubly linked list.
+ */
+ struct MessageQueue *next;
+
+ /**
+ * This is a doubly linked list.
+ */
+ struct MessageQueue *prev;
+
+ /**
+ * Once this message is actively being transmitted, which
+ * neighbour is it associated with?
+ */
+ struct NeighbourMapEntry *n;
+
+ /**
+ * Function to call once we're done.
+ */
+ GST_NeighbourSendContinuation cont;
+
+ /**
+ * Closure for 'cont'
+ */
+ void *cont_cls;
+
+ /**
+ * The message(s) we want to transmit, GNUNET_MessageHeader(s)
+ * stuck together in memory. Allocated at the end of this struct.
+ */
+ const char *message_buf;
+
+ /**
+ * Size of the message buf
+ */
+ size_t message_buf_size;
+
+ /**
+ * At what time should we fail?
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+};
+
+
+enum State
+{
+ /**
+ * fresh peer or completely disconnected
+ */
+ S_NOT_CONNECTED,
+
+ /**
+ * sent CONNECT message to other peer, waiting for CONNECT_ACK
+ */
+ S_CONNECT_SENT,
+
+ /**
+ * received CONNECT message to other peer, sending CONNECT_ACK
+ */
+ S_CONNECT_RECV,
+
+ /**
+ * received ACK or payload
+ */
+ S_CONNECTED,
+
+ /**
+ * connection ended, fast reconnect
+ */
+ S_FAST_RECONNECT,
+
+ /**
+ * Disconnect in progress
+ */
+ S_DISCONNECT
+};
+
+enum Address_State
+{
+ USED,
+ UNUSED,
+ FRESH,
+};
+
+
+/**
+ * Entry in neighbours.
+ */
+struct NeighbourMapEntry
+{
+
+ /**
+ * Head of list of messages we would like to send to this peer;
+ * must contain at most one message per client.
+ */
+ struct MessageQueue *messages_head;
+
+ /**
+ * Tail of list of messages we would like to send to this peer; must
+ * contain at most one message per client.
+ */
+ struct MessageQueue *messages_tail;
+
+ /**
+ * Are we currently trying to send a message? If so, which one?
+ */
+ struct MessageQueue *is_active;
+
+ /**
+ * Active session for communicating with the peer.
+ */
+ struct Session *session;
+
+ /**
+ * Address we currently use.
+ */
+ struct GNUNET_HELLO_Address *address;
+
+ /**
+ * Identity of this neighbour.
+ */
+ struct GNUNET_PeerIdentity id;
+
+ /**
+ * ID of task scheduled to run when this peer is about to
+ * time out (will free resources associated with the peer).
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * ID of task scheduled to send keepalives.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier keepalive_task;
+
+ /**
+ * ID of task scheduled to run when we should try transmitting
+ * the head of the message queue.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier transmission_task;
+
+ /**
+ * Tracker for inbound bandwidth.
+ */
+ struct GNUNET_BANDWIDTH_Tracker in_tracker;
+
+ /**
+ * Inbound bandwidth from ATS, activated when connection is up
+ */
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in;
+
+ /**
+ * Inbound bandwidth from ATS, activated when connection is up
+ */
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out;
+
+ /**
+ * Timestamp of the 'SESSION_CONNECT' message we got from the other peer
+ */
+ struct GNUNET_TIME_Absolute connect_ts;
+
+ /**
+ * When did we sent the last keep-alive message?
+ */
+ struct GNUNET_TIME_Absolute keep_alive_sent;
+
+ /**
+ * Latest calculated latency value
+ */
+ struct GNUNET_TIME_Relative latency;
+
+ /**
+ * Timeout for ATS
+ * We asked ATS for a new address for this peer
+ */
+ GNUNET_SCHEDULER_TaskIdentifier ats_suggest;
+
+ /**
+ * Task the resets the peer state after due to an pending
+ * unsuccessful connection setup
+ */
+ GNUNET_SCHEDULER_TaskIdentifier state_reset;
+
+
+ /**
+ * How often has the other peer (recently) violated the inbound
+ * traffic limit? Incremented by 10 per violation, decremented by 1
+ * per non-violation (for each time interval).
+ */
+ unsigned int quota_violation_count;
+
+
+ /**
+ * The current state of the peer
+ * Element of enum State
+ */
+ int state;
+
+ /**
+ * Did we sent an KEEP_ALIVE message and are we expecting a response?
+ */
+ int expect_latency_response;
+ int address_state;
+};
+
+
+/**
+ * All known neighbours and their HELLOs.
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *neighbours;
+
+/**
+ * Closure for connect_notify_cb, disconnect_notify_cb and address_change_cb
+ */
+static void *callback_cls;
+
+/**
+ * Function to call when we connected to a neighbour.
+ */
+static GNUNET_TRANSPORT_NotifyConnect connect_notify_cb;
+
+/**
+ * Function to call when we disconnected from a neighbour.
+ */
+static GNUNET_TRANSPORT_NotifyDisconnect disconnect_notify_cb;
+
+/**
+ * Function to call when we changed an active address of a neighbour.
+ */
+static GNUNET_TRANSPORT_PeerIterateCallback address_change_cb;
+
+/**
+ * counter for connected neighbours
+ */
+static int neighbours_connected;
+
+/**
+ * Lookup a neighbour entry in the neighbours hash map.
+ *
+ * @param pid identity of the peer to look up
+ * @return the entry, NULL if there is no existing record
+ */
+static struct NeighbourMapEntry *
+lookup_neighbour (const struct GNUNET_PeerIdentity *pid)
+{
+ return GNUNET_CONTAINER_multihashmap_get (neighbours, &pid->hashPubKey);
+}
+
+/**
+ * Disconnect from the given neighbour, clean up the record.
+ *
+ * @param n neighbour to disconnect from
+ */
+static void
+disconnect_neighbour (struct NeighbourMapEntry *n);
+
+#define change_state(n, state, ...) change (n, state, __LINE__)
+
+static int
+is_connecting (struct NeighbourMapEntry *n)
+{
+ if ((n->state > S_NOT_CONNECTED) && (n->state < S_CONNECTED))
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+static int
+is_connected (struct NeighbourMapEntry *n)
+{
+ if (n->state == S_CONNECTED)
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+static int
+is_disconnecting (struct NeighbourMapEntry *n)
+{
+ if (n->state == S_DISCONNECT)
+ return GNUNET_YES;
+ return GNUNET_NO;
+}
+
+static const char *
+print_state (int state)
+{
+ switch (state)
+ {
+ case S_CONNECTED:
+ return "S_CONNECTED";
+ break;
+ case S_CONNECT_RECV:
+ return "S_CONNECT_RECV";
+ break;
+ case S_CONNECT_SENT:
+ return "S_CONNECT_SENT";
+ break;
+ case S_DISCONNECT:
+ return "S_DISCONNECT";
+ break;
+ case S_NOT_CONNECTED:
+ return "S_NOT_CONNECTED";
+ break;
+ case S_FAST_RECONNECT:
+ return "S_FAST_RECONNECT";
+ break;
+ default:
+ GNUNET_break (0);
+ break;
+ }
+ return NULL;
+}
+
+static int
+change (struct NeighbourMapEntry *n, int state, int line);
+
+static void
+ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+static void
+reset_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct NeighbourMapEntry *n = cls;
+
+ if (n == NULL)
+ return;
+
+ n->state_reset = GNUNET_SCHEDULER_NO_TASK;
+ if (n->state == S_CONNECTED)
+ return;
+
+#if DEBUG_TRANSPORT
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# failed connection attempts due to timeout"), 1,
+ GNUNET_NO);
+#endif
+
+ /* resetting state */
+
+ if (n->state == S_FAST_RECONNECT)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Fast reconnect time out, disconnecting peer `%s'\n",
+ GNUNET_i2s (&n->id));
+ disconnect_neighbour(n);
+ return;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n",
+ GNUNET_i2s (&n->id), n, print_state(n->state), "S_NOT_CONNECTED", __LINE__);
+
+ n->state = S_NOT_CONNECTED;
+
+ /* destroying address */
+ if (n->address != NULL)
+ {
+ GNUNET_assert (strlen (n->address->transport_name) > 0);
+ GNUNET_ATS_address_destroyed (GST_ats, n->address, n->session);
+ }
+
+ /* request new address */
+ if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->ats_suggest);
+ n->ats_suggest =
+ GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
+ n);
+ GNUNET_ATS_suggest_address (GST_ats, &n->id);
+}
+
+static int
+change (struct NeighbourMapEntry *n, int state, int line)
+{
+ int previous_state;
+ /* allowed transitions */
+ int allowed = GNUNET_NO;
+
+ previous_state = n->state;
+
+ switch (n->state)
+ {
+ case S_NOT_CONNECTED:
+ if ((state == S_CONNECT_RECV) || (state == S_CONNECT_SENT) ||
+ (state == S_DISCONNECT))
+ allowed = GNUNET_YES;
+ break;
+ case S_CONNECT_RECV:
+ allowed = GNUNET_YES;
+ break;
+ case S_CONNECT_SENT:
+ allowed = GNUNET_YES;
+ break;
+ case S_CONNECTED:
+ if ((state == S_DISCONNECT) || (state == S_FAST_RECONNECT))
+ allowed = GNUNET_YES;
+ break;
+ case S_DISCONNECT:
+ break;
+ case S_FAST_RECONNECT:
+ if ((state == S_CONNECTED) || (state == S_DISCONNECT))
+ allowed = GNUNET_YES;
+ break;
+ default:
+ GNUNET_break (0);
+ break;
+ }
+ if (allowed == GNUNET_NO)
+ {
+ char *old = GNUNET_strdup (print_state (n->state));
+ char *new = GNUNET_strdup (print_state (state));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Illegal state transition from `%s' to `%s' in line %u \n", old,
+ new, line);
+ GNUNET_break (0);
+ GNUNET_free (old);
+ GNUNET_free (new);
+ return GNUNET_SYSERR;
+ }
+ {
+ char *old = GNUNET_strdup (print_state (n->state));
+ char *new = GNUNET_strdup (print_state (state));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "State for neighbour `%s' %X changed from `%s' to `%s' in line %u\n",
+ GNUNET_i2s (&n->id), n, old, new, line);
+ GNUNET_free (old);
+ GNUNET_free (new);
+ }
+ n->state = state;
+
+ switch (n->state)
+ {
+ case S_FAST_RECONNECT:
+ case S_CONNECT_RECV:
+ case S_CONNECT_SENT:
+ if (n->state_reset != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->state_reset);
+ n->state_reset =
+ GNUNET_SCHEDULER_add_delayed (SETUP_CONNECTION_TIMEOUT, &reset_task, n);
+ break;
+ case S_CONNECTED:
+ case S_NOT_CONNECTED:
+ case S_DISCONNECT:
+ if (GNUNET_SCHEDULER_NO_TASK != n->state_reset)
+ {
+#if DEBUG_TRANSPORT
+ char *old = GNUNET_strdup (print_state (n->state));
+ char *new = GNUNET_strdup (print_state (state));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Removed reset task for peer `%s' %s failed in state transition `%s' -> `%s' \n",
+ GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), old, new);
+ GNUNET_free (old);
+ GNUNET_free (new);
+#endif
+ GNUNET_assert (n->state_reset != GNUNET_SCHEDULER_NO_TASK);
+ GNUNET_SCHEDULER_cancel (n->state_reset);
+ n->state_reset = GNUNET_SCHEDULER_NO_TASK;
+ }
+ break;
+
+ default:
+ GNUNET_assert (0);
+ }
+
+ if (NULL != address_change_cb)
+ {
+ if (n->state == S_CONNECTED)
+ address_change_cb (callback_cls, &n->id, n->address);
+ else if (previous_state == S_CONNECTED)
+ address_change_cb (callback_cls, &n->id, NULL);
+ }
+
+ return GNUNET_OK;
+}
+
+static ssize_t
+send_with_session (struct NeighbourMapEntry *n,
+ const char *msgbuf, size_t msgbuf_size,
+ uint32_t priority,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct GNUNET_TRANSPORT_PluginFunctions *papi;
+ size_t ret = GNUNET_SYSERR;
+
+ GNUNET_assert (n != NULL);
+ GNUNET_assert (n->session != NULL);
+
+ papi = GST_plugins_find (n->address->transport_name);
+ if (papi == NULL)
+ {
+ if (cont != NULL)
+ cont (cont_cls, &n->id, GNUNET_SYSERR);
+ return GNUNET_SYSERR;
+ }
+
+ ret = papi->send (papi->cls,
+ n->session,
+ msgbuf, msgbuf_size,
+ 0,
+ timeout,
+ cont, cont_cls);
+
+ if ((ret == -1) && (cont != NULL))
+ cont (cont_cls, &n->id, GNUNET_SYSERR);
+ return ret;
+}
+
+/**
+ * Task invoked to start a transmission to another peer.
+ *
+ * @param cls the 'struct NeighbourMapEntry'
+ * @param tc scheduler context
+ */
+static void
+transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+
+/**
+ * We're done with our transmission attempt, continue processing.
+ *
+ * @param cls the 'struct MessageQueue' of the message
+ * @param receiver intended receiver
+ * @param success whether it worked or not
+ */
+static void
+transmit_send_continuation (void *cls,
+ const struct GNUNET_PeerIdentity *receiver,
+ int success)
+{
+ struct MessageQueue *mq = cls;
+ struct NeighbourMapEntry *n;
+ struct NeighbourMapEntry *tmp;
+
+ tmp = lookup_neighbour (receiver);
+ n = mq->n;
+ if ((NULL != n) && (tmp != NULL) && (tmp == n))
+ {
+ GNUNET_assert (n->is_active == mq);
+ n->is_active = NULL;
+ if (success == GNUNET_YES)
+ {
+ GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
+ n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
+ }
+ }
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message of type %u was %s\n",
+ ntohs (((struct GNUNET_MessageHeader *) mq->message_buf)->type),
+ (success == GNUNET_OK) ? "successful" : "FAILED");
+#endif
+ if (NULL != mq->cont)
+ mq->cont (mq->cont_cls, success);
+ GNUNET_free (mq);
+}
+
+
+/**
+ * Check the ready list for the given neighbour and if a plugin is
+ * ready for transmission (and if we have a message), do so!
+ *
+ * @param n target peer for which to transmit
+ */
+static void
+try_transmission_to_peer (struct NeighbourMapEntry *n)
+{
+ struct MessageQueue *mq;
+ struct GNUNET_TIME_Relative timeout;
+ ssize_t ret;
+
+ if (n->is_active != NULL)
+ {
+ GNUNET_break (0);
+ return; /* transmission already pending */
+ }
+ if (n->transmission_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_break (0);
+ return; /* currently waiting for bandwidth */
+ }
+ while (NULL != (mq = n->messages_head))
+ {
+ timeout = GNUNET_TIME_absolute_get_remaining (mq->timeout);
+ if (timeout.rel_value > 0)
+ break;
+ GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
+ n->is_active = mq;
+ mq->n = n;
+ transmit_send_continuation (mq, &n->id, GNUNET_SYSERR); /* timeout */
+ }
+ if (NULL == mq)
+ return; /* no more messages */
+
+ if (n->address == NULL)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No address for peer `%s'\n",
+ GNUNET_i2s (&n->id));
+#endif
+ GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
+ transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
+ GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
+ n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
+ return;
+ }
+
+ if (GST_plugins_find (n->address->transport_name) == NULL)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
+ n->is_active = mq;
+ mq->n = n;
+
+ if ((n->address->address_length == 0) && (n->session == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "No address for peer `%s'\n",
+ GNUNET_i2s (&n->id));
+ transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
+ GNUNET_assert (n->transmission_task == GNUNET_SCHEDULER_NO_TASK);
+ n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
+ return;
+ }
+
+ ret = send_with_session(n,
+ mq->message_buf, mq->message_buf_size,
+ 0, timeout,
+ &transmit_send_continuation, mq);
+
+ if (ret == -1)
+ {
+ /* failure, but 'send' would not call continuation in this case,
+ * so we need to do it here! */
+ transmit_send_continuation (mq, &n->id, GNUNET_SYSERR);
+ }
+
+}
+
+
+/**
+ * Task invoked to start a transmission to another peer.
+ *
+ * @param cls the 'struct NeighbourMapEntry'
+ * @param tc scheduler context
+ */
+static void
+transmission_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct NeighbourMapEntry *n = cls;
+
+ GNUNET_assert (NULL != lookup_neighbour (&n->id));
+ n->transmission_task = GNUNET_SCHEDULER_NO_TASK;
+ try_transmission_to_peer (n);
+}
+
+
+/**
+ * Initialize the neighbours subsystem.
+ *
+ * @param cls closure for callbacks
+ * @param connect_cb function to call if we connect to a peer
+ * @param disconnect_cb function to call if we disconnect from a peer
+ * @param peer_address_cb function to call if we change an active address
+ * of a neighbour
+ */
+void
+GST_neighbours_start (void *cls,
+ GNUNET_TRANSPORT_NotifyConnect connect_cb,
+ GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb,
+ GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb)
+{
+ callback_cls = cls;
+ connect_notify_cb = connect_cb;
+ disconnect_notify_cb = disconnect_cb;
+ address_change_cb = peer_address_cb;
+ neighbours = GNUNET_CONTAINER_multihashmap_create (NEIGHBOUR_TABLE_SIZE);
+}
+
+
+static void
+send_disconnect_cont (void *cls, const struct GNUNET_PeerIdentity *target,
+ int result)
+{
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending DISCONNECT message to peer `%4s': %i\n",
+ GNUNET_i2s (target), result);
+#endif
+}
+
+
+static int
+send_disconnect (struct NeighbourMapEntry * n)
+{
+ size_t ret;
+ struct SessionDisconnectMessage disconnect_msg;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending DISCONNECT message to peer `%4s'\n",
+ GNUNET_i2s (&n->id));
+#endif
+
+ disconnect_msg.header.size = htons (sizeof (struct SessionDisconnectMessage));
+ disconnect_msg.header.type =
+ htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
+ disconnect_msg.reserved = htonl (0);
+ disconnect_msg.purpose.size =
+ htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
+ sizeof (struct GNUNET_TIME_AbsoluteNBO));
+ disconnect_msg.purpose.purpose =
+ htonl (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT);
+ disconnect_msg.timestamp =
+ GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
+ disconnect_msg.public_key = GST_my_public_key;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_rsa_sign (GST_my_private_key,
+ &disconnect_msg.purpose,
+ &disconnect_msg.signature));
+
+ ret = send_with_session (n,
+ (const char *) &disconnect_msg, sizeof (disconnect_msg),
+ UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+ &send_disconnect_cont, NULL);
+
+ if (ret == GNUNET_SYSERR)
+ return GNUNET_SYSERR;
+
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# peers disconnected due to external request"), 1,
+ GNUNET_NO);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Disconnect from the given neighbour, clean up the record.
+ *
+ * @param n neighbour to disconnect from
+ */
+static void
+disconnect_neighbour (struct NeighbourMapEntry *n)
+{
+ struct MessageQueue *mq;
+ int previous_state;
+
+ previous_state = n->state;
+
+ if (is_disconnecting (n))
+ return;
+
+ /* send DISCONNECT MESSAGE */
+ if (previous_state == S_CONNECTED)
+ {
+ if (GNUNET_OK == send_disconnect (n))
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent DISCONNECT_MSG to `%s'\n",
+ GNUNET_i2s (&n->id));
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Could not send DISCONNECT_MSG to `%s'\n",
+ GNUNET_i2s (&n->id));
+ }
+
+ change_state (n, S_DISCONNECT);
+
+ if (previous_state == S_CONNECTED)
+ {
+ GNUNET_assert (NULL != n->address);
+ if (n->address_state == USED)
+ {
+ GST_validation_set_address_use (n->address, n->session, GNUNET_NO);
+ GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
+ n->address_state = UNUSED;
+ }
+ }
+
+ if (n->address != NULL)
+ {
+ struct GNUNET_TRANSPORT_PluginFunctions *papi;
+
+ papi = GST_plugins_find (n->address->transport_name);
+ if (papi != NULL)
+ papi->disconnect (papi->cls, &n->id);
+ }
+ while (NULL != (mq = n->messages_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (n->messages_head, n->messages_tail, mq);
+ if (NULL != mq->cont)
+ mq->cont (mq->cont_cls, GNUNET_SYSERR);
+ GNUNET_free (mq);
+ }
+ if (NULL != n->is_active)
+ {
+ n->is_active->n = NULL;
+ n->is_active = NULL;
+ }
+
+ switch (previous_state)
+ {
+ case S_CONNECTED:
+ GNUNET_assert (neighbours_connected > 0);
+ neighbours_connected--;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->keepalive_task);
+ GNUNET_SCHEDULER_cancel (n->keepalive_task);
+ n->keepalive_task = GNUNET_SCHEDULER_NO_TASK;
+ n->expect_latency_response = GNUNET_NO;
+ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1,
+ GNUNET_NO);
+ disconnect_notify_cb (callback_cls, &n->id);
+ break;
+ case S_FAST_RECONNECT:
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# fast reconnects failed"), 1,
+ GNUNET_NO);
+ disconnect_notify_cb (callback_cls, &n->id);
+ break;
+ default:
+ break;
+ }
+
+ GNUNET_ATS_suggest_address_cancel (GST_ats, &n->id);
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (neighbours,
+ &n->id.hashPubKey, n));
+ if (GNUNET_SCHEDULER_NO_TASK != n->ats_suggest)
+ {
+ GNUNET_SCHEDULER_cancel (n->ats_suggest);
+ n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != n->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (n->timeout_task);
+ n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != n->transmission_task)
+ {
+ GNUNET_SCHEDULER_cancel (n->transmission_task);
+ n->transmission_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != n->address)
+ {
+ GNUNET_HELLO_address_free (n->address);
+ n->address = NULL;
+ }
+ n->session = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting peer `%4s', %X\n",
+ GNUNET_i2s (&n->id), n);
+ GNUNET_free (n);
+}
+
+
+/**
+ * Peer has been idle for too long. Disconnect.
+ *
+ * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle
+ * @param tc scheduler context
+ */
+static void
+neighbour_timeout_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct NeighbourMapEntry *n = cls;
+
+ n->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# peers disconnected due to timeout"), 1,
+ GNUNET_NO);
+ disconnect_neighbour (n);
+}
+
+
+/**
+ * Send another keepalive message.
+ *
+ * @param cls the 'struct NeighbourMapEntry' of the neighbour that went idle
+ * @param tc scheduler context
+ */
+static void
+neighbour_keepalive_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct NeighbourMapEntry *n = cls;
+ struct GNUNET_MessageHeader m;
+ int ret;
+
+ GNUNET_assert (S_CONNECTED == n->state);
+ n->keepalive_task =
+ GNUNET_SCHEDULER_add_delayed (KEEPALIVE_FREQUENCY,
+ &neighbour_keepalive_task, n);
+
+ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# keepalives sent"), 1,
+ GNUNET_NO);
+ m.size = htons (sizeof (struct GNUNET_MessageHeader));
+ m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE);
+
+ ret = send_with_session (n,
+ (const void *) &m, sizeof (m),
+ UINT32_MAX /* priority */ ,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ NULL, NULL);
+
+ n->expect_latency_response = GNUNET_NO;
+ n->keep_alive_sent = GNUNET_TIME_absolute_get_zero ();
+ if (ret != GNUNET_SYSERR)
+ {
+ n->expect_latency_response = GNUNET_YES;
+ n->keep_alive_sent = GNUNET_TIME_absolute_get ();
+ }
+
+}
+
+
+/**
+ * Disconnect from the given neighbour.
+ *
+ * @param cls unused
+ * @param key hash of neighbour's public key (not used)
+ * @param value the 'struct NeighbourMapEntry' of the neighbour
+ */
+static int
+disconnect_all_neighbours (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct NeighbourMapEntry *n = value;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s', %s\n",
+ GNUNET_i2s (&n->id), "SHUTDOWN_TASK");
+#endif
+ if (S_CONNECTED == n->state)
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# peers disconnected due to global disconnect"),
+ 1, GNUNET_NO);
+ disconnect_neighbour (n);
+ return GNUNET_OK;
+}
+
+
+static void
+ats_suggest_cancel (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct NeighbourMapEntry *n = cls;
+
+ n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "ATS did not suggested address to connect to peer `%s'\n",
+ GNUNET_i2s (&n->id));
+
+ disconnect_neighbour (n);
+}
+
+/**
+ * Cleanup the neighbours subsystem.
+ */
+void
+GST_neighbours_stop ()
+{
+ // This can happen during shutdown
+ if (neighbours == NULL)
+ {
+ return;
+ }
+
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours, &disconnect_all_neighbours,
+ NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (neighbours);
+// GNUNET_assert (neighbours_connected == 0);
+ neighbours = NULL;
+ callback_cls = NULL;
+ connect_notify_cb = NULL;
+ disconnect_notify_cb = NULL;
+ address_change_cb = NULL;
+}
+
+struct ContinutionContext
+{
+ struct GNUNET_HELLO_Address *address;
+
+ struct Session *session;
+};
+
+static void
+send_outbound_quota (const struct GNUNET_PeerIdentity *target,
+ struct GNUNET_BANDWIDTH_Value32NBO quota)
+{
+ struct QuotaSetMessage q_msg;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending outbound quota of %u Bps for peer `%s' to all clients\n",
+ ntohl (quota.value__), GNUNET_i2s (target));
+#endif
+ q_msg.header.size = htons (sizeof (struct QuotaSetMessage));
+ q_msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA);
+ q_msg.quota = quota;
+ q_msg.peer = (*target);
+ GST_clients_broadcast (&q_msg.header, GNUNET_NO);
+}
+
+/**
+ * We tried to send a SESSION_CONNECT message to another peer. If this
+ * succeeded, we change the state. If it failed, we should tell
+ * ATS to not use this address anymore (until it is re-validated).
+ *
+ * @param cls the 'struct GNUNET_HELLO_Address' of the address that was tried
+ * @param target peer to send the message to
+ * @param success GNUNET_OK on success
+ */
+static void
+send_connect_continuation (void *cls, const struct GNUNET_PeerIdentity *target,
+ int success)
+{
+ struct ContinutionContext *cc = cls;
+ struct NeighbourMapEntry *n = lookup_neighbour (&cc->address->peer);
+
+ if (GNUNET_YES != success)
+ {
+ GNUNET_assert (strlen (cc->address->transport_name) > 0);
+ GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
+ }
+ if ((NULL == neighbours) || (NULL == n) || (n->state == S_DISCONNECT))
+ {
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+ return;
+ }
+
+ if ((GNUNET_YES == success) &&
+ ((n->state == S_NOT_CONNECTED) || (n->state == S_CONNECT_SENT)))
+ {
+ change_state (n, S_CONNECT_SENT);
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+ return;
+ }
+
+ if ((GNUNET_NO == success) &&
+ ((n->state == S_NOT_CONNECTED) || (n->state == S_CONNECT_SENT)))
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %p, asking ATS for new address \n",
+ GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
+#endif
+ change_state (n, S_NOT_CONNECTED);
+ if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->ats_suggest);
+ n->ats_suggest =
+ GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, &ats_suggest_cancel,
+ n);
+ GNUNET_ATS_suggest_address (GST_ats, &n->id);
+ }
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+}
+
+
+/**
+ * We tried to switch addresses with an peer already connected. If it failed,
+ * we should tell ATS to not use this address anymore (until it is re-validated).
+ *
+ * @param cls the 'struct NeighbourMapEntry'
+ * @param target peer to send the message to
+ * @param success GNUNET_OK on success
+ */
+static void
+send_switch_address_continuation (void *cls,
+ const struct GNUNET_PeerIdentity *target,
+ int success)
+{
+ struct ContinutionContext *cc = cls;
+ struct NeighbourMapEntry *n;
+
+ if (neighbours == NULL)
+ {
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+ return; /* neighbour is going away */
+ }
+
+ n = lookup_neighbour (&cc->address->peer);
+ if ((n == NULL) || (is_disconnecting (n)))
+ {
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+ return; /* neighbour is going away */
+ }
+
+ GNUNET_assert ((n->state == S_CONNECTED) || (n->state == S_FAST_RECONNECT));
+ if (GNUNET_YES != success)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to switch connected peer `%s' to address '%s' session %X, asking ATS for new address \n",
+ GNUNET_i2s (&n->id), GST_plugins_a2s (cc->address), cc->session);
+#endif
+ GNUNET_assert (strlen (cc->address->transport_name) > 0);
+ GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
+
+ if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->ats_suggest);
+ n->ats_suggest =
+ GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
+ n);
+ GNUNET_ATS_suggest_address (GST_ats, &n->id);
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+ return;
+ }
+ /* Tell ATS that switching addresses was successful */
+ switch (n->state)
+ {
+ case S_CONNECTED:
+ if (n->address_state == FRESH)
+ {
+ GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES);
+ GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0);
+ if (cc->session != n->session)
+ GNUNET_break (0);
+ GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES);
+ n->address_state = USED;
+ }
+ break;
+ case S_FAST_RECONNECT:
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Successful fast reconnect to peer `%s'\n",
+ GNUNET_i2s (&n->id));
+#endif
+ change_state (n, S_CONNECTED);
+ neighbours_connected++;
+ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
+ GNUNET_NO);
+
+ if (n->address_state == FRESH)
+ {
+ GST_validation_set_address_use (cc->address, cc->session, GNUNET_YES);
+ GNUNET_ATS_address_update (GST_ats, cc->address, cc->session, NULL, 0);
+ GNUNET_ATS_address_in_use (GST_ats, cc->address, cc->session, GNUNET_YES);
+ n->address_state = USED;
+ }
+
+ if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
+ n->keepalive_task =
+ GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
+
+ /* Updating quotas */
+ GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
+ send_outbound_quota (target, n->bandwidth_out);
+
+ default:
+ break;
+ }
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+}
+
+
+/**
+ * We tried to send a SESSION_CONNECT message to another peer. If this
+ * succeeded, we change the state. If it failed, we should tell
+ * ATS to not use this address anymore (until it is re-validated).
+ *
+ * @param cls the 'struct NeighbourMapEntry'
+ * @param target peer to send the message to
+ * @param success GNUNET_OK on success
+ */
+static void
+send_connect_ack_continuation (void *cls,
+ const struct GNUNET_PeerIdentity *target,
+ int success)
+{
+ struct ContinutionContext *cc = cls;
+ struct NeighbourMapEntry *n;
+
+ if (neighbours == NULL)
+ {
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+ return; /* neighbour is going away */
+ }
+
+ n = lookup_neighbour (&cc->address->peer);
+ if ((n == NULL) || (is_disconnecting (n)))
+ {
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+ return; /* neighbour is going away */
+ }
+
+ if (GNUNET_YES == success)
+ {
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+ return; /* sending successful */
+ }
+
+ /* sending failed, ask for next address */
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to send CONNECT_MSG to peer `%4s' with address '%s' session %X, asking ATS for new address \n",
+ GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
+#endif
+ change_state (n, S_NOT_CONNECTED);
+ GNUNET_assert (strlen (cc->address->transport_name) > 0);
+ GNUNET_ATS_address_destroyed (GST_ats, cc->address, cc->session);
+
+ if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->ats_suggest);
+ n->ats_suggest =
+ GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
+ n);
+ GNUNET_ATS_suggest_address (GST_ats, &n->id);
+ GNUNET_HELLO_address_free (cc->address);
+ GNUNET_free (cc);
+}
+
+
+/**
+ * For an existing neighbour record, set the active connection to
+ * use the given address.
+ *
+ * @param peer identity of the peer to switch the address for
+ * @param address address of the other peer, NULL if other peer
+ * connected to us
+ * @param session session to use (or NULL)
+ * @param ats performance data
+ * @param ats_count number of entries in ats
+ * @param bandwidth_in inbound quota to be used when connection is up
+ * @param bandwidth_out outbound quota to be used when connection is up
+ * @return GNUNET_YES if we are currently connected, GNUNET_NO if the
+ * connection is not up (yet)
+ */
+int
+GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address
+ *address,
+ struct Session *session,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count,
+ struct GNUNET_BANDWIDTH_Value32NBO
+ bandwidth_in,
+ struct GNUNET_BANDWIDTH_Value32NBO
+ bandwidth_out)
+{
+ struct NeighbourMapEntry *n;
+ struct SessionConnectMessage connect_msg;
+ struct ContinutionContext *cc;
+ size_t msg_len;
+ size_t ret;
+
+ if (neighbours == NULL)
+ {
+ /* This can happen during shutdown */
+ return GNUNET_NO;
+ }
+ n = lookup_neighbour (peer);
+ if (NULL == n)
+ return GNUNET_NO;
+ if (n->state == S_DISCONNECT)
+ {
+ /* We are disconnecting, nothing to do here */
+ return GNUNET_NO;
+ }
+ GNUNET_assert (address->transport_name != NULL);
+ if ((session == NULL) && (0 == address->address_length))
+ {
+ GNUNET_break_op (0);
+ /* FIXME: is this actually possible? When does this happen? */
+ if (strlen (address->transport_name) > 0)
+ GNUNET_ATS_address_destroyed (GST_ats, address, session);
+ GNUNET_ATS_suggest_address (GST_ats, peer);
+ return GNUNET_NO;
+ }
+
+ /* checks successful and neighbour != NULL */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "ATS tells us to switch to address '%s' session %p for peer `%s' in state `%s'\n",
+ (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>",
+ session,
+ GNUNET_i2s (peer),
+ print_state (n->state));
+
+ if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (n->ats_suggest);
+ n->ats_suggest = GNUNET_SCHEDULER_NO_TASK;
+ }
+ /* do not switch addresses just update quotas */
+/*
+ if (n->state == S_FAST_RECONNECT)
+ {
+ if (0 == GNUNET_HELLO_address_cmp(address, n->address))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "FAST RECONNECT to peer `%s' and address '%s' with identical ADDRESS\n",
+ GNUNET_i2s (&n->id), GST_plugins_a2s (n->address));
+ }
+ }
+*/
+ if ((n->state == S_CONNECTED) && (NULL != n->address) &&
+ (0 == GNUNET_HELLO_address_cmp (address, n->address)) &&
+ (n->session == session))
+ {
+ n->bandwidth_in = bandwidth_in;
+ n->bandwidth_out = bandwidth_out;
+ GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
+ send_outbound_quota (peer, n->bandwidth_out);
+ return GNUNET_NO;
+ }
+ if (n->state == S_CONNECTED)
+ {
+ /* mark old address as no longer used */
+ GNUNET_assert (NULL != n->address);
+ if (n->address_state == USED)
+ {
+ GST_validation_set_address_use (n->address, n->session, GNUNET_NO);
+ GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
+ n->address_state = UNUSED;
+ }
+ }
+
+ /* set new address */
+ if (NULL != n->address)
+ GNUNET_HELLO_address_free (n->address);
+ n->address = GNUNET_HELLO_address_copy (address);
+ n->address_state = FRESH;
+ n->bandwidth_in = bandwidth_in;
+ n->bandwidth_out = bandwidth_out;
+ GNUNET_SCHEDULER_cancel (n->timeout_task);
+ n->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ &neighbour_timeout_task, n);
+
+ if (NULL != address_change_cb && n->state == S_CONNECTED)
+ address_change_cb (callback_cls, &n->id, n->address);
+
+ /* Obtain an session for this address from plugin */
+ struct GNUNET_TRANSPORT_PluginFunctions *papi;
+ papi = GST_plugins_find (address->transport_name);
+
+ if (papi == NULL)
+ {
+ /* we don't have the plugin for this address */
+ GNUNET_ATS_address_destroyed (GST_ats, n->address, NULL);
+
+ if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->ats_suggest);
+ n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT,
+ ats_suggest_cancel,
+ n);
+ GNUNET_ATS_suggest_address (GST_ats, &n->id);
+ GNUNET_HELLO_address_free (n->address);
+ n->address = NULL;
+ n->session = NULL;
+ return GNUNET_NO;
+ }
+
+ if (session == NULL)
+ {
+ n->session = papi->get_session (papi->cls, address);
+ /* Session could not be initiated */
+ if (n->session == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to obtain new session %p for peer `%s' and address '%s'\n",
+ n->session, GNUNET_i2s (&n->id), GST_plugins_a2s (n->address));
+
+ GNUNET_ATS_address_destroyed (GST_ats, n->address, NULL);
+
+ if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->ats_suggest);
+ n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT,
+ ats_suggest_cancel,
+ n);
+ GNUNET_ATS_suggest_address (GST_ats, &n->id);
+ GNUNET_HELLO_address_free (n->address);
+ n->address = NULL;
+ n->session = NULL;
+ return GNUNET_NO;
+ }
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Obtained new session %p for peer `%s' and address '%s'\n",
+ n->session, GNUNET_i2s (&n->id), GST_plugins_a2s (n->address));
+ /* Telling ATS about new session */
+ GNUNET_ATS_address_update (GST_ats, n->address, n->session, NULL, 0);
+ }
+ else
+ {
+ n->session = session;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Using existing session %p for peer `%s' and address '%s'\n",
+ n->session,
+ GNUNET_i2s (&n->id),
+ (address->address_length != 0) ? GST_plugins_a2s (address): "<inbound>");
+ }
+
+ switch (n->state)
+ {
+ case S_NOT_CONNECTED:
+ case S_CONNECT_SENT:
+ msg_len = sizeof (struct SessionConnectMessage);
+ connect_msg.header.size = htons (msg_len);
+ connect_msg.header.type =
+ htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT);
+ connect_msg.reserved = htonl (0);
+ connect_msg.timestamp =
+ GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
+
+ cc = GNUNET_malloc (sizeof (struct ContinutionContext));
+ cc->session = n->session;
+ cc->address = GNUNET_HELLO_address_copy (address);
+
+ ret = send_with_session (n,
+ (const char *) &connect_msg, msg_len,
+ UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+ &send_connect_continuation, cc);
+
+ return GNUNET_NO;
+ case S_CONNECT_RECV:
+ /* We received a CONNECT message and asked ATS for an address */
+ msg_len = sizeof (struct SessionConnectMessage);
+ connect_msg.header.size = htons (msg_len);
+ connect_msg.header.type =
+ htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT_ACK);
+ connect_msg.reserved = htonl (0);
+ connect_msg.timestamp =
+ GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
+ cc = GNUNET_malloc (sizeof (struct ContinutionContext));
+ cc->session = n->session;
+ cc->address = GNUNET_HELLO_address_copy (address);
+
+ ret = send_with_session(n,
+ (const void *) &connect_msg, msg_len,
+ UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+ &send_connect_ack_continuation,
+ cc);
+ return GNUNET_NO;
+ case S_CONNECTED:
+ case S_FAST_RECONNECT:
+ /* connected peer is switching addresses or tries fast reconnect */
+ msg_len = sizeof (struct SessionConnectMessage);
+ connect_msg.header.size = htons (msg_len);
+ connect_msg.header.type =
+ htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_CONNECT);
+ connect_msg.reserved = htonl (0);
+ connect_msg.timestamp =
+ GNUNET_TIME_absolute_hton (GNUNET_TIME_absolute_get ());
+ cc = GNUNET_malloc (sizeof (struct ContinutionContext));
+ cc->session = n->session;
+ cc->address = GNUNET_HELLO_address_copy (address);
+ ret = send_with_session(n,
+ (const void *) &connect_msg, msg_len,
+ UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+ &send_switch_address_continuation, cc);
+ if (ret == GNUNET_SYSERR)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to send CONNECT_MESSAGE to `%4s' using address '%s' session %X\n",
+ GNUNET_i2s (peer), GST_plugins_a2s (address), session);
+ }
+ return GNUNET_NO;
+ default:
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Invalid connection state to switch addresses %u \n", n->state);
+ GNUNET_break_op (0);
+ return GNUNET_NO;
+ }
+}
+
+
+/**
+ * Obtain current latency information for the given neighbour.
+ *
+ * @param peer
+ * @return observed latency of the address, FOREVER if the address was
+ * never successfully validated
+ */
+struct GNUNET_TIME_Relative
+GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer)
+{
+ struct NeighbourMapEntry *n;
+
+ n = lookup_neighbour (peer);
+ if ((NULL == n) || ((n->address == NULL) && (n->session == NULL)))
+ return GNUNET_TIME_UNIT_FOREVER_REL;
+
+ return n->latency;
+}
+
+/**
+ * Obtain current address information for the given neighbour.
+ *
+ * @param peer
+ * @return address currently used
+ */
+struct GNUNET_HELLO_Address *
+GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer)
+{
+ struct NeighbourMapEntry *n;
+
+ n = lookup_neighbour (peer);
+ if ((NULL == n) || ((n->address == NULL) && (n->session == NULL)))
+ return NULL;
+
+ return n->address;
+}
+
+
+
+/**
+ * Create an entry in the neighbour map for the given peer
+ *
+ * @param peer peer to create an entry for
+ * @return new neighbour map entry
+ */
+static struct NeighbourMapEntry *
+setup_neighbour (const struct GNUNET_PeerIdentity *peer)
+{
+ struct NeighbourMapEntry *n;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Unknown peer `%s', creating new neighbour\n", GNUNET_i2s (peer));
+#endif
+ n = GNUNET_malloc (sizeof (struct NeighbourMapEntry));
+ n->id = *peer;
+ n->state = S_NOT_CONNECTED;
+ n->latency = GNUNET_TIME_relative_get_forever ();
+ GNUNET_BANDWIDTH_tracker_init (&n->in_tracker,
+ GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
+ MAX_BANDWIDTH_CARRY_S);
+ n->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ &neighbour_timeout_task, n);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (neighbours,
+ &n->id.hashPubKey, n,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ return n;
+}
+
+
+/**
+ * Try to create a connection to the given target (eventually).
+ *
+ * @param target peer to try to connect to
+ */
+void
+GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target)
+{
+ struct NeighbourMapEntry *n;
+
+ // This can happen during shutdown
+ if (neighbours == NULL)
+ {
+ return;
+ }
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying to connect to peer `%s'\n",
+ GNUNET_i2s (target));
+#endif
+ if (0 ==
+ memcmp (target, &GST_my_identity, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ /* my own hello */
+ return;
+ }
+ n = lookup_neighbour (target);
+
+ if (NULL != n)
+ {
+ if ((S_CONNECTED == n->state) || (is_connecting (n)))
+ return; /* already connecting or connected */
+ if (is_disconnecting (n))
+ change_state (n, S_NOT_CONNECTED);
+ }
+
+
+ if (n == NULL)
+ n = setup_neighbour (target);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Asking ATS for suggested address to connect to peer `%s'\n",
+ GNUNET_i2s (&n->id));
+#endif
+
+ GNUNET_ATS_suggest_address (GST_ats, &n->id);
+}
+
+/**
+ * Test if we're connected to the given peer.
+ *
+ * @param target peer to test
+ * @return GNUNET_YES if we are connected, GNUNET_NO if not
+ */
+int
+GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target)
+{
+ struct NeighbourMapEntry *n;
+
+ // This can happen during shutdown
+ if (neighbours == NULL)
+ {
+ return GNUNET_NO;
+ }
+
+ n = lookup_neighbour (target);
+
+ if ((NULL == n) || (S_CONNECTED != n->state))
+ return GNUNET_NO; /* not connected */
+ return GNUNET_YES;
+}
+
+/**
+ * A session was terminated. Take note.
+ *
+ * @param peer identity of the peer where the session died
+ * @param session session that is gone
+ */
+void
+GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
+ struct Session *session)
+{
+ struct NeighbourMapEntry *n;
+
+ if (neighbours == NULL)
+ {
+ /* This can happen during shutdown */
+ return;
+ }
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Session %X to peer `%s' ended \n",
+ session, GNUNET_i2s (peer));
+#endif
+
+ n = lookup_neighbour (peer);
+ if (NULL == n)
+ return;
+ if (session != n->session)
+ return; /* doesn't affect us */
+ if (n->state == S_CONNECTED)
+ {
+ if (n->address_state == USED)
+ {
+ GST_validation_set_address_use (n->address, n->session, GNUNET_NO);
+ GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_NO);
+ n->address_state = UNUSED;
+ }
+ }
+
+ if (NULL != n->address)
+ {
+ GNUNET_HELLO_address_free (n->address);
+ n->address = NULL;
+ }
+ n->session = NULL;
+
+ /* not connected anymore anyway, shouldn't matter */
+ if (S_CONNECTED != n->state)
+ return;
+
+ if (n->keepalive_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (n->keepalive_task);
+ n->keepalive_task = GNUNET_SCHEDULER_NO_TASK;
+ n->expect_latency_response = GNUNET_NO;
+ }
+
+ /* connected, try fast reconnect */
+ /* statistics "transport" : "# peers connected" -= 1
+ * neighbours_connected -= 1
+ * BUT: no disconnect_cb to notify clients about disconnect
+ */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Trying fast reconnect to peer `%s'\n",
+ GNUNET_i2s (peer));
+
+ GNUNET_assert (neighbours_connected > 0);
+ change_state (n, S_FAST_RECONNECT);
+ neighbours_connected--;
+ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), -1,
+ GNUNET_NO);
+
+
+ /* We are connected, so ask ATS to switch addresses */
+ GNUNET_SCHEDULER_cancel (n->timeout_task);
+ n->timeout_task = GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_DISCONNECT_SESSION_TIMEOUT,
+ &neighbour_timeout_task, n);
+ /* try QUICKLY to re-establish a connection, reduce timeout! */
+ if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->ats_suggest);
+ n->ats_suggest = GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT,
+ &ats_suggest_cancel,
+ n);
+ GNUNET_ATS_suggest_address (GST_ats, peer);
+}
+
+
+/**
+ * Transmit a message to the given target using the active connection.
+ *
+ * @param target destination
+ * @param msg message to send
+ * @param msg_size number of bytes in msg
+ * @param timeout when to fail with timeout
+ * @param cont function to call when done
+ * @param cont_cls closure for 'cont'
+ */
+void
+GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg,
+ size_t msg_size, struct GNUNET_TIME_Relative timeout,
+ GST_NeighbourSendContinuation cont, void *cont_cls)
+{
+ struct NeighbourMapEntry *n;
+ struct MessageQueue *mq;
+
+ // This can happen during shutdown
+ if (neighbours == NULL)
+ {
+ return;
+ }
+
+ n = lookup_neighbour (target);
+ if ((n == NULL) || (!is_connected (n)))
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# messages not sent (no such peer or not connected)"),
+ 1, GNUNET_NO);
+#if DEBUG_TRANSPORT
+ if (n == NULL)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Could not send message to peer `%s': unknown neighbour",
+ GNUNET_i2s (target));
+ else if (!is_connected (n))
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Could not send message to peer `%s': not connected\n",
+ GNUNET_i2s (target));
+#endif
+ if (NULL != cont)
+ cont (cont_cls, GNUNET_SYSERR);
+ return;
+ }
+
+ if ((n->session == NULL) && (n->address == NULL))
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# messages not sent (no such peer or not connected)"),
+ 1, GNUNET_NO);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Could not send message to peer `%s': no address available\n",
+ GNUNET_i2s (target));
+#endif
+
+ if (NULL != cont)
+ cont (cont_cls, GNUNET_SYSERR);
+ return;
+ }
+
+ GNUNET_assert (msg_size >= sizeof (struct GNUNET_MessageHeader));
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# bytes in message queue for other peers"),
+ msg_size, GNUNET_NO);
+ mq = GNUNET_malloc (sizeof (struct MessageQueue) + msg_size);
+ mq->cont = cont;
+ mq->cont_cls = cont_cls;
+ /* FIXME: this memcpy can be up to 7% of our total runtime! */
+ memcpy (&mq[1], msg, msg_size);
+ mq->message_buf = (const char *) &mq[1];
+ mq->message_buf_size = msg_size;
+ mq->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ GNUNET_CONTAINER_DLL_insert_tail (n->messages_head, n->messages_tail, mq);
+
+ if ((GNUNET_SCHEDULER_NO_TASK == n->transmission_task) &&
+ (NULL == n->is_active))
+ n->transmission_task = GNUNET_SCHEDULER_add_now (&transmission_task, n);
+}
+
+
+/**
+ * We have received a message from the given sender. How long should
+ * we delay before receiving more? (Also used to keep the peer marked
+ * as live).
+ *
+ * @param sender sender of the message
+ * @param size size of the message
+ * @param do_forward set to GNUNET_YES if the message should be forwarded to clients
+ * GNUNET_NO if the neighbour is not connected or violates the quota,
+ * GNUNET_SYSERR if the connection is not fully up yet
+ * @return how long to wait before reading more from this sender
+ */
+struct GNUNET_TIME_Relative
+GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity
+ *sender, ssize_t size, int *do_forward)
+{
+ struct NeighbourMapEntry *n;
+ struct GNUNET_TIME_Relative ret;
+
+ // This can happen during shutdown
+ if (neighbours == NULL)
+ {
+ return GNUNET_TIME_UNIT_FOREVER_REL;
+ }
+
+ n = lookup_neighbour (sender);
+ if (n == NULL)
+ {
+ GST_neighbours_try_connect (sender);
+ n = lookup_neighbour (sender);
+ if (NULL == n)
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# messages discarded due to lack of neighbour record"),
+ 1, GNUNET_NO);
+ *do_forward = GNUNET_NO;
+ return GNUNET_TIME_UNIT_ZERO;
+ }
+ }
+ if (!is_connected (n))
+ {
+ *do_forward = GNUNET_SYSERR;
+ return GNUNET_TIME_UNIT_ZERO;
+ }
+ if (GNUNET_YES == GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, size))
+ {
+ n->quota_violation_count++;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Bandwidth quota (%u b/s) violation detected (total of %u).\n",
+ n->in_tracker.available_bytes_per_s__,
+ n->quota_violation_count);
+#endif
+ /* Discount 32k per violation */
+ GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, -32 * 1024);
+ }
+ else
+ {
+ if (n->quota_violation_count > 0)
+ {
+ /* try to add 32k back */
+ GNUNET_BANDWIDTH_tracker_consume (&n->in_tracker, 32 * 1024);
+ n->quota_violation_count--;
+ }
+ }
+ if (n->quota_violation_count > QUOTA_VIOLATION_DROP_THRESHOLD)
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# bandwidth quota violations by other peers"),
+ 1, GNUNET_NO);
+ *do_forward = GNUNET_NO;
+ return GNUNET_CONSTANTS_QUOTA_VIOLATION_TIMEOUT;
+ }
+ *do_forward = GNUNET_YES;
+ ret = GNUNET_BANDWIDTH_tracker_get_delay (&n->in_tracker, 32 * 1024);
+ if (ret.rel_value > 0)
+ {
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Throttling read (%llu bytes excess at %u b/s), waiting %llu ms before reading more.\n",
+ (unsigned long long) n->in_tracker.
+ consumption_since_last_update__,
+ (unsigned int) n->in_tracker.available_bytes_per_s__,
+ (unsigned long long) ret.rel_value);
+#endif
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# ms throttling suggested"),
+ (int64_t) ret.rel_value, GNUNET_NO);
+ }
+ return ret;
+}
+
+
+/**
+ * Keep the connection to the given neighbour alive longer,
+ * we received a KEEPALIVE (or equivalent).
+ *
+ * @param neighbour neighbour to keep alive
+ */
+void
+GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour)
+{
+ struct NeighbourMapEntry *n;
+
+ // This can happen during shutdown
+ if (neighbours == NULL)
+ {
+ return;
+ }
+
+ n = lookup_neighbour (neighbour);
+ if (NULL == n)
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# KEEPALIVE messages discarded (not connected)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ GNUNET_SCHEDULER_cancel (n->timeout_task);
+ n->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT,
+ &neighbour_timeout_task, n);
+
+ /* send reply to measure latency */
+ if (S_CONNECTED != n->state)
+ return;
+
+ struct GNUNET_MessageHeader m;
+
+ m.size = htons (sizeof (struct GNUNET_MessageHeader));
+ m.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_KEEPALIVE_RESPONSE);
+
+ send_with_session(n,
+ (const void *) &m, sizeof (m),
+ UINT32_MAX,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ NULL, NULL);
+}
+
+/**
+ * We received a KEEP_ALIVE_RESPONSE message and use this to calculate latency
+ * to this peer
+ *
+ * @param neighbour neighbour to keep alive
+ * @param ats performance data
+ * @param ats_count number of entries in ats
+ */
+void
+GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ struct NeighbourMapEntry *n;
+ struct GNUNET_ATS_Information *ats_new;
+ uint32_t latency;
+
+ if (neighbours == NULL)
+ {
+ // This can happen during shutdown
+ return;
+ }
+
+ n = lookup_neighbour (neighbour);
+ if ((NULL == n) || (n->state != S_CONNECTED))
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# KEEPALIVE_RESPONSE messages discarded (not connected)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ if (n->expect_latency_response != GNUNET_YES)
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# KEEPALIVE_RESPONSE messages discarded (not expected)"),
+ 1, GNUNET_NO);
+ return;
+ }
+ n->expect_latency_response = GNUNET_NO;
+
+ GNUNET_assert (n->keep_alive_sent.abs_value !=
+ GNUNET_TIME_absolute_get_zero ().abs_value);
+ n->latency =
+ GNUNET_TIME_absolute_get_difference (n->keep_alive_sent,
+ GNUNET_TIME_absolute_get ());
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Latency for peer `%s' is %llu ms\n",
+ GNUNET_i2s (&n->id), n->latency.rel_value);
+#endif
+
+
+ if (n->latency.rel_value == GNUNET_TIME_relative_get_forever ().rel_value)
+ {
+ GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats, ats_count);
+ }
+ else
+ {
+ ats_new =
+ GNUNET_malloc (sizeof (struct GNUNET_ATS_Information) *
+ (ats_count + 1));
+ memcpy (ats_new, ats, sizeof (struct GNUNET_ATS_Information) * ats_count);
+
+ /* add latency */
+ ats_new[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
+ if (n->latency.rel_value > UINT32_MAX)
+ latency = UINT32_MAX;
+ else
+ latency = n->latency.rel_value;
+ ats_new[ats_count].value = htonl (latency);
+
+ GNUNET_ATS_address_update (GST_ats, n->address, n->session, ats_new,
+ ats_count + 1);
+ GNUNET_free (ats_new);
+ }
+}
+
+
+/**
+ * Change the incoming quota for the given peer.
+ *
+ * @param neighbour identity of peer to change qutoa for
+ * @param quota new quota
+ */
+void
+GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
+ struct GNUNET_BANDWIDTH_Value32NBO quota)
+{
+ struct NeighbourMapEntry *n;
+
+ // This can happen during shutdown
+ if (neighbours == NULL)
+ {
+ return;
+ }
+
+ n = lookup_neighbour (neighbour);
+ if (n == NULL)
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# SET QUOTA messages ignored (no such peer)"),
+ 1, GNUNET_NO);
+ return;
+ }
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Setting inbound quota of %u Bps for peer `%s' to all clients\n",
+ ntohl (quota.value__), GNUNET_i2s (&n->id));
+#endif
+ GNUNET_BANDWIDTH_tracker_update_quota (&n->in_tracker, quota);
+ if (0 != ntohl (quota.value__))
+ return;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Disconnecting peer `%4s' due to `%s'\n",
+ GNUNET_i2s (&n->id), "SET_QUOTA");
+#endif
+ if (is_connected (n))
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# disconnects due to quota of 0"),
+ 1, GNUNET_NO);
+ disconnect_neighbour (n);
+}
+
+
+/**
+ * Closure for the neighbours_iterate function.
+ */
+struct IteratorContext
+{
+ /**
+ * Function to call on each connected neighbour.
+ */
+ GST_NeighbourIterator cb;
+
+ /**
+ * Closure for 'cb'.
+ */
+ void *cb_cls;
+};
+
+
+/**
+ * Call the callback from the closure for each connected neighbour.
+ *
+ * @param cls the 'struct IteratorContext'
+ * @param key the hash of the public key of the neighbour
+ * @param value the 'struct NeighbourMapEntry'
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+neighbours_iterate (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct IteratorContext *ic = cls;
+ struct NeighbourMapEntry *n = value;
+
+ if (!is_connected (n))
+ return GNUNET_OK;
+
+ ic->cb (ic->cb_cls, &n->id, NULL, 0, n->address);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Iterate over all connected neighbours.
+ *
+ * @param cb function to call
+ * @param cb_cls closure for cb
+ */
+void
+GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls)
+{
+ struct IteratorContext ic;
+
+ // This can happen during shutdown
+ if (neighbours == NULL)
+ {
+ return;
+ }
+
+ ic.cb = cb;
+ ic.cb_cls = cb_cls;
+ GNUNET_CONTAINER_multihashmap_iterate (neighbours, &neighbours_iterate, &ic);
+}
+
+/**
+ * If we have an active connection to the given target, it must be shutdown.
+ *
+ * @param target peer to disconnect from
+ */
+void
+GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target)
+{
+ struct NeighbourMapEntry *n;
+
+ // This can happen during shutdown
+ if (neighbours == NULL)
+ {
+ return;
+ }
+
+ n = lookup_neighbour (target);
+ if (NULL == n)
+ return; /* not active */
+ disconnect_neighbour (n);
+}
+
+
+/**
+ * We received a disconnect message from the given peer,
+ * validate and process.
+ *
+ * @param peer sender of the message
+ * @param msg the disconnect message
+ */
+void
+GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity
+ *peer,
+ const struct GNUNET_MessageHeader
+ *msg)
+{
+ struct NeighbourMapEntry *n;
+ const struct SessionDisconnectMessage *sdm;
+ GNUNET_HashCode hc;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received DISCONNECT message from peer `%s'\n",
+ GNUNET_i2s (peer));
+#endif
+
+ if (ntohs (msg->size) != sizeof (struct SessionDisconnectMessage))
+ {
+ // GNUNET_break_op (0);
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# disconnect messages ignored (old format)"), 1,
+ GNUNET_NO);
+ return;
+ }
+ sdm = (const struct SessionDisconnectMessage *) msg;
+ n = lookup_neighbour (peer);
+ if (NULL == n)
+ return; /* gone already */
+ if (GNUNET_TIME_absolute_ntoh (sdm->timestamp).abs_value <=
+ n->connect_ts.abs_value)
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# disconnect messages ignored (timestamp)"), 1,
+ GNUNET_NO);
+ return;
+ }
+ GNUNET_CRYPTO_hash (&sdm->public_key,
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded),
+ &hc);
+ if (0 != memcmp (peer, &hc, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ if (ntohl (sdm->purpose.size) !=
+ sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded) +
+ sizeof (struct GNUNET_TIME_AbsoluteNBO))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify
+ (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_DISCONNECT, &sdm->purpose,
+ &sdm->signature, &sdm->public_key))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ GST_neighbours_force_disconnect (peer);
+}
+
+
+/**
+ * We received a 'SESSION_CONNECT_ACK' message from the other peer.
+ * Consider switching to it.
+ *
+ * @param message possibly a 'struct SessionConnectMessage' (check format)
+ * @param peer identity of the peer to switch the address for
+ * @param address address of the other peer, NULL if other peer
+ * connected to us
+ * @param session session to use (or NULL)
+ * @param ats performance data
+ * @param ats_count number of entries in ats
+ */
+void
+GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ const struct SessionConnectMessage *scm;
+ struct GNUNET_MessageHeader msg;
+ struct NeighbourMapEntry *n;
+ size_t msg_len;
+ size_t ret;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received CONNECT_ACK message from peer `%s'\n",
+ GNUNET_i2s (peer));
+
+ if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ scm = (const struct SessionConnectMessage *) message;
+ GNUNET_break_op (ntohl (scm->reserved) == 0);
+ n = lookup_neighbour (peer);
+ if (NULL == n)
+ {
+ /* we did not send 'CONNECT' -- at least not recently */
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# unexpected CONNECT_ACK messages (no peer)"),
+ 1, GNUNET_NO);
+ return;
+ }
+
+ /* Additional check
+ *
+ * ((n->state != S_CONNECT_RECV) && (n->address != NULL)):
+ *
+ * We also received an CONNECT message, switched from SENDT to RECV and
+ * ATS already suggested us an address after a successful blacklist check
+ */
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received CONNECT_ACK message from peer `%s' in state `%s'\n",
+ GNUNET_i2s (peer),
+ print_state(n->state));
+
+ if ((n->address != NULL) && (n->state == S_CONNECTED))
+ {
+ /* After fast reconnect: send ACK (ACK) even when we are connected */
+ msg_len = sizeof (msg);
+ msg.size = htons (msg_len);
+ msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
+
+ ret = send_with_session(n,
+ (const char *) &msg, msg_len,
+ UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+ NULL, NULL);
+
+ if (ret == GNUNET_SYSERR)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n",
+ GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
+ return;
+ }
+
+ if ((n->state != S_CONNECT_SENT) &&
+ ((n->state != S_CONNECT_RECV) && (n->address != NULL)))
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# unexpected CONNECT_ACK messages"), 1,
+ GNUNET_NO);
+ return;
+ }
+ if (n->state != S_CONNECTED)
+ change_state (n, S_CONNECTED);
+
+ if (NULL != session)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "transport-ats",
+ "Giving ATS session %p of plugin %s for peer %s\n",
+ session, address->transport_name, GNUNET_i2s (peer));
+ }
+ GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
+ GNUNET_assert (NULL != n->address);
+
+ if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address)))
+ {
+ GST_validation_set_address_use (n->address, n->session, GNUNET_YES);
+ GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES);
+ n->address_state = USED;
+ }
+
+ GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
+
+ /* send ACK (ACK) */
+ msg_len = sizeof (msg);
+ msg.size = htons (msg_len);
+ msg.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SESSION_ACK);
+
+ ret = send_with_session(n,
+ (const char *) &msg, msg_len,
+ UINT32_MAX, GNUNET_TIME_UNIT_FOREVER_REL,
+ NULL, NULL);
+
+ if (ret == GNUNET_SYSERR)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Failed to send SESSION_ACK to `%4s' using address '%s' session %X\n",
+ GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session);
+
+
+ if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
+ n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
+
+ neighbours_connected++;
+ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
+ GNUNET_NO);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Notify about connect of `%4s' using address '%s' session %X LINE %u\n",
+ GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session,
+ __LINE__);
+#endif
+ connect_notify_cb (callback_cls, &n->id, ats, ats_count);
+ send_outbound_quota (peer, n->bandwidth_out);
+
+}
+
+
+void
+GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ struct NeighbourMapEntry *n;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received ACK message from peer `%s'\n",
+ GNUNET_i2s (peer));
+#endif
+
+ if (ntohs (message->size) != sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ n = lookup_neighbour (peer);
+ if (NULL == n)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (S_CONNECTED == n->state)
+ return;
+ if (!is_connecting (n))
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# unexpected ACK messages"), 1,
+ GNUNET_NO);
+ return;
+ }
+ change_state (n, S_CONNECTED);
+ if (NULL != session)
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "transport-ats",
+ "Giving ATS session %p of plugin %s for peer %s\n",
+ session, address->transport_name, GNUNET_i2s (peer));
+ GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
+ GNUNET_assert (n->address != NULL);
+
+ if ((n->address_state == FRESH) && (0 == GNUNET_HELLO_address_cmp(address, n->address)))
+ {
+ GST_validation_set_address_use (n->address, n->session, GNUNET_YES);
+ GNUNET_ATS_address_in_use (GST_ats, n->address, n->session, GNUNET_YES);
+ n->address_state = USED;
+ }
+
+
+ neighbours_connected++;
+ GNUNET_STATISTICS_update (GST_stats, gettext_noop ("# peers connected"), 1,
+ GNUNET_NO);
+
+ GST_neighbours_set_incoming_quota (&n->id, n->bandwidth_in);
+ if (n->keepalive_task == GNUNET_SCHEDULER_NO_TASK)
+ n->keepalive_task = GNUNET_SCHEDULER_add_now (&neighbour_keepalive_task, n);
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Notify about connect of `%4s' using address '%s' session %X LINE %u\n",
+ GNUNET_i2s (&n->id), GST_plugins_a2s (n->address), n->session,
+ __LINE__);
+#endif
+ connect_notify_cb (callback_cls, &n->id, ats, ats_count);
+ send_outbound_quota (peer, n->bandwidth_out);
+}
+
+struct BlackListCheckContext
+{
+ struct GNUNET_ATS_Information *ats;
+
+ uint32_t ats_count;
+
+ struct Session *session;
+
+ struct GNUNET_HELLO_Address *address;
+
+ struct GNUNET_TIME_Absolute ts;
+};
+
+
+static void
+handle_connect_blacklist_cont (void *cls,
+ const struct GNUNET_PeerIdentity *peer,
+ int result)
+{
+ struct NeighbourMapEntry *n;
+ struct BlackListCheckContext *bcc = cls;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Blacklist check due to CONNECT message: `%s'\n",
+ GNUNET_i2s (peer),
+ (result == GNUNET_OK) ? "ALLOWED" : "FORBIDDEN");
+#endif
+
+ /* not allowed */
+ if (GNUNET_OK != result)
+ {
+ GNUNET_HELLO_address_free (bcc->address);
+ GNUNET_free (bcc);
+ return;
+ }
+
+ n = lookup_neighbour (peer);
+ if (NULL == n)
+ n = setup_neighbour (peer);
+
+ if (bcc->ts.abs_value > n->connect_ts.abs_value)
+ {
+ if (NULL != bcc->session)
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG | GNUNET_ERROR_TYPE_BULK,
+ "transport-ats",
+ "Giving ATS session %p of address `%s' for peer %s\n",
+ bcc->session, GST_plugins_a2s (bcc->address),
+ GNUNET_i2s (peer));
+ /* Tell ATS about the session, so ATS can suggest it if it likes it. */
+
+ GNUNET_ATS_address_update (GST_ats, bcc->address, bcc->session, bcc->ats,
+ bcc->ats_count);
+ n->connect_ts = bcc->ts;
+ }
+
+ GNUNET_HELLO_address_free (bcc->address);
+ GNUNET_free (bcc);
+
+ if (n->state != S_CONNECT_RECV)
+ change_state (n, S_CONNECT_RECV);
+
+
+ /* Ask ATS for an address to connect via that address */
+ if (n->ats_suggest != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (n->ats_suggest);
+ n->ats_suggest =
+ GNUNET_SCHEDULER_add_delayed (ATS_RESPONSE_TIMEOUT, ats_suggest_cancel,
+ n);
+ GNUNET_ATS_suggest_address (GST_ats, peer);
+}
+
+/**
+ * We received a 'SESSION_CONNECT' message from the other peer.
+ * Consider switching to it.
+ *
+ * @param message possibly a 'struct SessionConnectMessage' (check format)
+ * @param peer identity of the peer to switch the address for
+ * @param address address of the other peer, NULL if other peer
+ * connected to us
+ * @param session session to use (or NULL)
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+void
+GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count)
+{
+ const struct SessionConnectMessage *scm;
+ struct BlackListCheckContext *bcc = NULL;
+ struct NeighbourMapEntry *n;
+
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received CONNECT message from peer `%s'\n", GNUNET_i2s (peer));
+#endif
+
+ if (ntohs (message->size) != sizeof (struct SessionConnectMessage))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+
+ scm = (const struct SessionConnectMessage *) message;
+ GNUNET_break_op (ntohl (scm->reserved) == 0);
+
+ GNUNET_ATS_address_update (GST_ats, address, session, ats, ats_count);
+
+ n = lookup_neighbour (peer);
+ if ((n != NULL) && ((S_CONNECTED == n->state) || (S_FAST_RECONNECT == n->state)))
+ {
+ /* connected peer switches addresses or is trying to do a fast reconnect*/
+ return;
+ }
+
+
+ /* we are not connected to this peer */
+ /* do blacklist check */
+ bcc =
+ GNUNET_malloc (sizeof (struct BlackListCheckContext) +
+ sizeof (struct GNUNET_ATS_Information) * (ats_count + 1));
+ bcc->ts = GNUNET_TIME_absolute_ntoh (scm->timestamp);
+ bcc->ats_count = ats_count + 1;
+ bcc->address = GNUNET_HELLO_address_copy (address);
+ bcc->session = session;
+ bcc->ats = (struct GNUNET_ATS_Information *) &bcc[1];
+ memcpy (bcc->ats, ats, sizeof (struct GNUNET_ATS_Information) * ats_count);
+ bcc->ats[ats_count].type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
+ bcc->ats[ats_count].value =
+ htonl ((uint32_t) GST_neighbour_get_latency (peer).rel_value);
+ GST_blacklist_test_allowed (peer, address->transport_name,
+ &handle_connect_blacklist_cont, bcc);
+}
+
+
+/* end of file gnunet-service-transport_neighbours.c */
diff --git a/src/transport/gnunet-service-transport_neighbours.h b/src/transport/gnunet-service-transport_neighbours.h
new file mode 100644
index 0000000..33fa1da
--- /dev/null
+++ b/src/transport/gnunet-service-transport_neighbours.h
@@ -0,0 +1,314 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_neighbours.h
+ * @brief neighbour management API
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_TRANSPORT_NEIGHBOURS_H
+#define GNUNET_SERVICE_TRANSPORT_NEIGHBOURS_H
+
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_transport_plugin.h"
+#include "gnunet_util_lib.h"
+
+// TODO:
+// - ATS and similar info is a bit lacking in the API right now...
+
+
+
+/**
+ * Initialize the neighbours subsystem.
+ *
+ * @param cls closure for callbacks
+ * @param connect_cb function to call if we connect to a peer
+ * @param disconnect_cb function to call if we disconnect from a peer
+ * @param peer_address_cb function to call if a neighbour's active address changes
+ */
+void
+GST_neighbours_start (void *cls,
+ GNUNET_TRANSPORT_NotifyConnect connect_cb,
+ GNUNET_TRANSPORT_NotifyDisconnect disconnect_cb,
+ GNUNET_TRANSPORT_PeerIterateCallback peer_address_cb);
+
+
+/**
+ * Cleanup the neighbours subsystem.
+ */
+void
+GST_neighbours_stop (void);
+
+
+/**
+ * Try to create a connection to the given target (eventually).
+ *
+ * @param target peer to try to connect to
+ */
+void
+GST_neighbours_try_connect (const struct GNUNET_PeerIdentity *target);
+
+
+/**
+ * Test if we're connected to the given peer.
+ *
+ * @param target peer to test
+ * @return GNUNET_YES if we are connected, GNUNET_NO if not
+ */
+int
+GST_neighbours_test_connected (const struct GNUNET_PeerIdentity *target);
+
+
+/**
+ * Function called after the transmission is done.
+ *
+ * @param cls closure
+ * @param success GNUNET_OK on success, GNUNET_NO on failure, GNUNET_SYSERR if we're not connected
+ */
+typedef void (*GST_NeighbourSendContinuation) (void *cls, int success);
+
+
+/**
+ * Transmit a message to the given target using the active connection.
+ *
+ * @param target destination
+ * @param msg message to send
+ * @param msg_size number of bytes in msg
+ * @param timeout when to fail with timeout
+ * @param cont function to call when done
+ * @param cont_cls closure for 'cont'
+ */
+void
+GST_neighbours_send (const struct GNUNET_PeerIdentity *target, const void *msg,
+ size_t msg_size, struct GNUNET_TIME_Relative timeout,
+ GST_NeighbourSendContinuation cont, void *cont_cls);
+
+
+/**
+ * We have received a message from the given sender.
+ * How long should we delay before receiving more?
+ * (Also used to keep the peer marked as live).
+ *
+ * @param sender sender of the message
+ * @param size size of the message
+ * @param do_forward set to GNUNET_YES if the message should be forwarded to clients
+ * GNUNET_NO if the neighbour is not connected or violates the quota
+ * @return how long to wait before reading more from this sender
+ */
+struct GNUNET_TIME_Relative
+GST_neighbours_calculate_receive_delay (const struct GNUNET_PeerIdentity
+ *sender, ssize_t size, int *do_forward);
+
+
+/**
+ * Keep the connection to the given neighbour alive longer,
+ * we received a KEEPALIVE (or equivalent).
+ *
+ * @param neighbour neighbour to keep alive
+ */
+void
+GST_neighbours_keepalive (const struct GNUNET_PeerIdentity *neighbour);
+
+/**
+ * We received a KEEP_ALIVE_RESPONSE message and use this to calculate latency
+ * to this peer
+ *
+ * @param neighbour neighbour to keep alive
+ * @param ats performance data
+ * @param ats_count number of entries in ats
+ */
+void
+GST_neighbours_keepalive_response (const struct GNUNET_PeerIdentity *neighbour,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count);
+
+
+/**
+ * Change the incoming quota for the given peer.
+ *
+ * @param neighbour identity of peer to change qutoa for
+ * @param quota new quota
+ */
+void
+GST_neighbours_set_incoming_quota (const struct GNUNET_PeerIdentity *neighbour,
+ struct GNUNET_BANDWIDTH_Value32NBO quota);
+
+
+/**
+ * If we have an active connection to the given target, it must be shutdown.
+ *
+ * @param target peer to disconnect from
+ */
+void
+GST_neighbours_force_disconnect (const struct GNUNET_PeerIdentity *target);
+
+
+/**
+ * Function called for each connected neighbour.
+ *
+ * @param cls closure
+ * @param neighbour identity of the neighbour
+ * @param ats performance data
+ * @param ats_count number of entries in ats (including 0-termination)
+ * @param address the address (or NULL)
+ */
+typedef void (*GST_NeighbourIterator) (void *cls,
+ const struct GNUNET_PeerIdentity *
+ neighbour,
+ const struct GNUNET_ATS_Information *
+ ats, uint32_t ats_count,
+ const struct GNUNET_HELLO_Address *
+ address);
+
+
+/**
+ * Iterate over all connected neighbours.
+ *
+ * @param cb function to call
+ * @param cb_cls closure for cb
+ */
+void
+GST_neighbours_iterate (GST_NeighbourIterator cb, void *cb_cls);
+
+
+/**
+ * A session was terminated. Take note.
+ *
+ * @param peer identity of the peer where the session died
+ * @param session session that is gone
+ */
+void
+GST_neighbours_session_terminated (const struct GNUNET_PeerIdentity *peer,
+ struct Session *session);
+
+
+/**
+ * For an existing neighbour record, set the active connection to
+ * use the given address.
+ *
+ * @param peer identity of the peer to switch the address for
+ * @param address address of the other peer, NULL if other peer
+ * connected to us
+ * @param session session to use (or NULL)
+ * @param ats performance data
+ * @param ats_count number of entries in ats
+ * @param bandwidth_in inbound quota to be used when connection is up
+ * @param bandwidth_out outbound quota to be used when connection is up
+ * @return GNUNET_YES if we are currently connected, GNUNET_NO if the
+ * connection is not up (yet)
+ */
+int
+GST_neighbours_switch_to_address (const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address
+ *address, struct Session *session,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count,
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_in,
+ struct GNUNET_BANDWIDTH_Value32NBO bandwidth_out);
+
+
+/**
+ * We received a 'SESSION_CONNECT' message from the other peer.
+ * Consider switching to it.
+ *
+ * @param message possibly a 'struct SessionConnectMessage' (check format)
+ * @param peer identity of the peer to switch the address for
+ * @param address address of the other peer, NULL if other peer
+ * connected to us
+ * @param session session to use (or NULL)
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+void
+GST_neighbours_handle_connect (const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count);
+
+
+/**
+ * We received a 'SESSION_CONNECT_ACK' message from the other peer.
+ * Consider switching to it.
+ *
+ * @param message possibly a 'struct SessionConnectMessage' (check format)
+ * @param peer identity of the peer to switch the address for
+ * @param address address of the other peer, NULL if other peer
+ * connected to us
+ * @param session session to use (or NULL)
+ * @param ats performance data
+ * @param ats_count number of entries in ats
+ */
+void
+GST_neighbours_handle_connect_ack (const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count);
+
+void
+GST_neighbours_handle_ack (const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ const struct GNUNET_ATS_Information *ats,
+ uint32_t ats_count);
+
+
+/**
+ * Obtain current latency information for the given neighbour.
+ *
+ * @param peer
+ * @return observed latency of the address, FOREVER if the address was
+ * never successfully validated
+ */
+struct GNUNET_TIME_Relative
+GST_neighbour_get_latency (const struct GNUNET_PeerIdentity *peer);
+
+
+/**
+ * Obtain current address information for the given neighbour.
+ *
+ * @param peer
+ * @return address currently used
+ */
+struct GNUNET_HELLO_Address *
+GST_neighbour_get_current_address (const struct GNUNET_PeerIdentity *peer);
+
+
+/**
+ * We received a disconnect message from the given peer,
+ * validate and process.
+ *
+ * @param peer sender of the message
+ * @param msg the disconnect message
+ */
+void
+GST_neighbours_handle_disconnect_message (const struct GNUNET_PeerIdentity
+ *peer,
+ const struct GNUNET_MessageHeader
+ *msg);
+
+
+#endif
+/* end of file gnunet-service-transport_neighbours.h */
diff --git a/src/transport/gnunet-service-transport_plugins.c b/src/transport/gnunet-service-transport_plugins.c
new file mode 100644
index 0000000..fc14b6e
--- /dev/null
+++ b/src/transport/gnunet-service-transport_plugins.c
@@ -0,0 +1,230 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_plugins.c
+ * @brief plugin management
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-transport.h"
+#include "gnunet-service-transport_hello.h"
+#include "gnunet-service-transport_plugins.h"
+
+/**
+ * Entry in doubly-linked list of all of our plugins.
+ */
+struct TransportPlugin
+{
+ /**
+ * This is a doubly-linked list.
+ */
+ struct TransportPlugin *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct TransportPlugin *prev;
+
+ /**
+ * API of the transport as returned by the plugin's
+ * initialization function.
+ */
+ struct GNUNET_TRANSPORT_PluginFunctions *api;
+
+ /**
+ * Short name for the plugin (i.e. "tcp").
+ */
+ char *short_name;
+
+ /**
+ * Name of the library (i.e. "gnunet_plugin_transport_tcp").
+ */
+ char *lib_name;
+
+ /**
+ * Environment this transport service is using
+ * for this plugin.
+ */
+ struct GNUNET_TRANSPORT_PluginEnvironment env;
+
+};
+
+/**
+ * Head of DLL of all loaded plugins.
+ */
+static struct TransportPlugin *plugins_head;
+
+/**
+ * Head of DLL of all loaded plugins.
+ */
+static struct TransportPlugin *plugins_tail;
+
+
+
+/**
+ * Load and initialize all plugins. The respective functions will be
+ * invoked by the plugins when the respective events happen. The
+ * closure will be set to a 'const char*' containing the name of the
+ * plugin that caused the call.
+ *
+ * @param recv_cb function to call when data is received
+ * @param address_cb function to call when our public addresses changed
+ * @param session_end_cb function to call when a session was terminated
+ * @param address_type_cb function to call when a address type is requested
+ */
+void
+GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb,
+ GNUNET_TRANSPORT_AddressNotification address_cb,
+ GNUNET_TRANSPORT_SessionEnd session_end_cb,
+ GNUNET_TRANSPORT_AddressToType address_type_cb)
+{
+ struct TransportPlugin *plug;
+ struct TransportPlugin *next;
+ unsigned long long tneigh;
+ char *libname;
+ char *plugs;
+ char *pos;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (GST_cfg, "TRANSPORT",
+ "NEIGHBOUR_LIMIT", &tneigh))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Transport service is lacking NEIGHBOUR_LIMIT option.\n"));
+ return;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (GST_cfg, "TRANSPORT", "PLUGINS",
+ &plugs))
+ return;
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Starting transport plugins `%s'\n"),
+ plugs);
+ for (pos = strtok (plugs, " "); pos != NULL; pos = strtok (NULL, " "))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO, _("Loading `%s' transport plugin\n"),
+ pos);
+ GNUNET_asprintf (&libname, "libgnunet_plugin_transport_%s", pos);
+ plug = GNUNET_malloc (sizeof (struct TransportPlugin));
+ plug->short_name = GNUNET_strdup (pos);
+ plug->lib_name = libname;
+ plug->env.cfg = GST_cfg;
+ plug->env.my_identity = &GST_my_identity;
+ plug->env.get_our_hello = &GST_hello_get;
+ plug->env.cls = plug->short_name;
+ plug->env.receive = recv_cb;
+ plug->env.notify_address = address_cb;
+ plug->env.session_end = session_end_cb;
+ plug->env.get_address_type = address_type_cb;
+ plug->env.max_connections = tneigh;
+ plug->env.stats = GST_stats;
+ GNUNET_CONTAINER_DLL_insert (plugins_head, plugins_tail, plug);
+ }
+ GNUNET_free (plugs);
+ next = plugins_head;
+ while (next != NULL)
+ {
+ plug = next;
+ next = plug->next;
+ plug->api = GNUNET_PLUGIN_load (plug->lib_name, &plug->env);
+ if (plug->api == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to load transport plugin for `%s'\n"),
+ plug->lib_name);
+ GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
+ GNUNET_free (plug->short_name);
+ GNUNET_free (plug->lib_name);
+ GNUNET_free (plug);
+ }
+ }
+}
+
+
+/**
+ * Unload all plugins
+ */
+void
+GST_plugins_unload ()
+{
+ struct TransportPlugin *plug;
+
+ while (NULL != (plug = plugins_head))
+ {
+ GNUNET_break (NULL == GNUNET_PLUGIN_unload (plug->lib_name, plug->api));
+ GNUNET_free (plug->lib_name);
+ GNUNET_free (plug->short_name);
+ GNUNET_CONTAINER_DLL_remove (plugins_head, plugins_tail, plug);
+ GNUNET_free (plug);
+ }
+}
+
+
+/**
+ * Obtain the plugin API based on a plugin name.
+ *
+ * @param name name of the plugin
+ * @return the plugin's API, NULL if the plugin is not loaded
+ */
+struct GNUNET_TRANSPORT_PluginFunctions *
+GST_plugins_find (const char *name)
+{
+ struct TransportPlugin *head = plugins_head;
+
+ while ((head != NULL) && (0 != strcmp (name, head->short_name)))
+ head = head->next;
+ if (NULL == head)
+ return NULL;
+ return head->api;
+}
+
+
+/**
+ * Convert a given address to a human-readable format. Note that the
+ * return value will be overwritten on the next call to this function.
+ *
+ * @param address the address to convert
+ * @return statically allocated (!) human-readable address
+ */
+const char *
+GST_plugins_a2s (const struct GNUNET_HELLO_Address *address)
+{
+ struct GNUNET_TRANSPORT_PluginFunctions *api;
+ static char unable_to_show[1024];
+
+ if (address == NULL)
+ return "<inbound>";
+ api = GST_plugins_find (address->transport_name);
+ if (NULL == api)
+ return "<plugin unknown>";
+ if (0 == address->address_length)
+ {
+ GNUNET_snprintf (unable_to_show, sizeof (unable_to_show),
+ "<unable to stringify %u-byte long address of %s transport>",
+ (unsigned int) address->address_length,
+ address->transport_name);
+ return unable_to_show;
+ }
+ return api->address_to_string (NULL, address->address,
+ address->address_length);
+}
+
+
+/* end of file gnunet-service-transport_plugins.c */
diff --git a/src/transport/gnunet-service-transport_plugins.h b/src/transport/gnunet-service-transport_plugins.h
new file mode 100644
index 0000000..04bb5ea
--- /dev/null
+++ b/src/transport/gnunet-service-transport_plugins.h
@@ -0,0 +1,82 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_plugins.h
+ * @brief plugin management API
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_TRANSPORT_PLUGINS_H
+#define GNUNET_SERVICE_TRANSPORT_PLUGINS_H
+
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_transport_plugin.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
+
+
+/**
+ * Load and initialize all plugins. The respective functions will be
+ * invoked by the plugins when the respective events happen. The
+ * closure will be set to a 'const char*' containing the name of the
+ * plugin that caused the call.
+ *
+ * @param recv_cb function to call when data is received
+ * @param address_cb function to call when our public addresses changed
+ * @param session_end_cb function to call when a session was terminated
+ * @param address_type_cb function to call when a address type is requested
+ */
+void
+GST_plugins_load (GNUNET_TRANSPORT_PluginReceiveCallback recv_cb,
+ GNUNET_TRANSPORT_AddressNotification address_cb,
+ GNUNET_TRANSPORT_SessionEnd session_end_cb,
+ GNUNET_TRANSPORT_AddressToType address_type_cb);
+
+/**
+ * Unload all plugins
+ */
+void
+GST_plugins_unload (void);
+
+
+/**
+ * Obtain the plugin API based on a plugin name.
+ *
+ * @param name name of the plugin
+ * @return the plugin's API, NULL if the plugin is not loaded
+ */
+struct GNUNET_TRANSPORT_PluginFunctions *
+GST_plugins_find (const char *name);
+
+
+/**
+ * Convert a given address to a human-readable format. Note that the
+ * return value will be overwritten on the next call to this function.
+ *
+ * @param address address to convert
+ * @return statically allocated (!) human-readable address
+ */
+const char *
+GST_plugins_a2s (const struct GNUNET_HELLO_Address *address);
+
+
+#endif
+/* end of file gnunet-service-transport_plugins.h */
diff --git a/src/transport/gnunet-service-transport_validation.c b/src/transport/gnunet-service-transport_validation.c
new file mode 100644
index 0000000..a6d9424
--- /dev/null
+++ b/src/transport/gnunet-service-transport_validation.c
@@ -0,0 +1,1276 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_validation.c
+ * @brief address validation subsystem
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet-service-transport_validation.h"
+#include "gnunet-service-transport_plugins.h"
+#include "gnunet-service-transport_hello.h"
+#include "gnunet-service-transport_blacklist.h"
+#include "gnunet-service-transport.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_ats_service.h"
+#include "gnunet_peerinfo_service.h"
+#include "gnunet_signatures.h"
+
+
+/**
+ * How long is a PONG signature valid? We'll recycle a signature until
+ * 1/4 of this time is remaining. PONGs should expire so that if our
+ * external addresses change an adversary cannot replay them indefinitely.
+ * OTOH, we don't want to spend too much time generating PONG signatures,
+ * so they must have some lifetime to reduce our CPU usage.
+ */
+#define PONG_SIGNATURE_LIFETIME GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
+
+/**
+ * After how long do we expire an address in a HELLO that we just
+ * validated? This value is also used for our own addresses when we
+ * create a HELLO.
+ */
+#define HELLO_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 12)
+
+/**
+ * How often do we allow PINGing an address that we have not yet
+ * validated? This also determines how long we track an address that
+ * we cannot validate (because after this time we can destroy the
+ * validation record).
+ */
+#define UNVALIDATED_PING_KEEPALIVE GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 5)
+
+/**
+ * How often do we PING an address that we have successfully validated
+ * in the past but are not actively using? Should be (significantly)
+ * smaller than HELLO_ADDRESS_EXPIRATION.
+ */
+#define VALIDATED_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 15)
+
+/**
+ * How often do we PING an address that we are currently using?
+ */
+#define CONNECTED_PING_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 2)
+
+/**
+ * How much delay is acceptable for sending the PING or PONG?
+ */
+#define ACCEPTABLE_PING_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
+
+/**
+ * Size of the validation map hashmap.
+ */
+#define VALIDATION_MAP_SIZE 256
+
+/**
+ * Priority to use for PINGs
+ */
+#define PING_PRIORITY 2
+
+/**
+ * Priority to use for PONGs
+ */
+#define PONG_PRIORITY 4
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Message used to ask a peer to validate receipt (to check an address
+ * from a HELLO). Followed by the address we are trying to validate,
+ * or an empty address if we are just sending a PING to confirm that a
+ * connection which the receiver (of the PING) initiated is still valid.
+ */
+struct TransportPingMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PING
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Challenge code (to ensure fresh reply).
+ */
+ uint32_t challenge GNUNET_PACKED;
+
+ /**
+ * Who is the intended recipient?
+ */
+ struct GNUNET_PeerIdentity target;
+
+};
+
+
+/**
+ * Message used to validate a HELLO. The challenge is included in the
+ * confirmation to make matching of replies to requests possible. The
+ * signature signs our public key, an expiration time and our address.<p>
+ *
+ * This message is followed by our transport address that the PING tried
+ * to confirm (if we liked it). The address can be empty (zero bytes)
+ * if the PING had not address either (and we received the request via
+ * a connection that we initiated).
+ */
+struct TransportPongMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PONG
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Challenge code from PING (showing freshness). Not part of what
+ * is signed so that we can re-use signatures.
+ */
+ uint32_t challenge GNUNET_PACKED;
+
+ /**
+ * Signature.
+ */
+ struct GNUNET_CRYPTO_RsaSignature signature;
+
+ /**
+ * GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN to confirm that this is a
+ * plausible address for the signing peer.
+ */
+ struct GNUNET_CRYPTO_RsaSignaturePurpose purpose;
+
+ /**
+ * When does this signature expire?
+ */
+ struct GNUNET_TIME_AbsoluteNBO expiration;
+
+ /**
+ * Size of address appended to this message (part of what is
+ * being signed, hence not redundant).
+ */
+ uint32_t addrlen GNUNET_PACKED;
+
+};
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * Information about an address under validation
+ */
+struct ValidationEntry
+{
+
+ /**
+ * The address.
+ */
+ struct GNUNET_HELLO_Address *address;
+
+ /**
+ * Handle to the blacklist check (if we're currently in it).
+ */
+ struct GST_BlacklistCheck *bc;
+
+ /**
+ * Public key of the peer.
+ */
+ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
+
+ /**
+ * The identity of the peer. FIXME: duplicated (also in 'address')
+ */
+ struct GNUNET_PeerIdentity pid;
+
+ /**
+ * ID of task that will clean up this entry if nothing happens.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * ID of task that will trigger address revalidation.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier revalidation_task;
+
+ /**
+ * At what time did we send the latest validation request (PING)?
+ */
+ struct GNUNET_TIME_Absolute send_time;
+
+ /**
+ * Until when is this address valid?
+ * ZERO if it is not currently considered valid.
+ */
+ struct GNUNET_TIME_Absolute valid_until;
+
+ /**
+ * How long until we can try to validate this address again?
+ * FOREVER if the address is for an unsupported plugin (from PEERINFO)
+ * ZERO if the address is considered valid (no validation needed)
+ * otherwise a time in the future if we're currently denying re-validation
+ */
+ struct GNUNET_TIME_Absolute revalidation_block;
+
+ /**
+ * Last observed latency for this address (round-trip), delay between
+ * last PING sent and PONG received; FOREVER if we never got a PONG.
+ */
+ struct GNUNET_TIME_Relative latency;
+
+ /**
+ * Challenge number we used.
+ */
+ uint32_t challenge;
+
+ /**
+ * When passing the address in 'add_valid_peer_address', did we
+ * copy the address to the HELLO yet?
+ */
+ int copied;
+
+ /**
+ * Are we currently using this address for a connection?
+ */
+ int in_use;
+
+ /**
+ * Are we expecting a PONG message for this validation entry?
+ */
+ int expecting_pong;
+};
+
+
+/**
+ * Context of currently active requests to peerinfo
+ * for validation of HELLOs.
+ */
+struct CheckHelloValidatedContext
+{
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct CheckHelloValidatedContext *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct CheckHelloValidatedContext *prev;
+
+ /**
+ * Hello that we are validating.
+ */
+ const struct GNUNET_HELLO_Message *hello;
+
+};
+
+
+/**
+ * Head of linked list of HELLOs awaiting validation.
+ */
+static struct CheckHelloValidatedContext *chvc_head;
+
+/**
+ * Tail of linked list of HELLOs awaiting validation
+ */
+static struct CheckHelloValidatedContext *chvc_tail;
+
+/**
+ * Map of PeerIdentities to 'struct ValidationEntry*'s (addresses
+ * of the given peer that we are currently validating, have validated
+ * or are blocked from re-validation for a while).
+ */
+static struct GNUNET_CONTAINER_MultiHashMap *validation_map;
+
+/**
+ * Context for peerinfo iteration.
+ */
+static struct GNUNET_PEERINFO_NotifyContext *pnc;
+
+
+/**
+ * Context for the validation entry match function.
+ */
+struct ValidationEntryMatchContext
+{
+ /**
+ * Where to store the result?
+ */
+ struct ValidationEntry *ve;
+
+ /**
+ * Address we're interested in.
+ */
+ const struct GNUNET_HELLO_Address *address;
+
+};
+
+
+/**
+ * Iterate over validation entries until a matching one is found.
+ *
+ * @param cls the 'struct ValidationEntryMatchContext'
+ * @param key peer identity (unused)
+ * @param value a 'struct ValidationEntry' to match
+ * @return GNUNET_YES if the entry does not match,
+ * GNUNET_NO if the entry does match
+ */
+static int
+validation_entry_match (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct ValidationEntryMatchContext *vemc = cls;
+ struct ValidationEntry *ve = value;
+
+ if (0 == GNUNET_HELLO_address_cmp (ve->address, vemc->address))
+ {
+ vemc->ve = ve;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Iterate over validation entries and free them.
+ *
+ * @param cls (unused)
+ * @param key peer identity (unused)
+ * @param value a 'struct ValidationEntry' to clean up
+ * @return GNUNET_YES (continue to iterate)
+ */
+static int
+cleanup_validation_entry (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct ValidationEntry *ve = value;
+
+ if (NULL != ve->bc)
+ {
+ GST_blacklist_test_cancel (ve->bc);
+ ve->bc = NULL;
+ }
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_remove (validation_map,
+ &ve->pid.hashPubKey, ve));
+ GNUNET_HELLO_address_free (ve->address);
+ if (GNUNET_SCHEDULER_NO_TASK != ve->timeout_task)
+ {
+ GNUNET_SCHEDULER_cancel (ve->timeout_task);
+ ve->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != ve->revalidation_task)
+ {
+ GNUNET_SCHEDULER_cancel (ve->revalidation_task);
+ ve->revalidation_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_free (ve);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Address validation cleanup task. Assesses if the record is no
+ * longer valid and then possibly triggers its removal.
+ *
+ * @param cls the 'struct ValidationEntry'
+ * @param tc scheduler context (unused)
+ */
+static void
+timeout_hello_validation (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ValidationEntry *ve = cls;
+ struct GNUNET_TIME_Absolute max;
+ struct GNUNET_TIME_Relative left;
+
+ ve->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ max = GNUNET_TIME_absolute_max (ve->valid_until, ve->revalidation_block);
+ left = GNUNET_TIME_absolute_get_remaining (max);
+ if (left.rel_value > 0)
+ {
+ /* should wait a bit longer */
+ ve->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (left, &timeout_hello_validation, ve);
+ return;
+ }
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# address records discarded"), 1,
+ GNUNET_NO);
+ cleanup_validation_entry (NULL, &ve->pid.hashPubKey, ve);
+}
+
+
+/**
+ * Function called with the result from blacklisting.
+ * Send a PING to the other peer if a communication is allowed.
+ *
+ * @param cls our 'struct ValidationEntry'
+ * @param pid identity of the other peer
+ * @param result GNUNET_OK if the connection is allowed, GNUNET_NO if not
+ */
+static void
+transmit_ping_if_allowed (void *cls, const struct GNUNET_PeerIdentity *pid,
+ int result)
+{
+ struct ValidationEntry *ve = cls;
+ struct TransportPingMessage ping;
+ struct GNUNET_TRANSPORT_PluginFunctions *papi;
+ const struct GNUNET_MessageHeader *hello;
+ ssize_t ret;
+ size_t tsize;
+ size_t slen;
+ uint16_t hsize;
+
+ ve->bc = NULL;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Transmitting plain PING to `%s' %s\n",
+ GNUNET_i2s (pid), GST_plugins_a2s (ve->address));
+
+ slen = strlen (ve->address->transport_name) + 1;
+ hello = GST_hello_get ();
+ hsize = ntohs (hello->size);
+ tsize =
+ sizeof (struct TransportPingMessage) + ve->address->address_length +
+ slen + hsize;
+
+ ping.header.size =
+ htons (sizeof (struct TransportPingMessage) +
+ ve->address->address_length + slen);
+ ping.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PING);
+ ping.challenge = htonl (ve->challenge);
+ ping.target = *pid;
+
+ if (tsize >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _
+ ("Not transmitting `%s' with `%s', message too big (%u bytes!). This should not happen.\n"),
+ "HELLO", "PING", (unsigned int) tsize);
+ /* message too big (!?), get rid of HELLO */
+ hsize = 0;
+ tsize =
+ sizeof (struct TransportPingMessage) + ve->address->address_length +
+ slen + hsize;
+ }
+ {
+ char message_buf[tsize];
+
+ /* build message with structure:
+ * [HELLO][TransportPingMessage][Transport name][Address] */
+ memcpy (message_buf, hello, hsize);
+ memcpy (&message_buf[hsize], &ping, sizeof (struct TransportPingMessage));
+ memcpy (&message_buf[sizeof (struct TransportPingMessage) + hsize],
+ ve->address->transport_name, slen);
+ memcpy (&message_buf[sizeof (struct TransportPingMessage) + slen + hsize],
+ ve->address, ve->address->address_length);
+ papi = GST_plugins_find (ve->address->transport_name);
+ if (papi == NULL)
+ ret = -1;
+ else
+ {
+ GNUNET_assert (papi->send != NULL);
+ GNUNET_assert (papi->get_session != NULL);
+ struct Session * session = papi->get_session(papi->cls, ve->address);
+
+ if (session != NULL)
+ {
+ ret = papi->send (papi->cls, session,
+ message_buf, tsize,
+ PING_PRIORITY, ACCEPTABLE_PING_DELAY,
+ NULL, NULL);
+ }
+ else
+ {
+ /* Could not get a valid session */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Could not get a valid session for `%s' %s\n",
+ GNUNET_i2s (pid), GST_plugins_a2s (ve->address));
+ ret = -1;
+ }
+ }
+ }
+ if (-1 != ret)
+ {
+ ve->send_time = GNUNET_TIME_absolute_get ();
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# PING without HELLO messages sent"), 1,
+ GNUNET_NO);
+ ve->expecting_pong = GNUNET_YES;
+ }
+}
+
+
+/**
+ * Do address validation again to keep address valid.
+ *
+ * @param cls the 'struct ValidationEntry'
+ * @param tc scheduler context (unused)
+ */
+static void
+revalidate_address (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ValidationEntry *ve = cls;
+ struct GNUNET_TIME_Relative canonical_delay;
+ struct GNUNET_TIME_Relative delay;
+ struct GST_BlacklistCheck *bc;
+ uint32_t rdelay;
+
+ ve->revalidation_task = GNUNET_SCHEDULER_NO_TASK;
+ delay = GNUNET_TIME_absolute_get_remaining (ve->revalidation_block);
+ /* How long until we can possibly permit the next PING? */
+ canonical_delay =
+ (ve->in_use ==
+ GNUNET_YES) ? CONNECTED_PING_FREQUENCY
+ : ((GNUNET_TIME_absolute_get_remaining (ve->valid_until).rel_value >
+ 0) ? VALIDATED_PING_FREQUENCY : UNVALIDATED_PING_KEEPALIVE);
+ if (delay.rel_value > canonical_delay.rel_value * 2)
+ {
+ /* situation changed, recalculate delay */
+ delay = canonical_delay;
+ ve->revalidation_block = GNUNET_TIME_relative_to_absolute (delay);
+ }
+ if (delay.rel_value > 0)
+ {
+ /* should wait a bit longer */
+ ve->revalidation_task =
+ GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve);
+ return;
+ }
+ ve->revalidation_block = GNUNET_TIME_relative_to_absolute (canonical_delay);
+
+ /* schedule next PINGing with some extra random delay to avoid synchronous re-validations */
+ rdelay =
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK,
+ canonical_delay.rel_value);
+ delay =
+ GNUNET_TIME_relative_add (canonical_delay,
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MILLISECONDS, rdelay));
+ ve->revalidation_task =
+ GNUNET_SCHEDULER_add_delayed (delay, &revalidate_address, ve);
+
+ /* start PINGing by checking blacklist */
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# address revalidations started"), 1,
+ GNUNET_NO);
+ bc = GST_blacklist_test_allowed (&ve->pid, ve->address->transport_name,
+ &transmit_ping_if_allowed, ve);
+ if (NULL != bc)
+ ve->bc = bc; /* only set 'bc' if 'transmit_ping_if_allowed' was not already
+ * called... */
+}
+
+
+/**
+ * Find a ValidationEntry entry for the given neighbour that matches
+ * the given address and transport. If none exists, create one (but
+ * without starting any validation).
+ *
+ * @param public_key public key of the peer, NULL for unknown
+ * @param address address to find
+ * @return validation entry matching the given specifications, NULL
+ * if we don't have an existing entry and no public key was given
+ */
+static struct ValidationEntry *
+find_validation_entry (const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
+ *public_key, const struct GNUNET_HELLO_Address *address)
+{
+ struct ValidationEntryMatchContext vemc;
+ struct ValidationEntry *ve;
+
+ vemc.ve = NULL;
+ vemc.address = address;
+ GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
+ &address->peer.hashPubKey,
+ &validation_entry_match, &vemc);
+ if (NULL != (ve = vemc.ve))
+ return ve;
+ if (public_key == NULL)
+ return NULL;
+ ve = GNUNET_malloc (sizeof (struct ValidationEntry));
+ ve->address = GNUNET_HELLO_address_copy (address);
+ ve->public_key = *public_key;
+ ve->pid = address->peer;
+ ve->latency = GNUNET_TIME_UNIT_FOREVER_REL;
+ ve->challenge =
+ GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_NONCE, UINT32_MAX);
+ ve->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (UNVALIDATED_PING_KEEPALIVE,
+ &timeout_hello_validation, ve);
+ GNUNET_CONTAINER_multihashmap_put (validation_map, &address->peer.hashPubKey,
+ ve,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ ve->expecting_pong = GNUNET_NO;
+ return ve;
+}
+
+
+/**
+ * Iterator which adds the given address to the set of validated
+ * addresses.
+ *
+ * @param cls original HELLO message
+ * @param address the address
+ * @param expiration expiration time
+ * @return GNUNET_OK (keep the address)
+ */
+static int
+add_valid_address (void *cls, const struct GNUNET_HELLO_Address *address,
+ struct GNUNET_TIME_Absolute expiration)
+{
+ const struct GNUNET_HELLO_Message *hello = cls;
+ struct ValidationEntry *ve;
+ struct GNUNET_PeerIdentity pid;
+ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
+
+ if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0)
+ return GNUNET_OK; /* expired */
+ if ((GNUNET_OK != GNUNET_HELLO_get_id (hello, &pid)) ||
+ (GNUNET_OK != GNUNET_HELLO_get_key (hello, &public_key)))
+ {
+ GNUNET_break (0);
+ return GNUNET_OK; /* invalid HELLO !? */
+ }
+ if (0 == memcmp (&GST_my_identity, &pid, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ /* Peerinfo returned own identity, skip validation */
+ return GNUNET_OK;
+ }
+
+ ve = find_validation_entry (&public_key, address);
+ ve->valid_until = GNUNET_TIME_absolute_max (ve->valid_until, expiration);
+
+ if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task)
+ ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve);
+ GNUNET_ATS_address_update (GST_ats, address, NULL, NULL, 0);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called for any HELLO known to PEERINFO.
+ *
+ * @param cls unused
+ * @param peer id of the peer, NULL for last call
+ * @param hello hello message for the peer (can be NULL)
+ * @param err_msg error message
+ */
+static void
+process_peerinfo_hello (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Message *hello,
+ const char *err_msg)
+{
+ GNUNET_assert (NULL != peer);
+ if (NULL == hello)
+ return;
+ GNUNET_assert (NULL ==
+ GNUNET_HELLO_iterate_addresses (hello, GNUNET_NO,
+ &add_valid_address,
+ (void *) hello));
+}
+
+
+/**
+ * Start the validation subsystem.
+ */
+void
+GST_validation_start ()
+{
+ validation_map = GNUNET_CONTAINER_multihashmap_create (VALIDATION_MAP_SIZE);
+ pnc = GNUNET_PEERINFO_notify (GST_cfg, &process_peerinfo_hello, NULL);
+}
+
+
+/**
+ * Stop the validation subsystem.
+ */
+void
+GST_validation_stop ()
+{
+ struct CheckHelloValidatedContext *chvc;
+
+ GNUNET_CONTAINER_multihashmap_iterate (validation_map,
+ &cleanup_validation_entry, NULL);
+ GNUNET_CONTAINER_multihashmap_destroy (validation_map);
+ validation_map = NULL;
+ while (NULL != (chvc = chvc_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (chvc_head, chvc_tail, chvc);
+ GNUNET_free (chvc);
+ }
+ GNUNET_PEERINFO_notify_cancel (pnc);
+}
+
+
+/**
+ * Send the given PONG to the given address.
+ *
+ * @param cls the PONG message
+ * @param public_key public key for the peer, never NULL
+ * @param valid_until is ZERO if we never validated the address,
+ * otherwise a time up to when we consider it (or was) valid
+ * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO)
+ * is ZERO if the address is considered valid (no validation needed)
+ * otherwise a time in the future if we're currently denying re-validation
+ * @param address target address
+ */
+static void
+multicast_pong (void *cls,
+ const struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
+ *public_key, struct GNUNET_TIME_Absolute valid_until,
+ struct GNUNET_TIME_Absolute validation_block,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct TransportPongMessage *pong = cls;
+ struct GNUNET_TRANSPORT_PluginFunctions *papi;
+
+ papi = GST_plugins_find (address->transport_name);
+ if (papi == NULL)
+ return;
+
+ GNUNET_assert (papi->send != NULL);
+ GNUNET_assert (papi->get_session != NULL);
+
+ struct Session * session = papi->get_session(papi->cls, address);
+ if (session == NULL)
+ {
+ GNUNET_break (0);
+ return;
+ }
+
+ papi->send (papi->cls, session,
+ (const char *) pong, ntohs (pong->header.size),
+ PONG_PRIORITY, ACCEPTABLE_PING_DELAY,
+ NULL, NULL);
+}
+
+
+/**
+ * We've received a PING. If appropriate, generate a PONG.
+ *
+ * @param sender peer sending the PING
+ * @param hdr the PING
+ * @param sender_address the sender address as we got it
+ * @param session session we got the PING from
+ */
+void
+GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *hdr,
+ const struct GNUNET_HELLO_Address *sender_address,
+ struct Session *session)
+{
+ const struct TransportPingMessage *ping;
+ struct TransportPongMessage *pong;
+ struct GNUNET_TRANSPORT_PluginFunctions *papi;
+ struct GNUNET_CRYPTO_RsaSignature *sig_cache;
+ struct GNUNET_TIME_Absolute *sig_cache_exp;
+ const char *addr;
+ const char *addrend;
+ size_t alen;
+ size_t slen;
+ ssize_t ret;
+ struct GNUNET_HELLO_Address address;
+
+ if (ntohs (hdr->size) < sizeof (struct TransportPingMessage))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ ping = (const struct TransportPingMessage *) hdr;
+ if (0 !=
+ memcmp (&ping->target, &GST_my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# PING message for different peer received"), 1,
+ GNUNET_NO);
+ return;
+ }
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# PING messages received"), 1,
+ GNUNET_NO);
+ addr = (const char *) &ping[1];
+ alen = ntohs (hdr->size) - sizeof (struct TransportPingMessage);
+ /* peer wants to confirm that this is one of our addresses, this is what is
+ * used for address validation */
+
+ sig_cache = NULL;
+ sig_cache_exp = NULL;
+
+ if (0 < alen)
+ {
+ addrend = memchr (addr, '\0', alen);
+ if (NULL == addrend)
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ addrend++;
+ slen = strlen (addr) + 1;
+ alen -= slen;
+ address.address = addrend;
+ address.address_length = alen;
+ address.transport_name = addr;
+ address.peer = *sender;
+ if (GNUNET_YES !=
+ GST_hello_test_address (&address, &sig_cache, &sig_cache_exp))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_INFO,
+ _
+ ("Not confirming PING with address `%s' since I cannot confirm having this address.\n"),
+ GST_plugins_a2s (&address));
+ return;
+ }
+ }
+ else
+ {
+ addrend = NULL; /* make gcc happy */
+ slen = 0;
+ static struct GNUNET_CRYPTO_RsaSignature no_address_signature;
+ static struct GNUNET_TIME_Absolute no_address_signature_expiration;
+
+ sig_cache = &no_address_signature;
+ sig_cache_exp = &no_address_signature_expiration;
+ }
+
+ pong = GNUNET_malloc (sizeof (struct TransportPongMessage) + alen + slen);
+ pong->header.size =
+ htons (sizeof (struct TransportPongMessage) + alen + slen);
+ pong->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_PONG);
+ pong->purpose.size =
+ htonl (sizeof (struct GNUNET_CRYPTO_RsaSignaturePurpose) +
+ sizeof (uint32_t) + sizeof (struct GNUNET_TIME_AbsoluteNBO) +
+ alen + slen);
+ pong->purpose.purpose = htonl (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN);
+ pong->challenge = ping->challenge;
+ pong->addrlen = htonl (alen + slen);
+ memcpy (&pong[1], addr, slen);
+ memcpy (&((char *) &pong[1])[slen], addrend, alen);
+ if (GNUNET_TIME_absolute_get_remaining (*sig_cache_exp).rel_value <
+ PONG_SIGNATURE_LIFETIME.rel_value / 4)
+ {
+ /* create / update cached sig */
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating PONG signature to indicate ownership.\n");
+#endif
+ *sig_cache_exp = GNUNET_TIME_relative_to_absolute (PONG_SIGNATURE_LIFETIME);
+ pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CRYPTO_rsa_sign (GST_my_private_key, &pong->purpose,
+ sig_cache));
+ }
+ else
+ {
+ pong->expiration = GNUNET_TIME_absolute_hton (*sig_cache_exp);
+ }
+ pong->signature = *sig_cache;
+
+ GNUNET_assert (sender_address != NULL);
+
+ /* first see if the session we got this PING from can be used to transmit
+ * a response reliably */
+ papi = GST_plugins_find (sender_address->transport_name);
+ if (papi == NULL)
+ ret = -1;
+ else
+ {
+ GNUNET_assert (papi->send != NULL);
+ GNUNET_assert (papi->get_session != NULL);
+
+ if (session == NULL)
+ {
+ session = papi->get_session (papi->cls, sender_address);
+ }
+ if (session == NULL)
+ {
+ GNUNET_break (0);
+ ret = -1;
+ }
+ else
+ {
+ ret = papi->send (papi->cls, session,
+ (const char *) pong, ntohs (pong->header.size),
+ PONG_PRIORITY, ACCEPTABLE_PING_DELAY,
+ NULL, NULL);
+ }
+ }
+ if (ret != -1)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitted PONG to `%s' via reliable mechanism\n",
+ GNUNET_i2s (sender));
+ /* done! */
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# PONGs unicast via reliable transport"), 1,
+ GNUNET_NO);
+ GNUNET_free (pong);
+ return;
+ }
+
+ /* no reliable method found, try transmission via all known addresses */
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# PONGs multicast to all available addresses"), 1,
+ GNUNET_NO);
+ GST_validation_get_addresses (sender, &multicast_pong, pong);
+ GNUNET_free (pong);
+}
+
+
+/**
+ * Context for the 'validate_address' function
+ */
+struct ValidateAddressContext
+{
+ /**
+ * Hash of the public key of the peer whose address is being validated.
+ */
+ struct GNUNET_PeerIdentity pid;
+
+ /**
+ * Public key of the peer whose address is being validated.
+ */
+ struct GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded public_key;
+};
+
+
+/**
+ * Iterator callback to go over all addresses and try to validate them
+ * (unless blocked or already validated).
+ *
+ * @param cls pointer to a 'struct ValidateAddressContext'
+ * @param address the address
+ * @param expiration expiration time
+ * @return GNUNET_OK (keep the address)
+ */
+static int
+validate_address_iterator (void *cls,
+ const struct GNUNET_HELLO_Address *address,
+ struct GNUNET_TIME_Absolute expiration)
+{
+ const struct ValidateAddressContext *vac = cls;
+ struct ValidationEntry *ve;
+
+ if (GNUNET_TIME_absolute_get_remaining (expiration).rel_value == 0)
+ return GNUNET_OK; /* expired */
+ ve = find_validation_entry (&vac->public_key, address);
+ if (GNUNET_SCHEDULER_NO_TASK == ve->revalidation_task)
+ ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Add the validated peer address to the HELLO.
+ *
+ * @param cls the 'struct ValidationEntry' with the validated address
+ * @param max space in buf
+ * @param buf where to add the address
+ * @return number of bytes written, 0 to signal the
+ * end of the iteration.
+ */
+static size_t
+add_valid_peer_address (void *cls, size_t max, void *buf)
+{
+ struct ValidationEntry *ve = cls;
+
+ if (GNUNET_YES == ve->copied)
+ return 0; /* terminate */
+ ve->copied = GNUNET_YES;
+ return GNUNET_HELLO_add_address (ve->address, ve->valid_until, buf, max);
+}
+
+
+/**
+ * We've received a PONG. Check if it matches a pending PING and
+ * mark the respective address as confirmed.
+ *
+ * @param sender peer sending the PONG
+ * @param hdr the PONG
+ */
+void
+GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *hdr)
+{
+ const struct TransportPongMessage *pong;
+ struct ValidationEntry *ve;
+ const char *tname;
+ const char *addr;
+ size_t addrlen;
+ size_t slen;
+ size_t size;
+ struct GNUNET_HELLO_Message *hello;
+ struct GNUNET_HELLO_Address address;
+
+ if (ntohs (hdr->size) < sizeof (struct TransportPongMessage))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop ("# PONG messages received"), 1,
+ GNUNET_NO);
+
+ pong = (const struct TransportPongMessage *) hdr;
+ tname = (const char *) &pong[1];
+ size = ntohs (hdr->size) - sizeof (struct TransportPongMessage);
+ addr = memchr (tname, '\0', size);
+ if (NULL == addr)
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ addr++;
+ slen = strlen (tname) + 1;
+ addrlen = size - slen;
+ address.peer = *sender;
+ address.address = addr;
+ address.address_length = addrlen;
+ address.transport_name = tname;
+ ve = find_validation_entry (NULL, &address);
+ if ((NULL == ve) || (ve->expecting_pong == GNUNET_NO))
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# PONGs dropped, no matching pending validation"),
+ 1, GNUNET_NO);
+ return;
+ }
+ /* now check that PONG is well-formed */
+ if (0 != memcmp (&ve->pid, sender, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CRYPTO_rsa_verify (GNUNET_SIGNATURE_PURPOSE_TRANSPORT_PONG_OWN,
+ &pong->purpose, &pong->signature,
+ &ve->public_key))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+
+ if (GNUNET_TIME_absolute_get_remaining
+ (GNUNET_TIME_absolute_ntoh (pong->expiration)).rel_value == 0)
+ {
+ GNUNET_STATISTICS_update (GST_stats,
+ gettext_noop
+ ("# PONGs dropped, signature expired"), 1,
+ GNUNET_NO);
+ return;
+ }
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Address validated for peer `%s' with plugin `%s': `%s'\n",
+ GNUNET_i2s (sender), tname, GST_plugins_a2s (tname, addr,
+ addrlen));
+#endif
+
+ /* validity achieved, remember it! */
+ ve->expecting_pong = GNUNET_NO;
+ ve->valid_until = GNUNET_TIME_relative_to_absolute (HELLO_ADDRESS_EXPIRATION);
+ ve->latency = GNUNET_TIME_absolute_get_duration (ve->send_time);
+ {
+ struct GNUNET_ATS_Information ats;
+
+ ats.type = htonl (GNUNET_ATS_QUALITY_NET_DELAY);
+ ats.value = htonl ((uint32_t) ve->latency.rel_value);
+ GNUNET_ATS_address_update (GST_ats, ve->address, NULL, &ats, 1);
+ }
+ /* build HELLO to store in PEERINFO */
+ ve->copied = GNUNET_NO;
+ hello = GNUNET_HELLO_create (&ve->public_key, &add_valid_peer_address, ve);
+ GNUNET_PEERINFO_add_peer (GST_peerinfo, hello);
+ GNUNET_free (hello);
+}
+
+
+/**
+ * We've received a HELLO, check which addresses are new and trigger
+ * validation.
+ *
+ * @param hello the HELLO we received
+ */
+void
+GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello)
+{
+ const struct GNUNET_HELLO_Message *hm =
+ (const struct GNUNET_HELLO_Message *) hello;
+ struct ValidateAddressContext vac;
+ struct GNUNET_HELLO_Message *h;
+
+ if ((GNUNET_OK != GNUNET_HELLO_get_id (hm, &vac.pid)) ||
+ (GNUNET_OK != GNUNET_HELLO_get_key (hm, &vac.public_key)))
+ {
+ /* malformed HELLO */
+ GNUNET_break (0);
+ return;
+ }
+ if (0 ==
+ memcmp (&GST_my_identity, &vac.pid, sizeof (struct GNUNET_PeerIdentity)))
+ return;
+ /* Add peer identity without addresses to peerinfo service */
+ h = GNUNET_HELLO_create (&vac.public_key, NULL, NULL);
+ GNUNET_PEERINFO_add_peer (GST_peerinfo, h);
+#if VERBOSE_VALIDATION
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ _("Adding `%s' without addresses for peer `%s'\n"), "HELLO",
+ GNUNET_i2s (&vac.pid));
+#endif
+ GNUNET_free (h);
+ GNUNET_assert (NULL ==
+ GNUNET_HELLO_iterate_addresses (hm, GNUNET_NO,
+ &validate_address_iterator,
+ &vac));
+}
+
+
+/**
+ * Closure for 'iterate_addresses'
+ */
+struct IteratorContext
+{
+ /**
+ * Function to call on each address.
+ */
+ GST_ValidationAddressCallback cb;
+
+ /**
+ * Closure for 'cb'.
+ */
+ void *cb_cls;
+
+};
+
+
+/**
+ * Call the callback in the closure for each validation entry.
+ *
+ * @param cls the 'struct GST_ValidationIteratorContext'
+ * @param key the peer's identity
+ * @param value the 'struct ValidationEntry'
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+iterate_addresses (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct IteratorContext *ic = cls;
+ struct ValidationEntry *ve = value;
+
+ ic->cb (ic->cb_cls, &ve->public_key, ve->valid_until, ve->revalidation_block,
+ ve->address);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Call the given function for each address for the given target.
+ * Can either give a snapshot (synchronous API) or be continuous.
+ *
+ * @param target peer information is requested for
+ * @param cb function to call; will not be called after this function returns
+ * @param cb_cls closure for 'cb'
+ */
+void
+GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target,
+ GST_ValidationAddressCallback cb, void *cb_cls)
+{
+ struct IteratorContext ic;
+
+ ic.cb = cb;
+ ic.cb_cls = cb_cls;
+ GNUNET_CONTAINER_multihashmap_get_multiple (validation_map,
+ &target->hashPubKey,
+ &iterate_addresses, &ic);
+}
+
+
+/**
+ * Update if we are using an address for a connection actively right now.
+ * Based on this, the validation module will measure latency for the
+ * address more or less often.
+ *
+ * @param address the address
+ * @param session the session
+ * @param in_use GNUNET_YES if we are now using the address for a connection,
+ * GNUNET_NO if we are no longer using the address for a connection
+ */
+void
+GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address,
+ struct Session *session,
+ int in_use)
+{
+ struct ValidationEntry *ve;
+
+ if (NULL != address)
+ ve = find_validation_entry (NULL, address);
+ else
+ ve = NULL; /* FIXME: lookup based on session... */
+ if (NULL == ve)
+ {
+ /* this can happen for inbound connections (sender_address_len == 0); */
+ return;
+ }
+ if (ve->in_use == in_use)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "GST_validation_set_address_use: %s %s: ve->in_use %i <-> in_use %i\n",
+ GNUNET_i2s (&address->peer), GST_plugins_a2s (address), ve->in_use,
+ in_use);
+ GNUNET_break (ve->in_use != in_use); /* should be different... */
+ ve->in_use = in_use;
+ if (in_use == GNUNET_YES)
+ {
+ /* from now on, higher frequeny, so reschedule now */
+ GNUNET_SCHEDULER_cancel (ve->revalidation_task);
+ ve->revalidation_task = GNUNET_SCHEDULER_add_now (&revalidate_address, ve);
+ }
+}
+
+
+/**
+ * Query validation about the latest observed latency on a given
+ * address.
+ *
+ * @param sender peer
+ * @param address the address
+ * @param session session
+ * @return observed latency of the address, FOREVER if the address was
+ * never successfully validated
+ */
+struct GNUNET_TIME_Relative
+GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session)
+{
+ struct ValidationEntry *ve;
+
+ if (NULL == address)
+ {
+ GNUNET_break (0); // FIXME: support having latency only with session...
+ return GNUNET_TIME_UNIT_FOREVER_REL;
+ }
+ ve = find_validation_entry (NULL, address);
+ if (NULL == ve)
+ return GNUNET_TIME_UNIT_FOREVER_REL;
+ return ve->latency;
+}
+
+
+/* end of file gnunet-service-transport_validation.c */
diff --git a/src/transport/gnunet-service-transport_validation.h b/src/transport/gnunet-service-transport_validation.h
new file mode 100644
index 0000000..9b1063b
--- /dev/null
+++ b/src/transport/gnunet-service-transport_validation.h
@@ -0,0 +1,155 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010,2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-service-transport_validation.h
+ * @brief address validation API
+ * @author Christian Grothoff
+ */
+#ifndef GNUNET_SERVICE_TRANSPORT_VALIDATION_H
+#define GNUNET_SERVICE_TRANSPORT_VALIDATION_H
+
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_plugin.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_hello_lib.h"
+
+
+/**
+ * Start the validation subsystem.
+ */
+void
+GST_validation_start (void);
+
+
+/**
+ * Stop the validation subsystem.
+ */
+void
+GST_validation_stop (void);
+
+
+/**
+ * Update if we are using an address for a connection actively right now.
+ * Based on this, the validation module will measure latency for the
+ * address more or less often.
+ *
+ * @param address the address
+ * @param session session
+ * @param in_use GNUNET_YES if we are now using the address for a connection,
+ * GNUNET_NO if we are no longer using the address for a connection
+ */
+void
+GST_validation_set_address_use (const struct GNUNET_HELLO_Address *address,
+ struct Session *session, int in_use);
+
+
+/**
+ * Query validation about the latest observed latency on a given
+ * address.
+ *
+ * @param sender peer
+ * @param address the address
+ * @param session session
+ * @return observed latency of the address, FOREVER if the address was
+ * never successfully validated
+ */
+struct GNUNET_TIME_Relative
+GST_validation_get_address_latency (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_HELLO_Address *address,
+ struct Session *session);
+
+
+/**
+ * We've received a PING. If appropriate, generate a PONG.
+ *
+ * @param sender peer sending the PING
+ * @param hdr the PING
+ * @param sender_address address of the sender, NULL if we did not initiate
+ * @param session session we got the PING from
+ */
+void
+GST_validation_handle_ping (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *hdr,
+ const struct GNUNET_HELLO_Address *sender_address,
+ struct Session *session);
+
+
+/**
+ * We've received a PONG. Check if it matches a pending PING and
+ * mark the respective address as confirmed.
+ *
+ * @param sender peer sending the PONG
+ * @param hdr the PONG
+ */
+void
+GST_validation_handle_pong (const struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *hdr);
+
+
+/**
+ * We've received a HELLO, check which addresses are new and trigger
+ * validation.
+ *
+ * @param hello the HELLO we received
+ */
+void
+GST_validation_handle_hello (const struct GNUNET_MessageHeader *hello);
+
+
+/**
+ * Function called for each address (or address status change) that
+ * the validation module is aware of (for the given target).
+ *
+ * @param cls closure
+ * @param public_key public key for the peer, never NULL
+ * @param valid_until is ZERO if we never validated the address,
+ * otherwise a time up to when we consider it (or was) valid
+ * @param validation_block is FOREVER if the address is for an unsupported plugin (from PEERINFO)
+ * is ZERO if the address is considered valid (no validation needed)
+ * otherwise a time in the future if we're currently denying re-validation
+ * @param address the address
+ */
+typedef void (*GST_ValidationAddressCallback) (void *cls,
+ const struct
+ GNUNET_CRYPTO_RsaPublicKeyBinaryEncoded
+ * public_key,
+ struct GNUNET_TIME_Absolute
+ valid_until,
+ struct GNUNET_TIME_Absolute
+ validation_block,
+ const struct GNUNET_HELLO_Address
+ * address);
+
+
+/**
+ * Call the given function for each address for the given target.
+ *
+ * @param target peer information is requested for
+ * @param cb function to call; will not be called after this function returns
+ * @param cb_cls closure for 'cb'
+ */
+void
+GST_validation_get_addresses (const struct GNUNET_PeerIdentity *target,
+ GST_ValidationAddressCallback cb, void *cb_cls);
+
+
+#endif
+/* end of file gnunet-service-transport_validation.h */
diff --git a/src/transport/gnunet-transport-certificate-creation b/src/transport/gnunet-transport-certificate-creation
new file mode 100755
index 0000000..a38a7b7
--- /dev/null
+++ b/src/transport/gnunet-transport-certificate-creation
@@ -0,0 +1,148 @@
+#! /bin/bash
+
+# gnunet-transport-certificate-creation - temporary wrapper script for .libs/gnunet-transport-certificate-creation
+# Generated by ltmain.sh (GNU libtool) 2.2.6b Debian-2.2.6b-2
+#
+# The gnunet-transport-certificate-creation program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed='/bin/sed -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command="(cd /home/grothoff/svn/gnunet/src/transport; { test -z \"\${LIBRARY_PATH+set}\" || unset LIBRARY_PATH || { LIBRARY_PATH=; export LIBRARY_PATH; }; }; { test -z \"\${COMPILER_PATH+set}\" || unset COMPILER_PATH || { COMPILER_PATH=; export COMPILER_PATH; }; }; { test -z \"\${GCC_EXEC_PREFIX+set}\" || unset GCC_EXEC_PREFIX || { GCC_EXEC_PREFIX=; export GCC_EXEC_PREFIX; }; }; { test -z \"\${LD_RUN_PATH+set}\" || unset LD_RUN_PATH || { LD_RUN_PATH=; export LD_RUN_PATH; }; }; LD_LIBRARY_PATH=/usr/lib/debug:/home/grothoff/lib; export LD_LIBRARY_PATH; PATH=/opt/jdk1.6.0_22/bin:/usr/lib/jvm/java-6-sun//bin:.:/home/grothoff/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games; export PATH; gcc -fno-strict-aliasing -Wall -g -Wall -Werror -O0 -I/home/grothoff//include -o \$progdir/\$file gnunet-transport-certificate-creation.o -L/home/grothoff//lib ../../src/util/.libs/libgnunetutil.so -ldl -Wl,-rpath -Wl,/home/grothoff/svn/gnunet/src/util/.libs -Wl,-rpath -Wl,/home/grothoff/lib)"
+
+# This environment variable determines our operation mode.
+if test "$libtool_install_magic" = "%%%MAGIC variable%%%"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='2.2.6b'
+ notinst_deplibs=' ../../src/util/libgnunetutil.la'
+else
+ # When we are sourced in execute mode, $file and $ECHO are already set.
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ ECHO="echo"
+ file="$0"
+ # Make sure echo works.
+ if test "X$1" = X--no-reexec; then
+ # Discard the --no-reexec flag, and continue.
+ shift
+ elif test "X`{ $ECHO '\t'; } 2>/dev/null`" = 'X\t'; then
+ # Yippee, $ECHO works!
+ :
+ else
+ # Restart under the correct shell, and then maybe $ECHO will work.
+ exec /bin/bash "$0" --no-reexec ${1+"$@"}
+ fi
+ fi
+
+ # Find the directory that this script lives in.
+ thisdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'`
+ test "x$thisdir" = "x$file" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=`ls -ld "$file" | /bin/sed -n 's/.*-> //p'`
+ while test -n "$file"; do
+ destdir=`$ECHO "X$file" | $Xsed -e 's%/[^/]*$%%'`
+
+ # If there was a directory component, then change thisdir.
+ if test "x$destdir" != "x$file"; then
+ case "$destdir" in
+ [\\/]* | [A-Za-z]:[\\/]*) thisdir="$destdir" ;;
+ *) thisdir="$thisdir/$destdir" ;;
+ esac
+ fi
+
+ file=`$ECHO "X$file" | $Xsed -e 's%^.*/%%'`
+ file=`ls -ld "$thisdir/$file" | /bin/sed -n 's/.*-> //p'`
+ done
+
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=no
+ if test "$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR" = "yes"; then
+ # special case for '.'
+ if test "$thisdir" = "."; then
+ thisdir=`pwd`
+ fi
+ # remove .libs from thisdir
+ case "$thisdir" in
+ *[\\/].libs ) thisdir=`$ECHO "X$thisdir" | $Xsed -e 's%[\\/][^\\/]*$%%'` ;;
+ .libs ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=`cd "$thisdir" && pwd`
+ test -n "$absdir" && thisdir="$absdir"
+
+ program=lt-'gnunet-transport-certificate-creation'
+ progdir="$thisdir/.libs"
+
+ if test ! -f "$progdir/$program" ||
+ { file=`ls -1dt "$progdir/$program" "$progdir/../$program" 2>/dev/null | /bin/sed 1q`; \
+ test "X$file" != "X$progdir/$program"; }; then
+
+ file="$$-$program"
+
+ if test ! -d "$progdir"; then
+ mkdir "$progdir"
+ else
+ rm -f "$progdir/$file"
+ fi
+
+ # relink executable if necessary
+ if test -n "$relink_command"; then
+ if relink_command_output=`eval $relink_command 2>&1`; then :
+ else
+ echo "$relink_command_output" >&2
+ rm -f "$progdir/$file"
+ exit 1
+ fi
+ fi
+
+ mv -f "$progdir/$file" "$progdir/$program" 2>/dev/null ||
+ { rm -f "$progdir/$program";
+ mv -f "$progdir/$file" "$progdir/$program"; }
+ rm -f "$progdir/$file"
+ fi
+
+ if test -f "$progdir/$program"; then
+ if test "$libtool_execute_magic" != "%%%MAGIC variable%%%"; then
+ # Run the actual program with our arguments.
+
+ exec "$progdir/$program" ${1+"$@"}
+
+ $ECHO "$0: cannot exec $program $*" 1>&2
+ exit 1
+ fi
+ else
+ # The program doesn't exist.
+ $ECHO "$0: error: \`$progdir/$program' does not exist" 1>&2
+ $ECHO "This script is just a wrapper for $program." 1>&2
+ echo "See the libtool documentation for more information." 1>&2
+ exit 1
+ fi
+fi
diff --git a/src/transport/gnunet-transport-certificate-creation.c b/src/transport/gnunet-transport-certificate-creation.c
new file mode 100644
index 0000000..2ec8d36
--- /dev/null
+++ b/src/transport/gnunet-transport-certificate-creation.c
@@ -0,0 +1,82 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/gnunet-transport-certificate-creation.c
+ * @brief create certificate for HTTPS transport
+ * @author LRN
+ *
+ */
+#include "platform.h"
+#include "gnunet_disk_lib.h"
+#include "gnunet_os_lib.h"
+
+
+static void
+removecerts (const char *file1, const char *file2)
+{
+ if (GNUNET_DISK_file_test (file1) == GNUNET_YES)
+ {
+ CHMOD (file1, S_IWUSR | S_IRUSR);
+ REMOVE (file1);
+ }
+ if (GNUNET_DISK_file_test (file2) == GNUNET_YES)
+ {
+ CHMOD (file2, S_IWUSR | S_IRUSR);
+ REMOVE (file2);
+ }
+}
+
+
+int
+main (int argc, char **argv)
+{
+ struct GNUNET_OS_Process *openssl;
+
+ if (argc != 3)
+ return 1;
+ removecerts (argv[1], argv[2]);
+ close (2); /* eliminate stderr */
+ /* Create RSA Private Key */
+ /* openssl genrsa -out $1 1024 2> /dev/null */
+ openssl =
+ GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "openssl", "openssl", "genrsa",
+ "-out", argv[1], "1024", NULL);
+ if (openssl == NULL)
+ return 2;
+ GNUNET_assert (GNUNET_OS_process_wait (openssl) == GNUNET_OK);
+ GNUNET_OS_process_close (openssl);
+
+ /* Create a self-signed certificate in batch mode using rsa key */
+ /* openssl req -batch -days 365 -out $2 -new -x509 -key $1 2> /dev/null */
+ openssl =
+ GNUNET_OS_start_process (GNUNET_NO, NULL, NULL, "openssl", "openssl", "req",
+ "-batch", "-days", "365", "-out", argv[2],
+ "-new", "-x509", "-key", argv[1], NULL);
+ if (openssl == NULL)
+ return 3;
+ GNUNET_assert (GNUNET_OS_process_wait (openssl) == GNUNET_OK);
+ GNUNET_OS_process_close (openssl);
+ CHMOD (argv[1], S_IRUSR);
+ CHMOD (argv[2], S_IRUSR);
+ return 0;
+}
+
+/* end of gnunet-transport-certificate-creation.c */
diff --git a/src/transport/gnunet-transport-wlan-sender.c b/src/transport/gnunet-transport-wlan-sender.c
new file mode 100644
index 0000000..9f06b63
--- /dev/null
+++ b/src/transport/gnunet-transport-wlan-sender.c
@@ -0,0 +1,237 @@
+/*
+ This file is part of GNUnet
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file transport/gnunet-transport-wlan-sender.c
+ * @brief program to send via WLAN as much as possible (to test physical/theoretical throughput)
+ * @author David Brodski
+ */
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "plugin_transport_wlan.h"
+
+#define WLAN_MTU 1500
+
+/**
+ * LLC fields for better compatibility
+ */
+#define WLAN_LLC_DSAP_FIELD 0x1f
+#define WLAN_LLC_SSAP_FIELD 0x1f
+
+#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */
+
+#define IEEE80211_FC0_VERSION_MASK 0x03
+#define IEEE80211_FC0_VERSION_SHIFT 0
+#define IEEE80211_FC0_VERSION_0 0x00
+#define IEEE80211_FC0_TYPE_MASK 0x0c
+#define IEEE80211_FC0_TYPE_SHIFT 2
+#define IEEE80211_FC0_TYPE_MGT 0x00
+#define IEEE80211_FC0_TYPE_CTL 0x04
+#define IEEE80211_FC0_TYPE_DATA 0x08
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/*
+ * generic definitions for IEEE 802.11 frames
+ */
+struct ieee80211_frame
+{
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2];
+ u_int8_t i_addr1[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr2[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr3[IEEE80211_ADDR_LEN];
+ u_int8_t i_seq[2];
+ u_int8_t llc[4];
+} GNUNET_PACKED;
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * function to fill the radiotap header
+ * @param header pointer to the radiotap header
+ * @return GNUNET_YES at success
+ */
+static int
+getRadiotapHeader (struct Radiotap_Send *header)
+{
+ header->rate = 255;
+ header->tx_power = 0;
+ header->antenna = 0;
+
+ return GNUNET_YES;
+}
+
+/**
+ * function to generate the wlan hardware header for one packet
+ * @param Header address to write the header to
+ * @param to_mac_addr pointer to the address of the recipient
+ * @param mac pointer to the mac address to send from (normally overwritten over by helper)
+ * @param size size of the whole packet, needed to calculate the time to send the packet
+ * @return GNUNET_YES if there was no error
+ */
+static int
+getWlanHeader (struct ieee80211_frame *Header, const char *to_mac_addr,
+ const char *mac, unsigned int size)
+{
+ uint16_t *tmp16;
+ const int rate = 11000000;
+
+ Header->i_fc[0] = IEEE80211_FC0_TYPE_DATA;
+ Header->i_fc[1] = 0x00;
+ memcpy (&Header->i_addr3, &mac_bssid_gnunet, sizeof (mac_bssid_gnunet));
+ memcpy (&Header->i_addr2, mac, sizeof (mac_bssid_gnunet));
+ memcpy (&Header->i_addr1, to_mac_addr, sizeof (mac_bssid_gnunet));
+
+ tmp16 = (uint16_t *) Header->i_dur;
+ *tmp16 = (uint16_t) GNUNET_htole16 ((size * 1000000) / rate + 290);
+ Header->llc[0] = WLAN_LLC_DSAP_FIELD;
+ Header->llc[1] = WLAN_LLC_SSAP_FIELD;
+
+ return GNUNET_YES;
+}
+
+
+int
+main (int argc, char *argv[])
+{
+ char msg_buf[WLAN_MTU];
+ struct GNUNET_MessageHeader *msg;
+ struct ieee80211_frame *wlan_header;
+ struct Radiotap_Send *radiotap;
+
+ unsigned int temp[6];
+ char inmac[6];
+ char outmac[6];
+ int pos;
+ long long count;
+ double bytes_per_s;
+ time_t start;
+ time_t akt;
+ int i;
+
+ if (4 != argc)
+ {
+ fprintf (stderr,
+ "This program must be started with the interface and the targets and source mac as argument.\n");
+ fprintf (stderr,
+ "Usage: interface-name mac-target mac-source\n"
+ "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n");
+ return 1;
+ }
+ if (6 !=
+ sscanf (argv[3], "%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2],
+ &temp[3], &temp[4], &temp[5]))
+ {
+ fprintf (stderr,
+ "Usage: interface-name mac-target mac-source\n"
+ "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n");
+ return 1;
+ }
+ if (6 !=
+ sscanf (argv[2], "%x-%x-%x-%x-%x-%x", &temp[0], &temp[1], &temp[2],
+ &temp[3], &temp[4], &temp[5]))
+ {
+ fprintf (stderr,
+ "Usage: interface-name mac-target mac-source\n"
+ "e.g. mon0 11-22-33-44-55-66 12-34-56-78-90-ab\n");
+ return 1;
+ }
+ for (i = 0; i < 6; i++)
+ inmac[i] = temp[i];
+ for (i = 0; i < 6; i++)
+ outmac[i] = temp[i];
+
+ pid_t pid;
+ int commpipe[2]; /* This holds the fd for the input & output of the pipe */
+
+ /* Setup communication pipeline first */
+ if (pipe (commpipe))
+ {
+ fprintf (stderr,
+ "Failed to create pipe: %s\n",
+ STRERROR (errno));
+ exit (1);
+ }
+
+ /* Attempt to fork and check for errors */
+ if ((pid = fork ()) == -1)
+ {
+ fprintf (stderr, "Failed to fork: %s\n",
+ STRERROR (errno));
+ exit (1);
+ }
+
+ if (pid)
+ {
+ /* A positive (non-negative) PID indicates the parent process */
+ close (commpipe[0]); /* Close unused side of pipe (in side) */
+ setvbuf (stdout, (char *) NULL, _IONBF, 0); /* Set non-buffered output on stdout */
+
+
+ msg = (struct GNUNET_MessageHeader *) msg_buf;
+ msg->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
+ msg->size = htons (WLAN_MTU);
+ radiotap = (struct Radiotap_Send *) &msg[1];
+ wlan_header = (struct ieee80211_frame *) &radiotap[1];
+ pos = 0;
+
+ getRadiotapHeader (radiotap);
+ getWlanHeader (wlan_header, outmac, inmac,
+ WLAN_MTU - sizeof (struct GNUNET_MessageHeader));
+
+ start = time (NULL);
+ count = 0;
+ while (1)
+ {
+ pos += write (commpipe[1], msg, WLAN_MTU - pos);
+ if (pos % WLAN_MTU == 0)
+ {
+ pos = 0;
+ count++;
+
+ if (count % 1000 == 0)
+ {
+ akt = time (NULL);
+ bytes_per_s = count * WLAN_MTU / (akt - start);
+ bytes_per_s /= 1024;
+ printf ("send %f kbytes/s\n", bytes_per_s);
+ }
+ }
+
+ }
+ }
+ else
+ {
+ /* A zero PID indicates that this is the child process */
+ (void) close (0);
+ if (-1 == dup2 (commpipe[0], 0)) /* Replace stdin with the in side of the pipe */
+ fprintf (stderr, "dup2 failed: %s\n", strerror (errno));
+ (void) close (commpipe[1]); /* Close unused side of pipe (out side) */
+ /* Replace the child fork with a new process */
+ if (execl
+ ("gnunet-helper-transport-wlan", "gnunet-helper-transport-wlan",
+ argv[1], NULL) == -1)
+ {
+ fprintf (stderr, "Could not start gnunet-helper-transport-wlan!");
+ _exit (1);
+ }
+ }
+ return 0;
+}
diff --git a/src/transport/gnunet-transport.c b/src/transport/gnunet-transport.c
new file mode 100644
index 0000000..ee977f5
--- /dev/null
+++ b/src/transport/gnunet-transport.c
@@ -0,0 +1,619 @@
+/*
+ This file is part of GNUnet.
+ (C) 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file src/transport/gnunet-transport.c
+ * @brief Tool to help configure, measure and control the transport subsystem.
+ * @author Christian Grothoff
+ * @author Nathan Evans
+ *
+ * This utility can be used to test if a transport mechanism for
+ * GNUnet is properly configured.
+ */
+
+#include "platform.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_protocols.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_nat_lib.h"
+
+/**
+ * How long do we wait for the NAT test to report success?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1)
+
+/**
+ * Which peer should we connect to?
+ */
+static char *cpid;
+
+/**
+ * Handle to transport service.
+ */
+static struct GNUNET_TRANSPORT_Handle *handle;
+
+/**
+ * Option -s.
+ */
+static int benchmark_send;
+
+/**
+ * Option -b.
+ */
+static int benchmark_receive;
+
+/**
+ * Option -l.
+ */
+static int benchmark_receive;
+
+/**
+ * Option -i.
+ */
+static int iterate_connections;
+
+/**
+ * Option -t.
+ */
+static int test_configuration;
+
+/**
+ * Option -m.
+ */
+static int monitor_connections;
+
+/**
+ * Option -n.
+ */
+static int numeric;
+
+/**
+ * Global return value (0 success).
+ */
+static int ret;
+
+/**
+ * Number of bytes of traffic we received so far.
+ */
+static unsigned long long traffic_received;
+
+/**
+ * Number of bytes of traffic we sent so far.
+ */
+static unsigned long long traffic_sent;
+
+/**
+ * Starting time of transmitting/receiving data.
+ */
+static struct GNUNET_TIME_Absolute start_time;
+
+/**
+ * Handle for current transmission request.
+ */
+static struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+/**
+ * Identity of the peer we transmit to / connect to.
+ * (equivalent to 'cpid' string).
+ */
+static struct GNUNET_PeerIdentity pid;
+
+/**
+ * Task scheduled for cleanup / termination of the process.
+ */
+static GNUNET_SCHEDULER_TaskIdentifier end;
+
+/**
+ * Selected level of verbosity.
+ */
+static int verbosity;
+
+/**
+ * Resolver process handle.
+ */
+struct GNUNET_OS_Process *resolver;
+
+/**
+ * Number of tasks running that still need the resolver.
+ */
+static unsigned int resolver_users;
+
+
+/**
+ * Context for a plugin test.
+ */
+struct TestContext
+{
+
+ /**
+ * Handle to the active NAT test.
+ */
+ struct GNUNET_NAT_Test *tst;
+
+ /**
+ * Task identifier for the timeout.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier tsk;
+
+ /**
+ * Name of plugin under test.
+ */
+ const char *name;
+
+};
+
+
+/**
+ * Display the result of the test.
+ *
+ * @param tc test context
+ * @param result GNUNET_YES on success
+ */
+static void
+display_test_result (struct TestContext *tc, int result)
+{
+ if (GNUNET_YES != result)
+ {
+ FPRINTF (stderr, "Configuration for plugin `%s' did not work!\n", tc->name);
+ }
+ else
+ {
+ FPRINTF (stderr, "Configuration for plugin `%s' is working!\n", tc->name);
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != tc->tsk)
+ {
+ GNUNET_SCHEDULER_cancel (tc->tsk);
+ tc->tsk = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != tc->tst)
+ {
+ GNUNET_NAT_test_stop (tc->tst);
+ tc->tst = NULL;
+ }
+ GNUNET_free (tc);
+ resolver_users--;
+ if ((0 == resolver_users) && (NULL != resolver))
+ {
+ GNUNET_break (0 == GNUNET_OS_process_kill (resolver, SIGTERM));
+ GNUNET_OS_process_close (resolver);
+ resolver = NULL;
+ }
+}
+
+
+/**
+ * Function called by NAT on success.
+ * Clean up and update GUI (with success).
+ *
+ * @param cls test context
+ * @param success currently always GNUNET_OK
+ */
+static void
+result_callback (void *cls, int success)
+{
+ struct TestContext *tc = cls;
+
+ display_test_result (tc, success);
+}
+
+
+/**
+ * Function called if NAT failed to confirm success.
+ * Clean up and update GUI (with failure).
+ *
+ * @param cls test context
+ * @param tc scheduler callback
+ */
+static void
+fail_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct TestContext *tstc = cls;
+
+ tstc->tsk = GNUNET_SCHEDULER_NO_TASK;
+ display_test_result (tstc, GNUNET_NO);
+}
+
+
+/**
+ * Test our plugin's configuration (NAT traversal, etc.).
+ *
+ * @param cfg configuration to test
+ */
+static void
+do_test_configuration (const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ char *plugins;
+ char *tok;
+ unsigned long long bnd_port;
+ unsigned long long adv_port;
+ struct TestContext *tc;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_string (cfg, "transport", "plugins",
+ &plugins))
+ {
+ FPRINTF (stderr,
+ "%s",
+ _
+ ("No transport plugins configured, peer will never communicate\n"));
+ ret = 4;
+ return;
+ }
+ for (tok = strtok (plugins, " "); tok != NULL; tok = strtok (NULL, " "))
+ {
+ char section[12 + strlen (tok)];
+
+ GNUNET_snprintf (section, sizeof (section), "transport-%s", tok);
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg, section, "PORT", &bnd_port))
+ {
+ FPRINTF (stderr,
+ _("No port configured for plugin `%s', cannot test it\n"), tok);
+ continue;
+ }
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (cfg, section, "ADVERTISED_PORT",
+ &adv_port))
+ adv_port = bnd_port;
+ if (NULL == resolver)
+ resolver =
+ GNUNET_OS_start_process (GNUNET_YES, NULL, NULL, "gnunet-service-resolver",
+ "gnunet-service-resolver", NULL);
+ resolver_users++;
+ GNUNET_RESOLVER_connect (cfg);
+ tc = GNUNET_malloc (sizeof (struct TestContext));
+ tc->name = GNUNET_strdup (tok);
+ tc->tst =
+ GNUNET_NAT_test_start (cfg,
+ (0 ==
+ strcasecmp (tok,
+ "udp")) ? GNUNET_NO : GNUNET_YES,
+ (uint16_t) bnd_port, (uint16_t) adv_port,
+ &result_callback, tc);
+ if (NULL == tc->tst)
+ {
+ display_test_result (tc, GNUNET_SYSERR);
+ continue;
+ }
+ tc->tsk = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &fail_timeout, tc);
+ }
+ GNUNET_free (plugins);
+}
+
+
+/**
+ * Shutdown, print statistics.
+ */
+static void
+do_disconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TIME_Relative duration;
+
+ if (NULL != th)
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+ }
+ GNUNET_TRANSPORT_disconnect (handle);
+ if (benchmark_receive)
+ {
+ duration = GNUNET_TIME_absolute_get_duration (start_time);
+ FPRINTF (stdout, _("Received %llu bytes/s (%llu bytes in %llu ms)\n"),
+ 1000 * traffic_received / (1 + duration.rel_value),
+ traffic_received, (unsigned long long) duration.rel_value);
+ }
+ if (benchmark_send)
+ {
+ duration = GNUNET_TIME_absolute_get_duration (start_time);
+ FPRINTF (stdout, _("Transmitted %llu bytes/s (%llu bytes in %llu ms)\n"),
+ 1000 * traffic_sent / (1 + duration.rel_value), traffic_sent,
+ (unsigned long long) duration.rel_value);
+ }
+}
+
+
+/**
+ * Function called to notify a client about the socket
+ * begin ready to queue more data. "buf" will be
+ * NULL and "size" zero if the socket was closed for
+ * writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_data (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_MessageHeader *m = buf;
+
+ GNUNET_assert (size >= sizeof (struct GNUNET_MessageHeader));
+ GNUNET_assert (size < GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ m->size = ntohs (size);
+ m->type = ntohs (GNUNET_MESSAGE_TYPE_DUMMY);
+ memset (&m[1], 52, size - sizeof (struct GNUNET_MessageHeader));
+ traffic_sent += size;
+ th = GNUNET_TRANSPORT_notify_transmit_ready (handle, &pid, 32 * 1024, 0,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_data, NULL);
+ if (verbosity > 0)
+ FPRINTF (stdout, _("Transmitting %u bytes to %s\n"), (unsigned int) size,
+ GNUNET_i2s (&pid));
+ return size;
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer connected to us.
+ *
+ * @param cls closure
+ * @param peer the peer that connected
+ * @param ats performance data
+ * @param ats_count number of entries in ats (excluding 0-termination)
+ */
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ if (verbosity > 0)
+ FPRINTF (stdout, _("Connected to %s\n"), GNUNET_i2s (peer));
+ if (0 != memcmp (&pid, peer, sizeof (struct GNUNET_PeerIdentity)))
+ return;
+ ret = 0;
+ if (benchmark_send)
+ {
+ start_time = GNUNET_TIME_absolute_get ();
+ th = GNUNET_TRANSPORT_notify_transmit_ready (handle, peer, 32 * 1024, 0,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &transmit_data, NULL);
+ }
+ else
+ {
+ /* all done, terminate instantly */
+ GNUNET_SCHEDULER_cancel (end);
+ end = GNUNET_SCHEDULER_add_now (&do_disconnect, NULL);
+ }
+}
+
+
+/**
+ * Function called to notify transport users that another
+ * peer disconnected from us.
+ *
+ * @param cls closure
+ * @param peer the peer that disconnected
+ */
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ if (verbosity > 0)
+ FPRINTF (stdout, _("Disconnected from %s\n"), GNUNET_i2s (peer));
+ if ((0 == memcmp (&pid, peer, sizeof (struct GNUNET_PeerIdentity))) &&
+ (NULL != th))
+ {
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+ GNUNET_SCHEDULER_cancel (end);
+ end = GNUNET_SCHEDULER_add_now (&do_disconnect, NULL);
+ }
+}
+
+
+/**
+ * Function called by the transport for each received message.
+ *
+ * @param cls closure
+ * @param peer (claimed) identity of the other peer
+ * @param message the message
+ * @param ats performance data
+ * @param ats_count number of entries in ats
+ */
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ if (!benchmark_receive)
+ return;
+ if (verbosity > 0)
+ FPRINTF (stdout, _("Received %u bytes from %s\n"),
+ (unsigned int) ntohs (message->size), GNUNET_i2s (peer));
+ if (traffic_received == 0)
+ start_time = GNUNET_TIME_absolute_get ();
+ traffic_received += ntohs (message->size);
+}
+
+void
+process_string (void *cls, const char *address)
+{
+ struct GNUNET_HELLO_Address *addrcp = cls;
+
+ if ((address != NULL))
+ {
+ FPRINTF (stdout, _("Peer `%s': %s %s\n"), GNUNET_i2s (&addrcp->peer), addrcp->transport_name, address);
+ }
+ else
+ {
+ /* done */
+ GNUNET_free (addrcp);
+ }
+}
+
+/**
+ * Function to call with a binary address
+ *
+ * @param cls closure
+ * @param peer identity of the peer
+ * @param address binary address (NULL on disconnect)
+ */
+static void
+process_address (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_HELLO_Address *address)
+{
+ const struct GNUNET_CONFIGURATION_Handle *cfg = cls;
+
+ if (peer == NULL)
+ {
+ /* done */
+ return;
+ }
+
+ if (address == NULL)
+ {
+ FPRINTF (stdout, _("Peer `%s' disconnected\n"), GNUNET_i2s (peer));
+ return;
+ }
+
+ /* Resolve address to string */
+ GNUNET_TRANSPORT_address_to_string (cfg, address, numeric,
+ GNUNET_TIME_UNIT_MINUTES, &process_string,
+ GNUNET_HELLO_address_copy(address));
+}
+
+
+/**
+ * Task run in monitor mode when the user presses CTRL-C to abort.
+ * Stops monitoring activity.
+ *
+ * @param cls the 'struct GNUNET_TRANSPORT_PeerIterateContext *'
+ * @param tc scheduler context
+ */
+static void
+shutdown_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TRANSPORT_PeerIterateContext *pic = cls;
+
+ GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pic);
+}
+
+
+
+/**
+ * Main function that will be run by the scheduler.
+ *
+ * @param cls closure
+ * @param args remaining command-line arguments
+ * @param cfgfile name of the configuration file used (for saving, can be NULL!)
+ * @param cfg configuration
+ */
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ if (test_configuration)
+ {
+ do_test_configuration (cfg);
+ }
+ if (benchmark_send && (NULL == cpid))
+ {
+ FPRINTF (stderr, _("Option `%s' makes no sense without option `%s'.\n"),
+ "-s", "-C");
+ return;
+ }
+ if (NULL != cpid)
+ {
+ ret = 1;
+ if (GNUNET_OK != GNUNET_CRYPTO_hash_from_string (cpid, &pid.hashPubKey))
+ {
+ FPRINTF (stderr, _("Failed to parse peer identity `%s'\n"), cpid);
+ return;
+ }
+ handle =
+ GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive,
+ &notify_connect, &notify_disconnect);
+ GNUNET_TRANSPORT_try_connect (handle, &pid);
+ end =
+ GNUNET_SCHEDULER_add_delayed (benchmark_send ?
+ GNUNET_TIME_UNIT_FOREVER_REL :
+ GNUNET_TIME_UNIT_SECONDS, &do_disconnect,
+ NULL);
+ }
+ else if (benchmark_receive)
+ {
+ handle =
+ GNUNET_TRANSPORT_connect (cfg, NULL, NULL, &notify_receive,
+ &notify_connect, &notify_disconnect);
+ GNUNET_TRANSPORT_try_connect (handle, &pid);
+ end =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &do_disconnect, NULL);
+ }
+ if (iterate_connections)
+ {
+ GNUNET_TRANSPORT_peer_get_active_addresses (cfg, NULL, GNUNET_YES,
+ GNUNET_TIME_UNIT_MINUTES,
+ &process_address, (void *) cfg);
+ }
+ if (monitor_connections)
+ {
+ struct GNUNET_TRANSPORT_PeerIterateContext *pic;
+
+ pic = GNUNET_TRANSPORT_peer_get_active_addresses (cfg, NULL, GNUNET_NO,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &process_address, (void *) cfg);
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_FOREVER_REL,
+ &shutdown_task,
+ pic);
+ }
+}
+
+
+int
+main (int argc, char *const *argv)
+{
+ static const struct GNUNET_GETOPT_CommandLineOption options[] = {
+ {'b', "benchmark", NULL,
+ gettext_noop ("measure how fast we are receiving data (until CTRL-C)"),
+ 0, &GNUNET_GETOPT_set_one, &benchmark_receive},
+ {'C', "connect", "PEER",
+ gettext_noop ("try to connect to the given peer"),
+ 1, &GNUNET_GETOPT_set_string, &cpid},
+ {'i', "information", NULL,
+ gettext_noop ("provide information about all current connections (once)"),
+ 0, &GNUNET_GETOPT_set_one, &iterate_connections},
+ {'m', "monitor", NULL,
+ gettext_noop ("provide information about all current connections (continuously)"),
+ 0, &GNUNET_GETOPT_set_one, &monitor_connections},
+ {'n', "numeric", NULL,
+ gettext_noop ("do not resolve hostnames"),
+ 0, &GNUNET_GETOPT_set_one, &numeric},
+ {'s', "send", NULL,
+ gettext_noop
+ ("send data for benchmarking to the other peer (until CTRL-C)"),
+ 0, &GNUNET_GETOPT_set_one, &benchmark_send},
+ {'t', "test", NULL,
+ gettext_noop ("test transport configuration (involves external server)"),
+ 0, &GNUNET_GETOPT_set_one, &test_configuration},
+ GNUNET_GETOPT_OPTION_VERBOSE (&verbosity),
+ GNUNET_GETOPT_OPTION_END
+ };
+ return (GNUNET_OK ==
+ GNUNET_PROGRAM_run (argc, argv, "gnunet-transport",
+ gettext_noop
+ ("Direct access to transport service."), options,
+ &run, NULL)) ? ret : 1;
+}
+
+
+/* end of gnunet-transport.c */
diff --git a/src/transport/plugin_transport_http.c b/src/transport/plugin_transport_http.c
new file mode 100644
index 0000000..f88ff33
--- /dev/null
+++ b/src/transport/plugin_transport_http.c
@@ -0,0 +1,1529 @@
+/*
+ This file is part of GNUnet
+ (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_http.c
+ * @brief http transport service plugin
+ * @author Matthias Wachs
+ */
+
+#include "plugin_transport_http.h"
+
+/**
+ * After how long do we expire an address that we
+ * learned from another peer if it is not reconfirmed
+ * by anyone?
+ */
+#define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
+
+/**
+ * Wrapper to manage IPv4 addresses
+ */
+struct IPv4HttpAddressWrapper
+{
+ /**
+ * Linked list next
+ */
+ struct IPv4HttpAddressWrapper *next;
+
+ /**
+ * Linked list previous
+ */
+ struct IPv4HttpAddressWrapper *prev;
+
+ struct IPv4HttpAddress addr;
+};
+
+/**
+ * Wrapper for IPv4 addresses.
+ */
+struct IPv6HttpAddressWrapper
+{
+ /**
+ * Linked list next
+ */
+ struct IPv6HttpAddressWrapper *next;
+
+ /**
+ * Linked list previous
+ */
+ struct IPv6HttpAddressWrapper *prev;
+
+ struct IPv6HttpAddress addr6;
+};
+
+
+/**
+ * Context for address to string conversion.
+ */
+struct PrettyPrinterContext
+{
+ /**
+ * Function to call with the result.
+ */
+ GNUNET_TRANSPORT_AddressStringCallback asc;
+
+ /**
+ * Plugin
+ */
+ struct Plugin *plugin;
+
+ /**
+ * Clsoure for 'asc'.
+ */
+ void *asc_cls;
+
+ /**
+ * Port to add after the IP address.
+ */
+ uint16_t port;
+
+ uint32_t addrlen;
+
+ int numeric;
+};
+
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin;
+
+
+
+/**
+ * Append our port and forward the result.
+ *
+ * @param cls the 'struct PrettyPrinterContext*'
+ * @param hostname hostname part of the address
+ */
+static void
+append_port (void *cls, const char *hostname)
+{
+ struct PrettyPrinterContext *ppc = cls;
+ static char rbuf[INET6_ADDRSTRLEN + 13];
+
+ if (hostname == NULL)
+ {
+ ppc->asc (ppc->asc_cls, NULL);
+ GNUNET_free (ppc);
+ return;
+ }
+
+#if !BUILD_HTTPS
+ const char *protocol = "http";
+#else
+ const char *protocol = "https";
+#endif
+ GNUNET_assert ((strlen (hostname) + 7) < (INET6_ADDRSTRLEN + 13));
+ if (ppc->addrlen == sizeof (struct IPv6HttpAddress))
+ {
+ if (ppc->numeric == GNUNET_YES)
+ GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, hostname, ppc->port);
+ else
+ {
+ if (strchr(hostname, ':') != NULL)
+ GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol, hostname, ppc->port);
+ else
+ GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, hostname, ppc->port);
+ }
+ }
+ else if (ppc->addrlen == sizeof (struct IPv4HttpAddress))
+ GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, hostname, ppc->port);
+ ppc->asc (ppc->asc_cls, rbuf);
+}
+
+
+/**
+ * Convert the transports address to a nice, human-readable
+ * format.
+ *
+ * @param cls closure
+ * @param type name of the transport that generated the address
+ * @param addr one of the addresses of the host, NULL for the last address
+ * the specific address format depends on the transport
+ * @param addrlen length of the address
+ * @param numeric should (IP) addresses be displayed in numeric form?
+ * @param timeout after how long should we give up?
+ * @param asc function to call on each string
+ * @param asc_cls closure for asc
+ */
+static void
+http_plugin_address_pretty_printer (void *cls, const char *type,
+ const void *addr, size_t addrlen,
+ int numeric,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_AddressStringCallback asc,
+ void *asc_cls)
+{
+ GNUNET_assert (cls != NULL);
+ struct PrettyPrinterContext *ppc;
+ const void *sb;
+ struct sockaddr_in s4;
+ struct sockaddr_in6 s6;
+ size_t sbs;
+ uint16_t port = 0;
+
+ if ((addrlen == sizeof (struct IPv6HttpAddress)) && (addr != NULL))
+ {
+ struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr;
+ s6.sin6_family = AF_INET6;
+ s6.sin6_addr = a6->ipv6_addr;
+ s6.sin6_port = a6->u6_port;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ s6.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ sb = &s6;
+ sbs = sizeof (struct sockaddr_in6);
+ port = ntohs (a6->u6_port);
+
+ }
+ else if ((addrlen == sizeof (struct IPv4HttpAddress)) && (addr != NULL))
+ {
+ struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr;
+
+ s4.sin_family = AF_INET;
+ s4.sin_addr.s_addr = a4->ipv4_addr;
+ s4.sin_port = a4->u4_port;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ s4.sin_len = sizeof (struct sockaddr_in);
+#endif
+ sb = &s4;
+ sbs = sizeof (struct sockaddr_in);
+ port = ntohs (a4->u4_port);
+ }
+ else
+ {
+ /* invalid address */
+ GNUNET_break_op (0);
+ asc (asc_cls, NULL);
+ return;
+ }
+ ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
+ ppc->asc = asc;
+ ppc->asc_cls = asc_cls;
+ ppc->port = port;
+ ppc->plugin = cls;
+ ppc->addrlen = addrlen;
+ ppc->numeric = numeric;
+ GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc);
+}
+
+
+
+/**
+ * Another peer has suggested an address for this
+ * peer and transport plugin. Check that this could be a valid
+ * address. If so, consider adding it to the list
+ * of addresses.
+ *
+ * @param cls closure
+ * @param addr pointer to the address
+ * @param addrlen length of addr
+ * @return GNUNET_OK if this is a plausible address for this peer
+ * and transport
+ */
+static int
+http_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
+{
+
+ struct Plugin *plugin = cls;
+ struct IPv4HttpAddressWrapper *w_tv4 = plugin->ipv4_addr_head;
+ struct IPv6HttpAddressWrapper *w_tv6 = plugin->ipv6_addr_head;
+
+
+
+ GNUNET_assert (cls != NULL);
+ if ((addrlen != sizeof (struct sockaddr_in)) ||
+ (addrlen != sizeof (struct sockaddr_in6)))
+ return GNUNET_SYSERR;
+
+ if (addrlen == sizeof (struct IPv4HttpAddress))
+ {
+ struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) addr;
+
+ while (w_tv4 != NULL)
+ {
+ if ((0 ==
+ memcmp (&w_tv4->addr.ipv4_addr, &a4->ipv4_addr,
+ sizeof (struct in_addr))) &&
+ (w_tv4->addr.u4_port == a4->u4_port))
+ break;
+ w_tv4 = w_tv4->next;
+ }
+ if (w_tv4 != NULL)
+ return GNUNET_OK;
+ else
+ return GNUNET_SYSERR;
+ }
+ if (addrlen == sizeof (struct sockaddr_in6))
+ {
+ struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) addr;
+
+ while (w_tv6 != NULL)
+ {
+ if ((0 ==
+ memcmp (&w_tv6->addr6.ipv6_addr, &a6->ipv6_addr,
+ sizeof (struct in6_addr))) &&
+ (w_tv6->addr6.u6_port == a6->u6_port))
+ break;
+ w_tv6 = w_tv6->next;
+ }
+ if (w_tv6 != NULL)
+ return GNUNET_OK;
+ else
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+struct GNUNET_TIME_Relative
+http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ struct Session *session, const char *sender_address,
+ uint16_t sender_address_len)
+{
+ struct Session *s = cls;
+ struct Plugin *plugin = s->plugin;
+ struct GNUNET_TIME_Relative delay;
+ struct GNUNET_ATS_Information atsi[2];
+
+ atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
+ atsi[0].value = htonl (1);
+ atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE);
+ atsi[1].value = session->ats_address_network_type;
+ GNUNET_break (session->ats_address_network_type != ntohl (GNUNET_ATS_NET_UNSPECIFIED));
+
+ delay =
+ plugin->env->receive (plugin->env->cls, &s->target, message,
+ (const struct GNUNET_ATS_Information *) &atsi,
+ 2, s, s->addr, s->addrlen);
+ return delay;
+}
+
+/**
+ * Function called for a quick conversion of the binary address to
+ * a numeric address. Note that the caller must not free the
+ * address and that the next call to this function is allowed
+ * to override the address again.
+ *
+ * @param cls closure
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return string representing the same address
+ */
+const char *
+http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
+{
+
+ struct IPv4HttpAddress *a4;
+ struct IPv6HttpAddress *a6;
+ char *address;
+ static char rbuf[INET6_ADDRSTRLEN + 13];
+ uint16_t port;
+ int res = 0;
+
+ if (addrlen == sizeof (struct IPv6HttpAddress))
+ {
+ a6 = (struct IPv6HttpAddress *) addr;
+ address = GNUNET_malloc (INET6_ADDRSTRLEN);
+ GNUNET_assert (NULL !=
+ inet_ntop (AF_INET6, &a6->ipv6_addr, address,
+ INET6_ADDRSTRLEN));
+ port = ntohs (a6->u6_port);
+ }
+ else if (addrlen == sizeof (struct IPv4HttpAddress))
+ {
+ a4 = (struct IPv4HttpAddress *) addr;
+ address = GNUNET_malloc (INET_ADDRSTRLEN);
+ GNUNET_assert (NULL !=
+ inet_ntop (AF_INET, &(a4->ipv4_addr), address,
+ INET_ADDRSTRLEN));
+ port = ntohs (a4->u4_port);
+ }
+ else
+ {
+ /* invalid address */
+ GNUNET_break (0);
+ return NULL;
+ }
+#if !BUILD_HTTPS
+ char *protocol = "http";
+#else
+ char *protocol = "https";
+#endif
+
+ GNUNET_assert (strlen (address) + 7 < (INET6_ADDRSTRLEN + 13));
+ if (addrlen == sizeof (struct IPv6HttpAddress))
+ res =
+ GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://[%s]:%u/", protocol,
+ address, port);
+ else if (addrlen == sizeof (struct IPv4HttpAddress))
+ res =
+ GNUNET_snprintf (rbuf, sizeof (rbuf), "%s://%s:%u/", protocol, address,
+ port);
+
+ GNUNET_free (address);
+ GNUNET_assert (res != 0);
+ return rbuf;
+}
+
+struct Session *
+lookup_session_old (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
+ struct Session *session, const void *addr, size_t addrlen,
+ int force_address)
+{
+ struct Session *t;
+ int e_peer;
+ int e_addr;
+
+ for (t = plugin->head; NULL != t; t = t->next)
+ {
+#if 0
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ "Comparing peer `%s' address `%s' len %i session %X to \n",
+ GNUNET_i2s (target), GNUNET_a2s (addr, addrlen), addrlen,
+ session);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ "peer `%s' address `%s' len %i session %X \n\n",
+ GNUNET_i2s (&t->target), GNUNET_a2s (t->addr, t->addrlen),
+ t->addrlen, t);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "memcmp %i \n",
+ memcmp (addr, t->addr, addrlen));
+#endif
+ e_peer = GNUNET_NO;
+ e_addr = GNUNET_NO;
+ if (0 == memcmp (target, &t->target, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ e_peer = GNUNET_YES;
+ if ( (addrlen == t->addrlen) &&
+ (0 == memcmp (addr, t->addr, addrlen)) )
+ e_addr = GNUNET_YES;
+ if ( (t == session) &&
+ (t->addrlen == session->addrlen) &&
+ (0 == memcmp (session->addr, t->addr, t->addrlen)) )
+ e_addr = GNUNET_YES;
+ }
+
+ if ( ((e_peer == GNUNET_YES) && (force_address == GNUNET_NO)) ||
+ ((e_peer == GNUNET_YES) && (force_address == GNUNET_YES) && (e_addr == GNUNET_YES)) ||
+ ((e_peer == GNUNET_YES) && (force_address == GNUNET_SYSERR)) )
+ return t;
+ }
+ return NULL;
+}
+
+struct Session *
+lookup_session (struct Plugin *plugin,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct Session *pos;
+
+ for (pos = plugin->head; NULL != pos; pos = pos->next)
+ if ( (0 == memcmp (&address->peer, &pos->target, sizeof (struct GNUNET_PeerIdentity))) &&
+ (address->address_length == pos->addrlen) &&
+ (0 == memcmp (address->address, pos->addr, pos->addrlen)) )
+ return pos;
+ return NULL;
+}
+
+
+void
+delete_session (struct Session *s)
+{
+ if (s->msg_tk != NULL)
+ {
+ GNUNET_SERVER_mst_destroy (s->msg_tk);
+ s->msg_tk = NULL;
+ }
+ GNUNET_free (s->addr);
+ GNUNET_free_non_null (s->server_recv);
+ GNUNET_free_non_null (s->server_send);
+ GNUNET_free (s);
+}
+
+struct Session *
+create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
+ const void *addr, size_t addrlen,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct Session *s = NULL;
+
+ GNUNET_assert ((addrlen == sizeof (struct IPv6HttpAddress)) ||
+ (addrlen == sizeof (struct IPv4HttpAddress)));
+ s = GNUNET_malloc (sizeof (struct Session));
+ memcpy (&s->target, target, sizeof (struct GNUNET_PeerIdentity));
+ s->plugin = plugin;
+ s->addr = GNUNET_malloc (addrlen);
+ memcpy (s->addr, addr, addrlen);
+ s->addrlen = addrlen;
+ s->next = NULL;
+ s->next_receive = GNUNET_TIME_absolute_get_zero ();
+ s->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED);
+ return s;
+}
+
+void
+notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
+ struct Session *s)
+{
+ struct Plugin *plugin = cls;
+
+ plugin->env->session_end (plugin->env->cls, peer, s);
+ GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
+ delete_session (s);
+}
+
+/**
+ * Creates a new outbound session the transport service will use to send data to the
+ * peer
+ *
+ * @param cls the plugin
+ * @param address the address
+ * @return the session or NULL of max connections exceeded
+ */
+
+static struct Session *
+http_get_session (void *cls,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct Plugin *plugin = cls;
+ struct Session * s = NULL;
+ struct GNUNET_ATS_Information ats;
+ size_t addrlen;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (address != NULL);
+ GNUNET_assert (address->address != NULL);
+
+ ats.type = htonl (GNUNET_ATS_ARRAY_TERMINATOR);
+ ats.value = htonl (GNUNET_ATS_ARRAY_TERMINATOR);
+
+ /* find existing session */
+ s = lookup_session (plugin, address);
+ if (s != NULL)
+ return s;
+
+ if (plugin->max_connections <= plugin->cur_connections)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
+ "Maximum number of connections reached, "
+ "cannot connect to peer `%s'\n", GNUNET_i2s (&address->peer));
+ return NULL;
+ }
+
+ /* create new session */
+ addrlen = address->address_length;
+
+ GNUNET_assert ((addrlen == sizeof (struct IPv6HttpAddress)) ||
+ (addrlen == sizeof (struct IPv4HttpAddress)));
+
+ s = GNUNET_malloc (sizeof (struct Session));
+ memcpy (&s->target, &address->peer, sizeof (struct GNUNET_PeerIdentity));
+ s->plugin = plugin;
+ s->addr = GNUNET_malloc (address->address_length);
+ memcpy (s->addr, address->address, address->address_length);
+ s->addrlen = addrlen;
+ s->next = NULL;
+ s->next_receive = GNUNET_TIME_absolute_get_zero ();
+ s->inbound = GNUNET_NO;
+ s->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED);
+
+ /* Get ATS type */
+ if (addrlen == sizeof (struct IPv4HttpAddress))
+ {
+ struct IPv4HttpAddress *a4 = (struct IPv4HttpAddress *) address->address;
+ struct sockaddr_in s4;
+
+ s4.sin_family = AF_INET;
+ s4.sin_addr.s_addr = a4->ipv4_addr;
+ s4.sin_port = a4->u4_port;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ s4.sin_len = sizeof (struct sockaddr_in);
+#endif
+ ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s4, sizeof (struct sockaddr_in));
+ }
+ if (addrlen == sizeof (struct IPv6HttpAddress))
+ {
+ struct IPv6HttpAddress *a6 = (struct IPv6HttpAddress *) address->address;
+ struct sockaddr_in6 s6;
+
+ s6.sin6_family = AF_INET6;
+ s6.sin6_addr = a6->ipv6_addr;
+ s6.sin6_port = a6->u6_port;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ s6.sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) &s6, sizeof (struct sockaddr_in6));
+ }
+ s->ats_address_network_type = ats.value;
+
+ /* add new session */
+ GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
+ /* initiate new connection */
+ if (GNUNET_SYSERR == client_connect (s))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ "Cannot connect to peer `%s' address `%s''\n",
+ http_plugin_address_to_string(NULL, s->addr, s->addrlen),
+ GNUNET_i2s (&s->target));
+ GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
+ delete_session (s);
+ return NULL;
+ }
+
+ return s;
+}
+
+/**
+ * Function that can be used by the transport service to transmit
+ * a message using the plugin. Note that in the case of a
+ * peer disconnecting, the continuation MUST be called
+ * prior to the disconnect notification itself. This function
+ * will be called with this peer's HELLO message to initiate
+ * a fresh connection to another peer.
+ *
+ * @param cls closure
+ * @param session which session must be used
+ * @param msgbuf the message to transmit
+ * @param msgbuf_size number of bytes in 'msgbuf'
+ * @param priority how important is the message (most plugins will
+ * ignore message priority and just FIFO)
+ * @param to how long to wait at most for the transmission (does not
+ * require plugins to discard the message after the timeout,
+ * just advisory for the desired delay; most plugins will ignore
+ * this as well)
+ * @param cont continuation to call once the message has
+ * been transmitted (or if the transport is ready
+ * for the next transmission call; or if the
+ * peer disconnected...); can be NULL
+ * @param cont_cls closure for cont
+ * @return number of bytes used (on the physical network, with overheads);
+ * -1 on hard errors (i.e. address invalid); 0 is a legal value
+ * and does NOT mean that the message was not transmitted (DV)
+ */
+static ssize_t
+http_plugin_send (void *cls,
+ struct Session *session,
+ const char *msgbuf, size_t msgbuf_size,
+ unsigned int priority,
+ struct GNUNET_TIME_Relative to,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct Plugin *plugin = cls;
+ struct HTTP_Message *msg;
+ struct Session *tmp;
+ size_t res = -1;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (session != NULL);
+
+ /* lookup if session is really existing */
+ tmp = plugin->head;
+ while (tmp != NULL)
+ {
+ if ((tmp == session) &&
+ (0 == memcmp (&session->target, &tmp->target, sizeof (struct GNUNET_PeerIdentity))) &&
+ (session->addrlen == tmp->addrlen) &&
+ (0 == memcmp (session->addr, tmp->addr, tmp->addrlen)))
+ break;
+ tmp = tmp->next;
+ }
+ if (tmp == NULL)
+ {
+ GNUNET_break_op (0);
+ return res;
+ }
+
+ /* create new message and schedule */
+
+ msg = GNUNET_malloc (sizeof (struct HTTP_Message) + msgbuf_size);
+ msg->next = NULL;
+ msg->size = msgbuf_size;
+ msg->pos = 0;
+ msg->buf = (char *) &msg[1];
+ msg->transmit_cont = cont;
+ msg->transmit_cont_cls = cont_cls;
+ memcpy (msg->buf, msgbuf, msgbuf_size);
+
+ if (session->inbound == GNUNET_NO)
+ {
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Using outbound client session %p to send to `%session'\n", session,
+ GNUNET_i2s (&session->target));
+#endif
+
+ client_send (session, msg);
+ res = msgbuf_size;
+ }
+ if (session->inbound == GNUNET_YES)
+ {
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Using inbound server %p session to send to `%session'\n", session,
+ GNUNET_i2s (&session->target));
+#endif
+
+ server_send (session, msg);
+ res = msgbuf_size;
+ }
+ return res;
+
+}
+
+
+/**
+ * Function that can be used to force the plugin to disconnect
+ * from the given peer and cancel all previous transmissions
+ * (and their continuationc).
+ *
+ * @param cls closure
+ * @param target peer from which to disconnect
+ */
+static void
+http_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
+{
+ struct Plugin *plugin = cls;
+ struct Session *next = NULL;
+ struct Session *s = plugin->head;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Transport tells me to disconnect `%s'\n",
+ GNUNET_i2s (target));
+ while (s != NULL)
+ {
+ next = s->next;
+ if (0 == memcmp (target, &s->target, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ if (s->inbound == GNUNET_NO)
+ GNUNET_assert (GNUNET_OK == client_disconnect (s));
+ else
+ GNUNET_assert (GNUNET_OK == server_disconnect (s));
+ GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
+
+ struct HTTP_Message *msg = s->msg_head;
+ struct HTTP_Message *tmp = NULL;
+
+ while (msg != NULL)
+ {
+ tmp = msg->next;
+
+ GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
+ if (msg->transmit_cont != NULL)
+ {
+ msg->transmit_cont (msg->transmit_cont_cls, target, GNUNET_SYSERR);
+ }
+ GNUNET_free (msg);
+ msg = tmp;
+ }
+
+ delete_session (s);
+ }
+ s = next;
+ }
+}
+
+static void
+nat_add_address (void *cls, int add_remove, const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ struct Plugin *plugin = cls;
+ struct IPv4HttpAddressWrapper *w_t4 = NULL;
+ struct IPv6HttpAddressWrapper *w_t6 = NULL;
+ int af;
+
+ af = addr->sa_family;
+ switch (af)
+ {
+ case AF_INET:
+ w_t4 = plugin->ipv4_addr_head;
+ struct sockaddr_in *a4 = (struct sockaddr_in *) addr;
+
+ while (w_t4 != NULL)
+ {
+ int res = memcmp (&w_t4->addr.ipv4_addr,
+ &a4->sin_addr,
+ sizeof (struct in_addr));
+
+ if (res == 0)
+ {
+ if (a4->sin_port != w_t4->addr.u4_port)
+ res = -1;
+ }
+
+ if (0 == res)
+ break;
+ w_t4 = w_t4->next;
+ }
+ if (w_t4 == NULL)
+ {
+ w_t4 = GNUNET_malloc (sizeof (struct IPv4HttpAddressWrapper));
+ memcpy (&w_t4->addr.ipv4_addr, &a4->sin_addr, sizeof (struct in_addr));
+ w_t4->addr.u4_port = a4->sin_port;
+
+ GNUNET_CONTAINER_DLL_insert (plugin->ipv4_addr_head,
+ plugin->ipv4_addr_tail, w_t4);
+ }
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Notifying transport to add IPv4 address `%s'\n",
+ http_plugin_address_to_string (NULL, &w_t4->addr,
+ sizeof (struct
+ IPv4HttpAddress)));
+#endif
+ plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr,
+ sizeof (struct IPv4HttpAddress));
+
+ break;
+ case AF_INET6:
+ w_t6 = plugin->ipv6_addr_head;
+ struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr;
+
+ while (w_t6)
+ {
+ int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr,
+ sizeof (struct in6_addr));
+
+ if (res == 0)
+ {
+ if (a6->sin6_port != w_t6->addr6.u6_port)
+ res = -1;
+ }
+ if (0 == res)
+ break;
+ w_t6 = w_t6->next;
+ }
+ if (w_t6 == NULL)
+ {
+ w_t6 = GNUNET_malloc (sizeof (struct IPv6HttpAddressWrapper));
+
+ memcpy (&w_t6->addr6.ipv6_addr, &a6->sin6_addr, sizeof (struct in6_addr));
+ w_t6->addr6.u6_port = a6->sin6_port;
+
+ GNUNET_CONTAINER_DLL_insert (plugin->ipv6_addr_head,
+ plugin->ipv6_addr_tail, w_t6);
+ }
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Notifying transport to add IPv6 address `%s'\n",
+ http_plugin_address_to_string (NULL, &w_t6->addr6,
+ sizeof (struct
+ IPv6HttpAddress)));
+#endif
+ plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6,
+ sizeof (struct IPv6HttpAddress));
+ break;
+ default:
+ return;
+ }
+
+}
+
+static void
+nat_remove_address (void *cls, int add_remove, const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ struct Plugin *plugin = cls;
+ struct IPv4HttpAddressWrapper *w_t4 = NULL;
+ struct IPv6HttpAddressWrapper *w_t6 = NULL;
+ int af;
+
+ af = addr->sa_family;
+ switch (af)
+ {
+ case AF_INET:
+ w_t4 = plugin->ipv4_addr_head;
+ struct sockaddr_in *a4 = (struct sockaddr_in *) addr;
+
+ while (w_t4 != NULL)
+ {
+ int res = memcmp (&w_t4->addr.ipv4_addr,
+ &a4->sin_addr,
+ sizeof (struct in_addr));
+
+ if (res == 0)
+ {
+ if (a4->sin_port != w_t4->addr.u4_port)
+ res = -1;
+ }
+
+ if (0 == res)
+ break;
+ w_t4 = w_t4->next;
+ }
+ if (w_t4 == NULL)
+ return;
+
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Notifying transport to remove IPv4 address `%s'\n",
+ http_plugin_address_to_string (NULL, &w_t4->addr,
+ sizeof (struct
+ IPv4HttpAddress)));
+#endif
+ plugin->env->notify_address (plugin->env->cls, add_remove, &w_t4->addr,
+ sizeof (struct IPv4HttpAddress));
+
+ GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail,
+ w_t4);
+ GNUNET_free (w_t4);
+ break;
+ case AF_INET6:
+ w_t6 = plugin->ipv6_addr_head;
+ struct sockaddr_in6 *a6 = (struct sockaddr_in6 *) addr;
+
+ while (w_t6)
+ {
+ int res = memcmp (&w_t6->addr6.ipv6_addr, &a6->sin6_addr,
+ sizeof (struct in6_addr));
+
+ if (res == 0)
+ {
+ if (a6->sin6_port != w_t6->addr6.u6_port)
+ res = -1;
+ }
+ if (0 == res)
+ break;
+ w_t6 = w_t6->next;
+ }
+ if (w_t6 == NULL)
+ return;
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Notifying transport to remove IPv6 address `%s'\n",
+ http_plugin_address_to_string (NULL, &w_t6->addr6,
+ sizeof (struct
+ IPv6HttpAddress)));
+#endif
+ plugin->env->notify_address (plugin->env->cls, add_remove, &w_t6->addr6,
+ sizeof (struct IPv6HttpAddress));
+
+ GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail,
+ w_t6);
+ GNUNET_free (w_t6);
+ break;
+ default:
+ return;
+ }
+
+}
+
+/**
+ * Our external IP address/port mapping has changed.
+ *
+ * @param cls closure, the 'struct LocalAddrList'
+ * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
+ * the previous (now invalid) one
+ * @param addr either the previous or the new public IP address
+ * @param addrlen actual lenght of the address
+ */
+static void
+nat_port_map_callback (void *cls, int add_remove, const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ GNUNET_assert (cls != NULL);
+#if DEBUG_HTTP
+ struct Plugin *plugin = cls;
+#endif
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "NPMC called %s to address `%s'\n",
+ (add_remove == GNUNET_NO) ? "remove" : "add",
+ GNUNET_a2s (addr, addrlen));
+#endif
+ switch (add_remove)
+ {
+ case GNUNET_YES:
+ nat_add_address (cls, add_remove, addr, addrlen);
+ break;
+ case GNUNET_NO:
+ nat_remove_address (cls, add_remove, addr, addrlen);
+ break;
+ }
+}
+
+void
+http_check_ipv6 (struct Plugin *plugin)
+{
+ struct GNUNET_NETWORK_Handle *desc = NULL;
+
+ if (plugin->ipv6 == GNUNET_YES)
+ {
+ /* probe IPv6 support */
+ desc = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_STREAM, 0);
+ if (NULL == desc)
+ {
+ if ((errno == ENOBUFS) || (errno == ENOMEM) || (errno == ENFILE) ||
+ (errno == EACCES))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
+ }
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
+ _
+ ("Disabling IPv6 since it is not supported on this system!\n"));
+ plugin->ipv6 = GNUNET_NO;
+ }
+ else
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (desc));
+ desc = NULL;
+ }
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Testing IPv6 on this system: %s\n",
+ (plugin->ipv6 == GNUNET_YES) ? "successful" : "failed");
+ }
+}
+
+int
+http_get_addresses (struct Plugin *plugin, const char *serviceName,
+ const struct GNUNET_CONFIGURATION_Handle *cfg,
+ struct sockaddr ***addrs, socklen_t ** addr_lens)
+{
+ int disablev6;
+ unsigned long long port;
+ struct addrinfo hints;
+ struct addrinfo *res;
+ struct addrinfo *pos;
+ struct addrinfo *next;
+ unsigned int i;
+ int resi;
+ int ret;
+ struct sockaddr **saddrs;
+ socklen_t *saddrlens;
+ char *hostname;
+
+ *addrs = NULL;
+ *addr_lens = NULL;
+
+ disablev6 = !plugin->ipv6;
+
+ port = 0;
+ if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "PORT"))
+ {
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_number (cfg, serviceName,
+ "PORT", &port));
+ if (port > 65535)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _
+ ("Require valid port number for service in configuration!\n"));
+ return GNUNET_SYSERR;
+ }
+ }
+
+ if (GNUNET_CONFIGURATION_have_value (cfg, serviceName, "BINDTO"))
+ {
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (cfg, serviceName,
+ "BINDTO", &hostname));
+ }
+ else
+ hostname = NULL;
+
+ if (hostname != NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Resolving `%s' since that is where `%s' will bind to.\n",
+ hostname, serviceName);
+ memset (&hints, 0, sizeof (struct addrinfo));
+ if (disablev6)
+ hints.ai_family = AF_INET;
+ if ((0 != (ret = getaddrinfo (hostname, NULL, &hints, &res))) ||
+ (res == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Failed to resolve `%s': %s\n"),
+ hostname, gai_strerror (ret));
+ GNUNET_free (hostname);
+ return GNUNET_SYSERR;
+ }
+ next = res;
+ i = 0;
+ while (NULL != (pos = next))
+ {
+ next = pos->ai_next;
+ if ((disablev6) && (pos->ai_family == AF_INET6))
+ continue;
+ i++;
+ }
+ if (0 == i)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ _("Failed to find %saddress for `%s'.\n"),
+ disablev6 ? "IPv4 " : "", hostname);
+ freeaddrinfo (res);
+ GNUNET_free (hostname);
+ return GNUNET_SYSERR;
+ }
+ resi = i;
+ saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ i = 0;
+ next = res;
+ while (NULL != (pos = next))
+ {
+ next = pos->ai_next;
+ if ((disablev6) && (pos->ai_family == AF_INET6))
+ continue;
+ if ((pos->ai_protocol != IPPROTO_TCP) && (pos->ai_protocol != 0))
+ continue; /* not TCP */
+ if ((pos->ai_socktype != SOCK_STREAM) && (pos->ai_socktype != 0))
+ continue; /* huh? */
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Service will bind to `%s'\n", GNUNET_a2s (pos->ai_addr,
+ pos->ai_addrlen));
+ if (pos->ai_family == AF_INET)
+ {
+ GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in));
+ saddrlens[i] = pos->ai_addrlen;
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+ memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+ ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+ }
+ else
+ {
+ GNUNET_assert (pos->ai_family == AF_INET6);
+ GNUNET_assert (pos->ai_addrlen == sizeof (struct sockaddr_in6));
+ saddrlens[i] = pos->ai_addrlen;
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+ memcpy (saddrs[i], pos->ai_addr, saddrlens[i]);
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+ }
+ i++;
+ }
+ GNUNET_free (hostname);
+ freeaddrinfo (res);
+ resi = i;
+ }
+ else
+ {
+ /* will bind against everything, just set port */
+ if (disablev6)
+ {
+ /* V4-only */
+ resi = 1;
+ i = 0;
+ saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+
+ saddrlens[i] = sizeof (struct sockaddr_in);
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[i];
+#endif
+ ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+ ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+ }
+ else
+ {
+ /* dual stack */
+ resi = 2;
+ saddrs = GNUNET_malloc ((resi + 1) * sizeof (struct sockaddr *));
+ saddrlens = GNUNET_malloc ((resi + 1) * sizeof (socklen_t));
+ i = 0;
+ saddrlens[i] = sizeof (struct sockaddr_in6);
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_len = saddrlens[0];
+#endif
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_family = AF_INET6;
+ ((struct sockaddr_in6 *) saddrs[i])->sin6_port = htons (port);
+ i++;
+ saddrlens[i] = sizeof (struct sockaddr_in);
+ saddrs[i] = GNUNET_malloc (saddrlens[i]);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ ((struct sockaddr_in *) saddrs[i])->sin_len = saddrlens[1];
+#endif
+ ((struct sockaddr_in *) saddrs[i])->sin_family = AF_INET;
+ ((struct sockaddr_in *) saddrs[i])->sin_port = htons (port);
+ }
+ }
+ *addrs = saddrs;
+ *addr_lens = saddrlens;
+ return resi;
+}
+
+static void
+start_report_addresses (struct Plugin *plugin)
+{
+ int res = GNUNET_OK;
+ struct sockaddr **addrs;
+ socklen_t *addrlens;
+
+ res =
+ http_get_addresses (plugin, plugin->name, plugin->env->cfg, &addrs,
+ &addrlens);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ _("Found %u addresses to report to NAT service\n"), res);
+
+ if (res != GNUNET_SYSERR)
+ {
+ plugin->nat =
+ GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, plugin->port,
+ (unsigned int) res,
+ (const struct sockaddr **) addrs, addrlens,
+ &nat_port_map_callback, NULL, plugin);
+ while (res > 0)
+ {
+ res--;
+#if 0
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, _("FREEING %s\n"),
+ GNUNET_a2s (addrs[res], addrlens[res]));
+#endif
+ GNUNET_assert (addrs[res] != NULL);
+ GNUNET_free (addrs[res]);
+ }
+ GNUNET_free_non_null (addrs);
+ GNUNET_free_non_null (addrlens);
+ }
+ else
+ {
+ plugin->nat =
+ GNUNET_NAT_register (plugin->env->cfg, GNUNET_YES, 0, 0, NULL, NULL,
+ NULL, NULL, plugin);
+ }
+}
+
+static void
+stop_report_addresses (struct Plugin *plugin)
+{
+ /* Stop NAT handle */
+ GNUNET_NAT_unregister (plugin->nat);
+
+ /* Clean up addresses */
+ struct IPv4HttpAddressWrapper *w_t4;
+ struct IPv6HttpAddressWrapper *w_t6;
+
+ while (plugin->ipv4_addr_head != NULL)
+ {
+ w_t4 = plugin->ipv4_addr_head;
+ GNUNET_CONTAINER_DLL_remove (plugin->ipv4_addr_head, plugin->ipv4_addr_tail,
+ w_t4);
+ GNUNET_free (w_t4);
+ }
+
+ while (plugin->ipv6_addr_head != NULL)
+ {
+ w_t6 = plugin->ipv6_addr_head;
+ GNUNET_CONTAINER_DLL_remove (plugin->ipv6_addr_head, plugin->ipv6_addr_tail,
+ w_t6);
+ GNUNET_free (w_t6);
+ }
+}
+
+static int
+configure_plugin (struct Plugin *plugin)
+{
+ int res = GNUNET_OK;
+
+ /* Use IPv4? */
+ if (GNUNET_CONFIGURATION_have_value
+ (plugin->env->cfg, plugin->name, "USE_IPv4"))
+ {
+ plugin->ipv4 =
+ GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
+ "USE_IPv4");
+ }
+ else
+ plugin->ipv4 = GNUNET_YES;
+
+ /* Use IPv6? */
+ if (GNUNET_CONFIGURATION_have_value
+ (plugin->env->cfg, plugin->name, "USE_IPv6"))
+ {
+ plugin->ipv6 =
+ GNUNET_CONFIGURATION_get_value_yesno (plugin->env->cfg, plugin->name,
+ "USE_IPv6");
+ }
+ else
+ plugin->ipv6 = GNUNET_YES;
+
+ if ((plugin->ipv4 == GNUNET_NO) && (plugin->ipv6 == GNUNET_NO))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ _
+ ("Neither IPv4 nor IPv6 are enabled! Fix in configuration\n"),
+ plugin->name);
+ res = GNUNET_SYSERR;
+ }
+
+ /* Reading port number from config file */
+ unsigned long long port;
+
+ if ((GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
+ "PORT", &port)) || (port > 65535))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ _("Port is required! Fix in configuration\n"),
+ plugin->name);
+ res = GNUNET_SYSERR;
+ goto fail;
+ }
+ plugin->port = port;
+
+ plugin->client_only = GNUNET_NO;
+ if (plugin->port == 0)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ _("Port 0, client only mode\n"));
+ plugin->client_only = GNUNET_YES;
+ }
+
+ char *bind4_address = NULL;
+
+ if ((plugin->ipv4 == GNUNET_YES) &&
+ (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
+ "BINDTO", &bind4_address)))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Binding %s plugin to specific IPv4 address: `%s'\n",
+ plugin->protocol, bind4_address);
+ plugin->server_addr_v4 = GNUNET_malloc (sizeof (struct sockaddr_in));
+ if (1 !=
+ inet_pton (AF_INET, bind4_address, &plugin->server_addr_v4->sin_addr))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ _
+ ("Specific IPv4 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"),
+ bind4_address, plugin->protocol);
+ GNUNET_free (plugin->server_addr_v4);
+ plugin->server_addr_v4 = NULL;
+ }
+ else
+ {
+ plugin->server_addr_v4->sin_family = AF_INET;
+ plugin->server_addr_v4->sin_port = htons (plugin->port);
+ }
+ GNUNET_free (bind4_address);
+ }
+
+
+ char *bind6_address = NULL;
+
+ if ((plugin->ipv6 == GNUNET_YES) &&
+ (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg, plugin->name,
+ "BINDTO6", &bind6_address)))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Binding %s plugin to specific IPv6 address: `%s'\n",
+ plugin->protocol, bind6_address);
+ plugin->server_addr_v6 = GNUNET_malloc (sizeof (struct sockaddr_in6));
+ if (1 !=
+ inet_pton (AF_INET6, bind6_address, &plugin->server_addr_v6->sin6_addr))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ _
+ ("Specific IPv6 address `%s' for plugin %s in configuration file is invalid! Binding to all addresses!\n"),
+ bind6_address, plugin->protocol);
+ GNUNET_free (plugin->server_addr_v6);
+ plugin->server_addr_v6 = NULL;
+ }
+ else
+ {
+ plugin->server_addr_v6->sin6_family = AF_INET6;
+ plugin->server_addr_v6->sin6_port = htons (plugin->port);
+ }
+ GNUNET_free (bind6_address);
+ }
+
+
+ /* Optional parameters */
+ unsigned long long maxneigh;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (plugin->env->cfg, plugin->name,
+ "MAX_CONNECTIONS", &maxneigh))
+ maxneigh = 128;
+ plugin->max_connections = maxneigh;
+
+fail:
+ return res;
+}
+
+/**
+ * Entry point for the plugin.
+ */
+void *
+LIBGNUNET_PLUGIN_TRANSPORT_INIT (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
+ struct GNUNET_TRANSPORT_PluginFunctions *api;
+ struct Plugin *plugin;
+ int res;
+
+ plugin = GNUNET_malloc (sizeof (struct Plugin));
+ plugin->env = env;
+ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
+ api->cls = plugin;
+ api->disconnect = &http_plugin_disconnect;
+ api->address_pretty_printer = &http_plugin_address_pretty_printer;
+ api->check_address = &http_plugin_address_suggested;
+ api->address_to_string = &http_plugin_address_to_string;
+ api->get_session = &http_get_session;
+ api->send = &http_plugin_send;
+
+#if BUILD_HTTPS
+ plugin->name = "transport-https";
+ plugin->protocol = "https";
+#else
+ plugin->name = "transport-http";
+ plugin->protocol = "http";
+#endif
+ /* Configure plugin from configuration */
+ res = configure_plugin (plugin);
+ if (res == GNUNET_SYSERR)
+ {
+ GNUNET_free_non_null (plugin->server_addr_v4);
+ GNUNET_free_non_null (plugin->server_addr_v6);
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+ return NULL;
+ }
+
+ /* checking IPv6 support */
+ http_check_ipv6 (plugin);
+
+ /* Start client */
+ res = client_start (plugin);
+ if (res == GNUNET_SYSERR)
+ {
+ GNUNET_free_non_null (plugin->server_addr_v4);
+ GNUNET_free_non_null (plugin->server_addr_v6);
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+ return NULL;
+ }
+
+ /* Start server */
+ if (plugin->client_only == GNUNET_NO)
+ {
+ res = server_start (plugin);
+ if (res == GNUNET_SYSERR)
+ {
+ server_stop (plugin);
+ client_stop (plugin);
+
+ GNUNET_free_non_null (plugin->server_addr_v4);
+ GNUNET_free_non_null (plugin->server_addr_v6);
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+ return NULL;
+ }
+ }
+ /* Report addresses to transport service */
+ start_report_addresses (plugin);
+
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Plugin `%s' loaded\n", plugin->name);
+#endif
+
+ return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ */
+void *
+LIBGNUNET_PLUGIN_TRANSPORT_DONE (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
+ struct Plugin *plugin = api->cls;
+ struct Session *s = NULL;
+
+ /* Stop reporting addresses to transport service */
+ stop_report_addresses (plugin);
+
+ /* cleaning up sessions */
+ s = plugin->head;
+ while (s != NULL)
+ {
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Disconnecting `%s' \n", GNUNET_i2s (&s->target));
+#endif
+ if (s->inbound == GNUNET_NO)
+ GNUNET_assert (GNUNET_OK == client_disconnect (s));
+ else
+ GNUNET_assert (GNUNET_OK == server_disconnect (s));
+ s = s->next;
+ }
+
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping server\n");
+#endif
+ /* Stop server */
+ server_stop (plugin);
+
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name, "Stopping client\n");
+#endif
+ /* Stop client */
+ client_stop (plugin);
+
+ /* deleting up sessions */
+ s = plugin->head;
+ while (s != NULL)
+ {
+ struct Session *t = s->next;
+
+ GNUNET_CONTAINER_DLL_remove (plugin->head, plugin->tail, s);
+
+ struct HTTP_Message *msg = s->msg_head;
+ struct HTTP_Message *tmp = NULL;
+
+ while (msg != NULL)
+ {
+ tmp = msg->next;
+
+ GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
+ if (msg->transmit_cont != NULL)
+ {
+ msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR);
+ }
+ GNUNET_free (msg);
+ msg = tmp;
+ }
+
+ delete_session (s);
+ s = t;
+ }
+
+
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Plugin `%s' unloaded\n", plugin->name);
+#endif
+
+ GNUNET_free_non_null (plugin->server_addr_v4);
+ GNUNET_free_non_null (plugin->server_addr_v6);
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+
+ return NULL;
+}
+
+/* end of plugin_transport_http.c */
diff --git a/src/transport/plugin_transport_http.h b/src/transport/plugin_transport_http.h
new file mode 100644
index 0000000..be8f93d
--- /dev/null
+++ b/src/transport/plugin_transport_http.h
@@ -0,0 +1,504 @@
+/*
+ This file is part of GNUnet
+ (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_http.h
+ * @brief http transport service plugin
+ * @author Matthias Wachs
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_constants.h"
+#include "gnunet_protocols.h"
+#include "gnunet_connection_lib.h"
+#include "gnunet_service_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_transport_plugin.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_nat_lib.h"
+#include "microhttpd.h"
+#include <curl/curl.h>
+
+
+#define DEBUG_HTTP GNUNET_EXTRA_LOGGING
+#define VERBOSE_SERVER GNUNET_EXTRA_LOGGING
+#define VERBOSE_CLIENT GNUNET_EXTRA_LOGGING
+#define VERBOSE_CURL GNUNET_EXTRA_LOGGING
+
+#if BUILD_HTTPS
+#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_https_init
+#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_https_done
+#else
+#define LIBGNUNET_PLUGIN_TRANSPORT_INIT libgnunet_plugin_transport_http_init
+#define LIBGNUNET_PLUGIN_TRANSPORT_DONE libgnunet_plugin_transport_http_done
+#endif
+
+#define INBOUND GNUNET_YES
+#define OUTBOUND GNUNET_NO
+
+
+#define HTTP_NOT_VALIDATED_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 15)
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin
+{
+ /**
+ * General handles
+ * ---------------
+ */
+
+ /**
+ * Our environment.
+ */
+ struct GNUNET_TRANSPORT_PluginEnvironment *env;
+
+ /**
+ * Linked list of open sessions.
+ */
+
+ struct Session *head;
+
+ struct Session *tail;
+
+ /**
+ * NAT handle & address management
+ */
+ struct GNUNET_NAT_Handle *nat;
+
+ /**
+ * List of own addresses
+ */
+
+ /**
+ * IPv4 addresses DLL head
+ */
+ struct IPv4HttpAddressWrapper *ipv4_addr_head;
+
+ /**
+ * IPv4 addresses DLL tail
+ */
+ struct IPv4HttpAddressWrapper *ipv4_addr_tail;
+
+ /**
+ * IPv6 addresses DLL head
+ */
+ struct IPv6HttpAddressWrapper *ipv6_addr_head;
+
+ /**
+ * IPv6 addresses DLL tail
+ */
+ struct IPv6HttpAddressWrapper *ipv6_addr_tail;
+
+ /**
+ * Plugin configuration
+ * --------------------
+ */
+
+ /**
+ * Plugin name
+ * Equals configuration section: transport-http, transport-https
+ */
+ char *name;
+
+ /**
+ * Plugin protocol
+ * http, https
+ */
+ char *protocol;
+
+ /**
+ * Use IPv4?
+ * GNUNET_YES or GNUNET_NO
+ */
+ int ipv4;
+
+ /**
+ * Use IPv6?
+ * GNUNET_YES or GNUNET_NO
+ */
+ int ipv6;
+
+ /**
+ * Does plugin just use outbound connections and not accept inbound?
+ */
+
+ int client_only;
+
+ /**
+ * Port used
+ */
+ uint16_t port;
+
+ /**
+ * Maximum number of sockets the plugin can use
+ * Each http inbound /outbound connections are two connections
+ */
+ int max_connections;
+
+ /**
+ * Plugin HTTPS SSL/TLS options
+ * ----------------------------
+ */
+
+ /**
+ * libCurl TLS crypto init string, can be set to enhance performance
+ *
+ * Example:
+ *
+ * Use RC4-128 instead of AES:
+ * NONE:+VERS-TLS1.0:+ARCFOUR-128:+SHA1:+RSA:+COMP-NULL
+ *
+ */
+ char *crypto_init;
+
+ /**
+ * TLS key
+ */
+ char *key;
+
+ /**
+ * TLS certificate
+ */
+ char *cert;
+
+ /**
+ * Plugin values
+ * -------------
+ */
+
+ /**
+ * Current number of establishes connections
+ */
+ int cur_connections;
+
+ /**
+ * Last used unique HTTP connection tag
+ */
+ uint32_t last_tag;
+
+ /**
+ * Server handles
+ * --------------
+ */
+
+ /**
+ * MHD IPv4 daemon
+ */
+ struct MHD_Daemon *server_v4;
+
+ /**
+ * MHD IPv4 task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier server_v4_task;
+
+ /**
+ * MHD IPv6 daemon
+ */
+ struct MHD_Daemon *server_v6;
+
+ /**
+ * MHD IPv4 task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier server_v6_task;
+
+ /**
+ * IPv4 server socket to bind to
+ */
+ struct sockaddr_in *server_addr_v4;
+
+ /**
+ * IPv6 server socket to bind to
+ */
+ struct sockaddr_in6 *server_addr_v6;
+
+ /**
+ * Server semi connections
+ * A full session consists of 2 semi-connections: send and receive
+ * If not both directions are established the server keeps this sessions here
+ */
+ struct Session *server_semi_head;
+
+ struct Session *server_semi_tail;
+
+ /*
+ * Client handles
+ */
+
+ /**
+ * cURL Multihandle
+ */
+ CURLM *client_mh;
+
+ /**
+ * curl perform task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier client_perform_task;
+
+};
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * IPv4 addresses
+ */
+struct IPv4HttpAddress
+{
+ /**
+ * IPv4 address, in network byte order.
+ */
+ uint32_t ipv4_addr GNUNET_PACKED;
+
+ /**
+ * Port number, in network byte order.
+ */
+ uint16_t u4_port GNUNET_PACKED;
+};
+
+/**
+ * IPv4 addresses
+ */
+struct IPv6HttpAddress
+{
+ /**
+ * IPv6 address.
+ */
+ struct in6_addr ipv6_addr GNUNET_PACKED;
+
+ /**
+ * Port number, in network byte order.
+ */
+ uint16_t u6_port GNUNET_PACKED;
+};
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * Session handle for connections.
+ */
+struct Session
+{
+
+ /**
+ * Stored in a linked list.
+ */
+ struct Session *next;
+
+ /**
+ * Stored in a linked list.
+ */
+ struct Session *prev;
+
+ /**
+ * Pointer to the global plugin struct.
+ */
+ struct Plugin *plugin;
+
+ /**
+ * Address
+ */
+ void *addr;
+
+ /**
+ * Address length
+ */
+ size_t addrlen;
+
+ /**
+ * ATS network type in NBO
+ */
+ uint32_t ats_address_network_type;
+
+ /**
+ * To whom are we talking to
+ */
+ struct GNUNET_PeerIdentity target;
+
+ /**
+ * next pointer for double linked list
+ */
+ struct HTTP_Message *msg_head;
+
+ /**
+ * previous pointer for double linked list
+ */
+ struct HTTP_Message *msg_tail;
+
+
+ /**
+ * Message stream tokenizer for incoming data
+ */
+ struct GNUNET_SERVER_MessageStreamTokenizer *msg_tk;
+
+ /**
+ * Absolute time when to receive data again
+ * Used for receive throttling
+ */
+ struct GNUNET_TIME_Absolute next_receive;
+
+ /**
+ * Inbound or outbound connection
+ * Outbound: GNUNET_NO (client is used to send and receive)
+ * Inbound : GNUNET_YES (server is used to send and receive)
+ */
+ int inbound;
+
+ /**
+ * Unique HTTP/S connection tag for this connection
+ */
+ uint32_t tag;
+
+ /**
+ * Client handles
+ */
+
+ /**
+ * Client send handle
+ */
+ void *client_put;
+
+ /**
+ * Client receive handle
+ */
+ void *client_get;
+
+ /**
+ * Task to wake up client receive handle when receiving is allowed again
+ */
+ GNUNET_SCHEDULER_TaskIdentifier recv_wakeup_task;
+
+ /**
+ * Is client send handle paused since there are no data to send?
+ * GNUNET_YES/NO
+ */
+ int client_put_paused;
+
+ /**
+ * Server handles
+ */
+
+ /**
+ * Client send handle
+ */
+ void *server_recv;
+
+ /**
+ * Client send handle
+ */
+ void *server_send;
+};
+
+/**
+ * Message to send using http
+ */
+struct HTTP_Message
+{
+ /**
+ * next pointer for double linked list
+ */
+ struct HTTP_Message *next;
+
+ /**
+ * previous pointer for double linked list
+ */
+ struct HTTP_Message *prev;
+
+ /**
+ * buffer containing data to send
+ */
+ char *buf;
+
+ /**
+ * amount of data already sent
+ */
+ size_t pos;
+
+ /**
+ * buffer length
+ */
+ size_t size;
+
+ /**
+ * Continuation function to call once the transmission buffer
+ * has again space available. NULL if there is no
+ * continuation to call.
+ */
+ GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
+
+ /**
+ * Closure for transmit_cont.
+ */
+ void *transmit_cont_cls;
+};
+
+void
+delete_session (struct Session *s);
+
+struct Session *
+create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
+ const void *addr, size_t addrlen,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls);
+
+struct GNUNET_TIME_Relative
+http_plugin_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ struct Session *session, const char *sender_address,
+ uint16_t sender_address_len);
+
+const char *
+http_plugin_address_to_string (void *cls, const void *addr, size_t addrlen);
+
+int
+client_disconnect (struct Session *s);
+
+int
+client_connect (struct Session *s);
+
+int
+client_send (struct Session *s, struct HTTP_Message *msg);
+
+int
+client_start (struct Plugin *plugin);
+
+void
+client_stop (struct Plugin *plugin);
+
+int
+server_disconnect (struct Session *s);
+
+int
+server_send (struct Session *s, struct HTTP_Message *msg);
+
+int
+server_start (struct Plugin *plugin);
+
+void
+server_stop (struct Plugin *plugin);
+
+void
+notify_session_end (void *cls, const struct GNUNET_PeerIdentity *peer,
+ struct Session *s);
+
+/* end of plugin_transport_http.h */
diff --git a/src/transport/plugin_transport_http_client.c b/src/transport/plugin_transport_http_client.c
new file mode 100644
index 0000000..4679e45
--- /dev/null
+++ b/src/transport/plugin_transport_http_client.c
@@ -0,0 +1,643 @@
+/*
+ This file is part of GNUnet
+ (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_http_client.c
+ * @brief http transport service plugin
+ * @author Matthias Wachs
+ */
+
+#include "plugin_transport_http.h"
+
+#if VERBOSE_CURL
+/**
+ * Function to log curl debug messages with GNUNET_log
+ * @param curl handle
+ * @param type curl_infotype
+ * @param data data
+ * @param size size
+ * @param cls closure
+ * @return 0
+ */
+static int
+client_log (CURL * curl, curl_infotype type, char *data, size_t size, void *cls)
+{
+ if (type == CURLINFO_TEXT)
+ {
+ char text[size + 2];
+
+ memcpy (text, data, size);
+ if (text[size - 1] == '\n')
+ text[size] = '\0';
+ else
+ {
+ text[size] = '\n';
+ text[size + 1] = '\0';
+ }
+#if BUILD_HTTPS
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-https",
+ "Client: %X - %s", cls, text);
+#else
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-http",
+ "Client: %X - %s", cls, text);
+#endif
+ }
+ return 0;
+}
+#endif
+
+/**
+ * Task performing curl operations
+ * @param cls plugin as closure
+ * @param tc gnunet scheduler task context
+ */
+static void
+client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+ * Function setting up file descriptors and scheduling task to run
+ *
+ * @param plugin plugin as closure
+ * @param now schedule task in 1ms, regardless of what curl may say
+ * @return GNUNET_SYSERR for hard failure, GNUNET_OK for ok
+ */
+static int
+client_schedule (struct Plugin *plugin, int now)
+{
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ int max;
+ struct GNUNET_NETWORK_FDSet *grs;
+ struct GNUNET_NETWORK_FDSet *gws;
+ long to;
+ CURLMcode mret;
+ struct GNUNET_TIME_Relative timeout;
+
+ /* Cancel previous scheduled task */
+ if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
+ plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ max = -1;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ mret = curl_multi_fdset (plugin->client_mh, &rs, &ws, &es, &max);
+ if (mret != CURLM_OK)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"),
+ "curl_multi_fdset", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ return GNUNET_SYSERR;
+ }
+ mret = curl_multi_timeout (plugin->client_mh, &to);
+ if (to == -1)
+ timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 1);
+ else
+ timeout = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MILLISECONDS, to);
+ if (now == GNUNET_YES)
+ timeout = GNUNET_TIME_UNIT_MILLISECONDS;
+
+ if (mret != CURLM_OK)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("%s failed at %s:%d: `%s'\n"),
+ "curl_multi_timeout", __FILE__, __LINE__,
+ curl_multi_strerror (mret));
+ return GNUNET_SYSERR;
+ }
+
+ grs = GNUNET_NETWORK_fdset_create ();
+ gws = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_copy_native (grs, &rs, max + 1);
+ GNUNET_NETWORK_fdset_copy_native (gws, &ws, max + 1);
+
+ plugin->client_perform_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK, timeout, grs, gws,
+ &client_run, plugin);
+ GNUNET_NETWORK_fdset_destroy (gws);
+ GNUNET_NETWORK_fdset_destroy (grs);
+ return GNUNET_OK;
+}
+
+
+int
+client_send (struct Session *s, struct HTTP_Message *msg)
+{
+ GNUNET_assert (s != NULL);
+ GNUNET_CONTAINER_DLL_insert (s->msg_head, s->msg_tail, msg);
+
+ if (s->client_put_paused == GNUNET_YES)
+ {
+#if VERBOSE_CLIENT
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name,
+ "Client: %X was suspended, unpausing\n", s->client_put);
+#endif
+ s->client_put_paused = GNUNET_NO;
+ curl_easy_pause (s->client_put, CURLPAUSE_CONT);
+ }
+
+ client_schedule (s->plugin, GNUNET_YES);
+
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Task performing curl operations
+ * @param cls plugin as closure
+ * @param tc gnunet scheduler task context
+ */
+static void
+client_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+ int running;
+ CURLMcode mret;
+
+ GNUNET_assert (cls != NULL);
+
+ plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ do
+ {
+ running = 0;
+ mret = curl_multi_perform (plugin->client_mh, &running);
+
+ CURLMsg *msg;
+ int msgs_left;
+
+ while ((msg = curl_multi_info_read (plugin->client_mh, &msgs_left)))
+ {
+ CURL *easy_h = msg->easy_handle;
+ struct Session *s = NULL;
+ char *d = (char *) s;
+
+
+ //GNUNET_assert (easy_h != NULL);
+ if (easy_h == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Client: connection to ended with reason %i: `%s', %i handles running\n",
+ msg->data.result,
+ curl_easy_strerror (msg->data.result), running);
+ continue;
+ }
+
+ GNUNET_assert (CURLE_OK ==
+ curl_easy_getinfo (easy_h, CURLINFO_PRIVATE, &d));
+ s = (struct Session *) d;
+ GNUNET_assert (s != NULL);
+
+ if (msg->msg == CURLMSG_DONE)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Client: %X connection to '%s' %s ended with reason %i: `%s'\n",
+ msg->easy_handle, GNUNET_i2s (&s->target),
+ http_plugin_address_to_string (NULL, s->addr,
+ s->addrlen),
+ msg->data.result,
+ curl_easy_strerror (msg->data.result));
+
+ client_disconnect (s);
+ //GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,"Notifying about ended session to peer `%s' `%s'\n", GNUNET_i2s (&s->target), http_plugin_address_to_string (plugin, s->addr, s->addrlen));
+ notify_session_end (plugin, &s->target, s);
+ }
+ }
+ }
+ while (mret == CURLM_CALL_MULTI_PERFORM);
+ client_schedule (plugin, GNUNET_NO);
+}
+
+int
+client_disconnect (struct Session *s)
+{
+ int res = GNUNET_OK;
+ CURLMcode mret;
+ struct Plugin *plugin = s->plugin;
+ struct HTTP_Message *msg;
+ struct HTTP_Message *t;
+
+
+
+ if (s->client_put != NULL)
+ {
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Client: %X Deleting outbound PUT session to peer `%s'\n",
+ s->client_put, GNUNET_i2s (&s->target));
+#endif
+
+ mret = curl_multi_remove_handle (plugin->client_mh, s->client_put);
+ if (mret != CURLM_OK)
+ {
+ curl_easy_cleanup (s->client_put);
+ res = GNUNET_SYSERR;
+ GNUNET_break (0);
+ }
+ curl_easy_cleanup (s->client_put);
+ s->client_put = NULL;
+ }
+
+
+ if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
+ s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (s->client_get != NULL)
+ {
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Client: %X Deleting outbound GET session to peer `%s'\n",
+ s->client_get, GNUNET_i2s (&s->target));
+#endif
+
+ mret = curl_multi_remove_handle (plugin->client_mh, s->client_get);
+ if (mret != CURLM_OK)
+ {
+ curl_easy_cleanup (s->client_get);
+ res = GNUNET_SYSERR;
+ GNUNET_break (0);
+ }
+ curl_easy_cleanup (s->client_get);
+ s->client_get = NULL;
+ }
+
+ msg = s->msg_head;
+ while (msg != NULL)
+ {
+ t = msg->next;
+ if (NULL != msg->transmit_cont)
+ msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR);
+ GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
+ GNUNET_free (msg);
+ msg = t;
+ }
+
+ plugin->cur_connections -= 2;
+ /* Re-schedule since handles have changed */
+ if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
+ plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ client_schedule (plugin, GNUNET_YES);
+
+ return res;
+}
+
+static void
+client_receive_mst_cb (void *cls, void *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct Session *s = cls;
+ struct GNUNET_TIME_Relative delay;
+
+ delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen);
+ s->next_receive =
+ GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay);
+
+ if (GNUNET_TIME_absolute_get ().abs_value < s->next_receive.abs_value)
+ {
+#if VERBOSE_CLIENT
+ struct Plugin *plugin = s->plugin;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Client: peer `%s' address `%s' next read delayed for %llu ms\n",
+ GNUNET_i2s (&s->target), GNUNET_a2s (s->addr, s->addrlen),
+ delay);
+#endif
+ }
+}
+
+static void
+client_wake_up (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Session *s = cls;
+
+ s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, s->plugin->name,
+ "Client: %X Waking up receive handle\n", s->client_get);
+
+ if (s->client_get != NULL)
+ curl_easy_pause (s->client_get, CURLPAUSE_CONT);
+
+}
+
+/**
+* Callback method used with libcurl
+* Method is called when libcurl needs to write data during sending
+* @param stream pointer where to write data
+* @param size size of an individual element
+* @param nmemb count of elements that can be written to the buffer
+* @param cls destination pointer, passed to the libcurl handle
+* @return bytes read from stream
+*/
+static size_t
+client_receive (void *stream, size_t size, size_t nmemb, void *cls)
+{
+ struct Session *s = cls;
+ struct GNUNET_TIME_Absolute now;
+ size_t len = size * nmemb;
+
+
+#if VERBOSE_CLIENT
+ struct Plugin *plugin = s->plugin;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Client: Received %Zu bytes from peer `%s'\n", len,
+ GNUNET_i2s (&s->target));
+#endif
+
+ now = GNUNET_TIME_absolute_get ();
+ if (now.abs_value < s->next_receive.abs_value)
+ {
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+ struct GNUNET_TIME_Relative delta =
+ GNUNET_TIME_absolute_get_difference (now, s->next_receive);
+#if DEBUG_CLIENT
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Client: %X No inbound bandwidth available! Next read was delayed for %llu ms\n",
+ s->client_get, delta.rel_value);
+#endif
+ if (s->recv_wakeup_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (s->recv_wakeup_task);
+ s->recv_wakeup_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ s->recv_wakeup_task =
+ GNUNET_SCHEDULER_add_delayed (delta, &client_wake_up, s);
+ return CURLPAUSE_ALL;
+ }
+
+
+ if (s->msg_tk == NULL)
+ s->msg_tk = GNUNET_SERVER_mst_create (&client_receive_mst_cb, s);
+
+ GNUNET_SERVER_mst_receive (s->msg_tk, s, stream, len, GNUNET_NO, GNUNET_NO);
+
+ return len;
+}
+
+/**
+ * Callback method used with libcurl
+ * Method is called when libcurl needs to read data during sending
+ * @param stream pointer where to write data
+ * @param size size of an individual element
+ * @param nmemb count of elements that can be written to the buffer
+ * @param cls source pointer, passed to the libcurl handle
+ * @return bytes written to stream, returning 0 will terminate connection!
+ */
+static size_t
+client_send_cb (void *stream, size_t size, size_t nmemb, void *cls)
+{
+ struct Session *s = cls;
+
+#if VERBOSE_CLIENT
+ struct Plugin *plugin = s->plugin;
+#endif
+ size_t bytes_sent = 0;
+ size_t len;
+
+ struct HTTP_Message *msg = s->msg_head;
+
+ if (msg == NULL)
+ {
+#if VERBOSE_CLIENT
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Client: %X Nothing to send! Suspending PUT handle!\n",
+ s->client_put);
+#endif
+ s->client_put_paused = GNUNET_YES;
+ return CURL_READFUNC_PAUSE;
+ }
+
+ GNUNET_assert (msg != NULL);
+ /* data to send */
+ if (msg->pos < msg->size)
+ {
+ /* data fit in buffer */
+ if ((msg->size - msg->pos) <= (size * nmemb))
+ {
+ len = (msg->size - msg->pos);
+ memcpy (stream, &msg->buf[msg->pos], len);
+ msg->pos += len;
+ bytes_sent = len;
+ }
+ else
+ {
+ len = size * nmemb;
+ memcpy (stream, &msg->buf[msg->pos], len);
+ msg->pos += len;
+ bytes_sent = len;
+ }
+ }
+ /* no data to send */
+ else
+ {
+ GNUNET_assert (0);
+ bytes_sent = 0;
+ }
+
+ if (msg->pos == msg->size)
+ {
+#if VERBOSE_CLIENT
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Client: %X Message with %u bytes sent, removing message from queue\n",
+ s->client_put, msg->size, msg->pos);
+#endif
+ /* Calling transmit continuation */
+ if (NULL != msg->transmit_cont)
+ msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK);
+ GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
+ GNUNET_free (msg);
+ }
+ return bytes_sent;
+}
+
+int
+client_connect (struct Session *s)
+{
+ struct Plugin *plugin = s->plugin;
+ int res = GNUNET_OK;
+ char *url;
+ CURLMcode mret;
+
+#if VERBOSE_CLIENT
+#endif
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Initiating outbound session peer `%s'\n",
+ GNUNET_i2s (&s->target));
+
+
+ s->inbound = GNUNET_NO;
+
+ plugin->last_tag++;
+ /* create url */
+ GNUNET_asprintf (&url, "%s%s;%u",
+ http_plugin_address_to_string (plugin, s->addr, s->addrlen),
+ GNUNET_h2s_full (&plugin->env->my_identity->hashPubKey),
+ plugin->last_tag);
+#if 0
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name, "URL `%s'\n", url);
+#endif
+ /* create get connection */
+ s->client_get = curl_easy_init ();
+#if VERBOSE_CURL
+ curl_easy_setopt (s->client_get, CURLOPT_VERBOSE, 1L);
+ curl_easy_setopt (s->client_get, CURLOPT_DEBUGFUNCTION, &client_log);
+ curl_easy_setopt (s->client_get, CURLOPT_DEBUGDATA, s->client_get);
+#endif
+#if BUILD_HTTPS
+ curl_easy_setopt (s->client_get, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
+ curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt (s->client_get, CURLOPT_SSL_VERIFYHOST, 0);
+#endif
+ curl_easy_setopt (s->client_get, CURLOPT_URL, url);
+ //curl_easy_setopt (s->client_get, CURLOPT_HEADERFUNCTION, &curl_get_header_cb);
+ //curl_easy_setopt (s->client_get, CURLOPT_WRITEHEADER, ps);
+ curl_easy_setopt (s->client_get, CURLOPT_READFUNCTION, client_send_cb);
+ curl_easy_setopt (s->client_get, CURLOPT_READDATA, s);
+ curl_easy_setopt (s->client_get, CURLOPT_WRITEFUNCTION, client_receive);
+ curl_easy_setopt (s->client_get, CURLOPT_WRITEDATA, s);
+ curl_easy_setopt (s->client_get, CURLOPT_TIMEOUT_MS,
+ (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
+ curl_easy_setopt (s->client_get, CURLOPT_PRIVATE, s);
+ curl_easy_setopt (s->client_get, CURLOPT_CONNECTTIMEOUT_MS,
+ (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value);
+ curl_easy_setopt (s->client_get, CURLOPT_BUFFERSIZE,
+ 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
+#if CURL_TCP_NODELAY
+ curl_easy_setopt (ps->recv_endpoint, CURLOPT_TCP_NODELAY, 1);
+#endif
+
+ /* create put connection */
+ s->client_put = curl_easy_init ();
+#if VERBOSE_CURL
+ curl_easy_setopt (s->client_put, CURLOPT_VERBOSE, 1L);
+ curl_easy_setopt (s->client_put, CURLOPT_DEBUGFUNCTION, &client_log);
+ curl_easy_setopt (s->client_put, CURLOPT_DEBUGDATA, s->client_put);
+#endif
+#if BUILD_HTTPS
+ curl_easy_setopt (s->client_put, CURLOPT_SSLVERSION, CURL_SSLVERSION_TLSv1);
+ curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYPEER, 0);
+ curl_easy_setopt (s->client_put, CURLOPT_SSL_VERIFYHOST, 0);
+#endif
+ curl_easy_setopt (s->client_put, CURLOPT_URL, url);
+ curl_easy_setopt (s->client_put, CURLOPT_PUT, 1L);
+ //curl_easy_setopt (s->client_put, CURLOPT_HEADERFUNCTION, &curl_put_header_cb);
+ //curl_easy_setopt (s->client_put, CURLOPT_WRITEHEADER, ps);
+ curl_easy_setopt (s->client_put, CURLOPT_READFUNCTION, client_send_cb);
+ curl_easy_setopt (s->client_put, CURLOPT_READDATA, s);
+ curl_easy_setopt (s->client_put, CURLOPT_WRITEFUNCTION, client_receive);
+ curl_easy_setopt (s->client_put, CURLOPT_WRITEDATA, s);
+ curl_easy_setopt (s->client_put, CURLOPT_TIMEOUT_MS,
+ (long) GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value);
+ curl_easy_setopt (s->client_put, CURLOPT_PRIVATE, s);
+ curl_easy_setopt (s->client_put, CURLOPT_CONNECTTIMEOUT_MS,
+ (long) HTTP_NOT_VALIDATED_TIMEOUT.rel_value);
+ curl_easy_setopt (s->client_put, CURLOPT_BUFFERSIZE,
+ 2 * GNUNET_SERVER_MAX_MESSAGE_SIZE);
+#if CURL_TCP_NODELAY
+ curl_easy_setopt (s->client_put, CURLOPT_TCP_NODELAY, 1);
+#endif
+
+ GNUNET_free (url);
+
+ mret = curl_multi_add_handle (plugin->client_mh, s->client_get);
+ if (mret != CURLM_OK)
+ {
+ curl_easy_cleanup (s->client_get);
+ res = GNUNET_SYSERR;
+ GNUNET_break (0);
+ }
+
+ mret = curl_multi_add_handle (plugin->client_mh, s->client_put);
+ if (mret != CURLM_OK)
+ {
+ curl_multi_remove_handle (plugin->client_mh, s->client_get);
+ curl_easy_cleanup (s->client_get);
+ curl_easy_cleanup (s->client_put);
+ res = GNUNET_SYSERR;
+ GNUNET_break (0);
+ }
+
+ /* Perform connect */
+ plugin->cur_connections += 2;
+
+ /* Re-schedule since handles have changed */
+ if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
+ plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ plugin->client_perform_task = GNUNET_SCHEDULER_add_now (client_run, plugin);
+
+ return res;
+}
+
+int
+client_start (struct Plugin *plugin)
+{
+ int res = GNUNET_OK;
+
+ curl_global_init (CURL_GLOBAL_ALL);
+ plugin->client_mh = curl_multi_init ();
+
+ if (NULL == plugin->client_mh)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ _
+ ("Could not initialize curl multi handle, failed to start %s plugin!\n"),
+ plugin->name);
+ res = GNUNET_SYSERR;
+ }
+ return res;
+}
+
+void
+client_stop (struct Plugin *plugin)
+{
+ if (plugin->client_perform_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->client_perform_task);
+ plugin->client_perform_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ curl_multi_cleanup (plugin->client_mh);
+ curl_global_cleanup ();
+}
+
+
+
+/* end of plugin_transport_http_client.c */
diff --git a/src/transport/plugin_transport_http_server.c b/src/transport/plugin_transport_http_server.c
new file mode 100644
index 0000000..8ec5a5e
--- /dev/null
+++ b/src/transport/plugin_transport_http_server.c
@@ -0,0 +1,1223 @@
+/*
+ This file is part of GNUnet
+ (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_http.c
+ * @brief http transport service plugin
+ * @author Matthias Wachs
+ */
+
+#include "plugin_transport_http.h"
+
+#define HTTP_ERROR_RESPONSE "<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML 2.0//EN\"><HTML><HEAD><TITLE>404 Not Found</TITLE></HEAD><BODY><H1>Not Found</H1>The requested URL was not found on this server.<P><HR><ADDRESS></ADDRESS></BODY></HTML>"
+#define _RECEIVE 0
+#define _SEND 1
+
+struct ServerConnection
+{
+ /* _RECV or _SEND */
+ int direction;
+
+ /* should this connection get disconnected? GNUNET_YES/NO */
+ int disconnect;
+
+ struct Session *session;
+ struct MHD_Connection *mhd_conn;
+};
+
+/**
+ * Function that queries MHD's select sets and
+ * starts the task waiting for them.
+ * @param plugin plugin
+ * @param daemon_handle the MHD daemon handle
+ * @param now schedule now or with MHD delay
+ * @return gnunet task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier
+server_schedule (struct Plugin *plugin,
+ struct MHD_Daemon *daemon_handle,
+ int now);
+
+static void
+server_log (void *arg, const char *fmt, va_list ap)
+{
+ char text[1024];
+
+ vsnprintf (text, sizeof (text), fmt, ap);
+ va_end (ap);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Server: %s\n", text);
+}
+
+/**
+ * Check if incoming connection is accepted.
+ * NOTE: Here every connection is accepted
+ * @param cls plugin as closure
+ * @param addr address of incoming connection
+ * @param addr_len address length of incoming connection
+ * @return MHD_YES if connection is accepted, MHD_NO if connection is rejected
+ *
+ */
+static int
+server_accept_cb (void *cls, const struct sockaddr *addr, socklen_t addr_len)
+{
+ struct Plugin *plugin = cls;
+
+ if (plugin->cur_connections <= plugin->max_connections)
+ return MHD_YES;
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Server: Cannot accept new connections\n");
+ return MHD_NO;
+ }
+}
+
+
+#if BUILD_HTTPS
+static char *
+server_load_file (const char *file)
+{
+ struct GNUNET_DISK_FileHandle *gn_file;
+ struct stat fstat;
+ char *text = NULL;
+
+ if (0 != STAT (file, &fstat))
+ return NULL;
+ text = GNUNET_malloc (fstat.st_size + 1);
+ gn_file =
+ GNUNET_DISK_file_open (file, GNUNET_DISK_OPEN_READ,
+ GNUNET_DISK_PERM_USER_READ);
+ if (gn_file == NULL)
+ {
+ GNUNET_free (text);
+ return NULL;
+ }
+ if (GNUNET_SYSERR == GNUNET_DISK_file_read (gn_file, text, fstat.st_size))
+ {
+ GNUNET_free (text);
+ GNUNET_DISK_file_close (gn_file);
+ return NULL;
+ }
+ text[fstat.st_size] = '\0';
+ GNUNET_DISK_file_close (gn_file);
+ return text;
+}
+#endif
+
+
+#if BUILD_HTTPS
+
+static int
+server_load_certificate (struct Plugin *plugin)
+{
+ int res = GNUNET_OK;
+
+ char *key_file;
+ char *cert_file;
+
+ /* Get crypto init string from config
+ * If not present just use default values */
+
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (plugin->env->cfg,
+ plugin->name,
+ "CRYPTO_INIT",
+ &plugin->crypto_init));
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name,
+ "KEY_FILE", &key_file))
+ {
+ key_file = GNUNET_strdup ("https_key.key");
+ }
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_filename (plugin->env->cfg, plugin->name,
+ "CERT_FILE", &cert_file))
+ {
+ GNUNET_asprintf (&cert_file, "%s", "https_cert.crt");
+ }
+
+ /* read key & certificates from file */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Loading TLS certificate from key-file `%s' cert-file`%s'\n",
+ key_file, cert_file);
+
+ plugin->key = server_load_file (key_file);
+ plugin->cert = server_load_file (cert_file);
+
+ if ((plugin->key == NULL) || (plugin->cert == NULL))
+ {
+ struct GNUNET_OS_Process *cert_creation;
+
+ GNUNET_free_non_null (plugin->key);
+ plugin->key = NULL;
+ GNUNET_free_non_null (plugin->cert);
+ plugin->cert = NULL;
+
+#if VERBOSE_SERVER
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "No usable TLS certificate found, creating certificate\n");
+#endif
+ errno = 0;
+ cert_creation =
+ GNUNET_OS_start_process (GNUNET_NO, NULL, NULL,
+ "gnunet-transport-certificate-creation",
+ "gnunet-transport-certificate-creation",
+ key_file, cert_file, NULL);
+ if (cert_creation == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ _
+ ("Could not create a new TLS certificate, program `gnunet-transport-certificate-creation' could not be started!\n"));
+ GNUNET_free (key_file);
+ GNUNET_free (cert_file);
+
+ GNUNET_free_non_null (plugin->key);
+ plugin->key = NULL;
+ GNUNET_free_non_null (plugin->cert);
+ plugin->cert = NULL;
+ GNUNET_free_non_null (plugin->crypto_init);
+ plugin->crypto_init = NULL;
+
+ return GNUNET_SYSERR;
+ }
+ GNUNET_assert (GNUNET_OK == GNUNET_OS_process_wait (cert_creation));
+ GNUNET_OS_process_close (cert_creation);
+
+ plugin->key = server_load_file (key_file);
+ plugin->cert = server_load_file (cert_file);
+ }
+
+ if ((plugin->key == NULL) || (plugin->cert == NULL))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ _
+ ("No usable TLS certificate found and creating one failed!\n"),
+ "transport-https");
+ GNUNET_free (key_file);
+ GNUNET_free (cert_file);
+
+ GNUNET_free_non_null (plugin->key);
+ plugin->key = NULL;
+ GNUNET_free_non_null (plugin->cert);
+ plugin->cert = NULL;
+ GNUNET_free_non_null (plugin->crypto_init);
+ plugin->crypto_init = NULL;
+
+ return GNUNET_SYSERR;
+ }
+ GNUNET_free (key_file);
+ GNUNET_free (cert_file);
+#if DEBUG_HTTP
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "TLS certificate loaded\n");
+#endif
+
+ return res;
+}
+#endif
+
+
+/**
+ * Reschedule the execution of both IPv4 and IPv6 server
+ * @param plugin the plugin
+ * @param server which server to schedule v4 or v6?
+ * @param now GNUNET_YES to schedule execution immediately, GNUNET_NO to wait
+ * until timeout
+ */
+
+static void
+server_reschedule (struct Plugin *plugin, struct MHD_Daemon *server, int now)
+{
+ if ((server == plugin->server_v4) && (plugin->server_v4 != NULL))
+ {
+ if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
+ plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ plugin->server_v4_task = server_schedule (plugin, plugin->server_v4, now);
+ }
+
+ if ((server == plugin->server_v6) && (plugin->server_v6 != NULL))
+ {
+ if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
+ plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ plugin->server_v6_task = server_schedule (plugin, plugin->server_v6, now);
+ }
+}
+
+/**
+ * Callback called by MessageStreamTokenizer when a message has arrived
+ * @param cls current session as closure
+ * @param client clien
+ * @param message the message to be forwarded to transport service
+ */
+static void
+server_receive_mst_cb (void *cls, void *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct Session *s = cls;
+ struct Plugin *plugin = s->plugin;
+ struct GNUNET_TIME_Relative delay;
+
+ delay = http_plugin_receive (s, &s->target, message, s, s->addr, s->addrlen);
+
+ s->next_receive =
+ GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (), delay);
+
+ if (delay.rel_value > 0)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: peer `%s' address `%s' next read delayed for %llu ms\n",
+ GNUNET_i2s (&s->target),
+ http_plugin_address_to_string (NULL, s->addr, s->addrlen),
+ delay);
+ }
+}
+
+/**
+ * Callback called by MHD when it needs data to send
+ * @param cls current session
+ * @param pos position in buffer
+ * @param buf the buffer to write data to
+ * @param max max number of bytes available in buffer
+ * @return bytes written to buffer
+ */
+static ssize_t
+server_send_callback (void *cls, uint64_t pos, char *buf, size_t max)
+{
+ struct Session *s = cls;
+
+ struct HTTP_Message *msg;
+ int bytes_read = 0;
+
+ //static int c = 0;
+ msg = s->msg_head;
+ if (msg != NULL)
+ {
+ /* sending */
+ if ((msg->size - msg->pos) <= max)
+ {
+ memcpy (buf, &msg->buf[msg->pos], (msg->size - msg->pos));
+ bytes_read = msg->size - msg->pos;
+ msg->pos += (msg->size - msg->pos);
+ }
+ else
+ {
+ memcpy (buf, &msg->buf[msg->pos], max);
+ msg->pos += max;
+ bytes_read = max;
+ }
+
+ /* removing message */
+ if (msg->pos == msg->size)
+ {
+ if (NULL != msg->transmit_cont)
+ msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_OK);
+ GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
+ GNUNET_free (msg);
+ }
+ }
+
+ struct Plugin *plugin = s->plugin;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: %X: sent %u bytes\n", s, bytes_read);
+
+ return bytes_read;
+}
+
+static struct ServerConnection *
+server_lookup_session (struct Plugin *plugin,
+ struct MHD_Connection *mhd_connection, const char *url,
+ const char *method)
+{
+ struct Session *s = NULL;
+ struct Session *t;
+ struct ServerConnection *sc = NULL;
+ const union MHD_ConnectionInfo *conn_info;
+ struct GNUNET_ATS_Information ats;
+ struct IPv4HttpAddress a4;
+ struct IPv6HttpAddress a6;
+ struct sockaddr_in *s4;
+ struct sockaddr_in6 *s6;
+ void *a;
+ size_t a_len;
+ struct GNUNET_PeerIdentity target;
+ int check = GNUNET_NO;
+ uint32_t tag = 0;
+ int direction = GNUNET_SYSERR;
+
+ conn_info =
+ MHD_get_connection_info (mhd_connection,
+ MHD_CONNECTION_INFO_CLIENT_ADDRESS);
+ if ((conn_info->client_addr->sa_family != AF_INET) &&
+ (conn_info->client_addr->sa_family != AF_INET6))
+ return MHD_NO;
+
+ if ((strlen (&url[1]) >= 105) && (url[104] == ';'))
+ {
+ char hash[104];
+ char *tagc = (char *) &url[105];
+
+ memcpy (&hash, &url[1], 103);
+ hash[103] = '\0';
+ if (GNUNET_OK ==
+ GNUNET_CRYPTO_hash_from_string ((const char *) &hash,
+ &(target.hashPubKey)))
+ {
+ tag = strtoul (tagc, NULL, 10);
+ if (tagc > 0)
+ check = GNUNET_YES;
+ }
+ }
+
+ if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
+ direction = _RECEIVE;
+ else if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
+ direction = _SEND;
+ else
+ {
+ GNUNET_break_op (0);
+ goto error;
+ }
+
+
+ if (check == GNUNET_NO)
+ goto error;
+
+ plugin->cur_connections++;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: New inbound connection from %s with tag %u\n",
+ GNUNET_i2s (&target), tag);
+ /* find duplicate session */
+
+ t = plugin->head;
+
+ while (t != NULL)
+ {
+ if ((t->inbound) &&
+ (0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity)))
+ &&
+ /* FIXME add source address comparison */
+ (t->tag == tag))
+ break;
+ t = t->next;
+ }
+ if (t != NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Duplicate session, dismissing new connection from peer `%s'\n",
+ GNUNET_i2s (&target));
+ goto error;
+ }
+
+ /* find semi-session */
+ t = plugin->server_semi_head;
+
+ while (t != NULL)
+ {
+ /* FIXME add source address comparison */
+ if ((0 == memcmp (&t->target, &target, sizeof (struct GNUNET_PeerIdentity)))
+ && (t->tag == tag))
+ {
+ break;
+ }
+ t = t->next;
+ }
+
+ if (t == NULL)
+ goto create;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Found existing semi-session for `%s'\n",
+ GNUNET_i2s (&target));
+
+ if ((direction == _SEND) && (t->server_send != NULL))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Duplicate GET session, dismissing new connection from peer `%s'\n",
+ GNUNET_i2s (&target));
+ goto error;
+ }
+ else
+ {
+ s = t;
+ GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head,
+ plugin->server_semi_tail, s);
+ GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Found matching semi-session, merging session for peer `%s'\n",
+ GNUNET_i2s (&target));
+
+ goto found;
+ }
+ if ((direction == _RECEIVE) && (t->server_recv != NULL))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Duplicate PUT session, dismissing new connection from peer `%s'\n",
+ GNUNET_i2s (&target));
+ goto error;
+ }
+ else
+ {
+ s = t;
+ GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head,
+ plugin->server_semi_tail, s);
+ GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Found matching semi-session, merging session for peer `%s'\n",
+ GNUNET_i2s (&target));
+ goto found;
+ }
+
+create:
+/* create new session */
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Creating new session for peer `%s' \n",
+ GNUNET_i2s (&target));
+ switch (conn_info->client_addr->sa_family)
+ {
+ case (AF_INET):
+ s4 = ((struct sockaddr_in *) conn_info->client_addr);
+ a4.u4_port = s4->sin_port;
+ memcpy (&a4.ipv4_addr, &s4->sin_addr, sizeof (struct in_addr));
+ a = &a4;
+ a_len = sizeof (struct IPv4HttpAddress);
+ ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s4, sizeof (struct sockaddr_in));
+ break;
+ case (AF_INET6):
+ s6 = ((struct sockaddr_in6 *) conn_info->client_addr);
+ a6.u6_port = s6->sin6_port;
+ memcpy (&a6.ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr));
+ a = &a6;
+ a_len = sizeof (struct IPv6HttpAddress);
+ ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) s6, sizeof (struct sockaddr_in6));
+ break;
+ default:
+ GNUNET_break (0);
+ goto error;
+ }
+ s = create_session (plugin, &target, a, a_len, NULL, NULL);
+ s->ats_address_network_type = ats.value;
+
+ s->inbound = GNUNET_YES;
+ s->next_receive = GNUNET_TIME_absolute_get_zero ();
+ s->tag = tag;
+ if (0 == strcmp (MHD_HTTP_METHOD_PUT, method))
+ s->server_recv = s;
+ if (0 == strcmp (MHD_HTTP_METHOD_GET, method))
+ s->server_send = s;
+ GNUNET_CONTAINER_DLL_insert (plugin->server_semi_head,
+ plugin->server_semi_tail, s);
+ goto found;
+
+error:
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Invalid connection request\n");
+ return NULL;
+
+found:
+ sc = GNUNET_malloc (sizeof (struct ServerConnection));
+ sc->mhd_conn = mhd_connection;
+ sc->direction = direction;
+ sc->session = s;
+ if (direction == _SEND)
+ s->server_send = sc;
+ if (direction == _RECEIVE)
+ s->server_recv = sc;
+
+#if MHD_VERSION >= 0x00090E00
+ int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Setting timeout for %X to %u sec.\n", sc, to);
+ MHD_set_connection_option (mhd_connection, MHD_CONNECTION_OPTION_TIMEOUT, to);
+
+ struct MHD_Daemon *d = NULL;
+
+ if (s->addrlen == sizeof (struct IPv6HttpAddress))
+ d = plugin->server_v6;
+ if (s->addrlen == sizeof (struct IPv4HttpAddress))
+ d = plugin->server_v4;
+
+ server_reschedule (plugin, d, GNUNET_NO);
+#endif
+ return sc;
+}
+
+/**
+ * Process GET or PUT request received via MHD. For
+ * GET, queue response that will send back our pending
+ * messages. For PUT, process incoming data and send
+ * to GNUnet core. In either case, check if a session
+ * already exists and create a new one if not.
+ */
+static int
+server_access_cb (void *cls, struct MHD_Connection *mhd_connection,
+ const char *url, const char *method, const char *version,
+ const char *upload_data, size_t * upload_data_size,
+ void **httpSessionCache)
+{
+
+ struct Plugin *plugin = cls;
+ struct ServerConnection *sc = *httpSessionCache;
+ struct Session *s = NULL;
+
+ int res = MHD_YES;
+ struct MHD_Response *response;
+
+ GNUNET_assert (cls != NULL);
+ /* new connection */
+ if (sc == NULL)
+ {
+ sc = server_lookup_session (plugin, mhd_connection, url, method);
+ if (sc != NULL)
+ (*httpSessionCache) = sc;
+ else
+ {
+ response =
+ MHD_create_response_from_data (strlen (HTTP_ERROR_RESPONSE),
+ HTTP_ERROR_RESPONSE, MHD_NO, MHD_NO);
+ res = MHD_queue_response (mhd_connection, MHD_HTTP_NOT_FOUND, response);
+ MHD_destroy_response (response);
+ return res;
+ }
+ }
+
+ /* existing connection */
+ sc = (*httpSessionCache);
+ s = sc->session;
+
+ /* connection is to be disconnected */
+ if (sc->disconnect == GNUNET_YES)
+ {
+ /* Sent HTTP/1.1: 200 OK as PUT Response\ */
+ response =
+ MHD_create_response_from_data (strlen ("Thank you!"), "Thank you!",
+ MHD_NO, MHD_NO);
+ res = MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return MHD_YES;
+ }
+
+ GNUNET_assert (s != NULL);
+ /* Check if both directions are connected */
+ if ((sc->session->server_recv == NULL) || (sc->session->server_send == NULL))
+ {
+ /* Delayed read from since not both semi-connections are connected */
+ return MHD_YES;
+ }
+
+ if (sc->direction == _SEND)
+ {
+ response =
+ MHD_create_response_from_callback (-1, 32 * 1024, &server_send_callback,
+ s, NULL);
+ MHD_queue_response (mhd_connection, MHD_HTTP_OK, response);
+ MHD_destroy_response (response);
+ return MHD_YES;
+ }
+ if (sc->direction == _RECEIVE)
+ {
+ if (*upload_data_size == 0)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Peer `%s' PUT on address `%s' connected\n",
+ GNUNET_i2s (&s->target),
+ http_plugin_address_to_string (NULL, s->addr,
+ s->addrlen));
+ return MHD_YES;
+ }
+
+ /* Receiving data */
+ if ((*upload_data_size > 0))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: peer `%s' PUT on address `%s' received %u bytes\n",
+ GNUNET_i2s (&s->target),
+ http_plugin_address_to_string (NULL, s->addr,
+ s->addrlen),
+ *upload_data_size);
+ struct GNUNET_TIME_Absolute now = GNUNET_TIME_absolute_get ();
+
+ if ((s->next_receive.abs_value <= now.abs_value))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: %X: PUT with %u bytes forwarded to MST\n", s,
+ *upload_data_size);
+ if (s->msg_tk == NULL)
+ {
+ s->msg_tk = GNUNET_SERVER_mst_create (&server_receive_mst_cb, s);
+ }
+ GNUNET_SERVER_mst_receive (s->msg_tk, s, upload_data,
+ *upload_data_size, GNUNET_NO, GNUNET_NO);
+
+#if MHD_VERSION >= 0x00090E00
+ int to = (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000);
+ struct ServerConnection *t = NULL;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Received %u bytes\n", *upload_data_size);
+ /* Setting timeouts for other connections */
+ if (s->server_recv != NULL)
+ {
+ t = s->server_recv;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Setting timeout for %X to %u sec.\n", t,
+ to);
+ MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT,
+ to);
+ }
+ if (s->server_send != NULL)
+ {
+ t = s->server_send;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: Setting timeout for %X to %u sec.\n", t,
+ to);
+ MHD_set_connection_option (t->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT,
+ to);
+ }
+ struct MHD_Daemon *d = NULL;
+
+ if (s->addrlen == sizeof (struct IPv6HttpAddress))
+ d = plugin->server_v6;
+ if (s->addrlen == sizeof (struct IPv4HttpAddress))
+ d = plugin->server_v4;
+ server_reschedule (plugin, d, GNUNET_NO);
+#endif
+ (*upload_data_size) = 0;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Server: %X no inbound bandwidth available! Next read was delayed by %llu ms\n",
+ s, now.abs_value - s->next_receive.abs_value);
+ }
+ return MHD_YES;
+ }
+ else
+ return MHD_NO;
+ }
+ return res;
+}
+
+static void
+server_disconnect_cb (void *cls, struct MHD_Connection *connection,
+ void **httpSessionCache)
+{
+ struct ServerConnection *sc = *httpSessionCache;
+ struct ServerConnection *tc = NULL;
+ struct Session *s = NULL;
+ struct Session *t = NULL;
+ struct Plugin *plugin = NULL;
+
+ if (sc == NULL)
+ return;
+
+ s = sc->session;
+ plugin = s->plugin;
+ if (sc->direction == _SEND)
+ {
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: %X peer `%s' GET on address `%s' disconnected\n",
+ s->server_send, GNUNET_i2s (&s->target),
+ http_plugin_address_to_string (NULL, s->addr, s->addrlen));
+
+ s->server_send = NULL;
+
+ if (s->server_recv != NULL)
+ {
+ tc = s->server_recv;
+ tc->disconnect = GNUNET_YES;
+#if MHD_VERSION >= 0x00090E00
+ MHD_set_connection_option (sc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT,
+ 1);
+#endif
+ }
+ }
+ if (sc->direction == _RECEIVE)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: %X peer `%s' PUT on address `%s' disconnected\n",
+ s->server_recv, GNUNET_i2s (&s->target),
+ http_plugin_address_to_string (NULL, s->addr, s->addrlen));
+ s->server_recv = NULL;
+ if (s->server_send != NULL)
+ {
+ tc = s->server_send;
+ tc->disconnect = GNUNET_YES;
+#if MHD_VERSION >= 0x00090E00
+ MHD_set_connection_option (sc->mhd_conn, MHD_CONNECTION_OPTION_TIMEOUT,
+ 1);
+#endif
+ }
+ if (s->msg_tk != NULL)
+ {
+ GNUNET_SERVER_mst_destroy (s->msg_tk);
+ s->msg_tk = NULL;
+ }
+ }
+ GNUNET_free (sc);
+
+ t = plugin->server_semi_head;
+ while (t != NULL)
+ {
+ if (t == s)
+ {
+ GNUNET_CONTAINER_DLL_remove (plugin->server_semi_head,
+ plugin->server_semi_tail, s);
+ GNUNET_CONTAINER_DLL_insert (plugin->head, plugin->tail, s);
+ break;
+ }
+ t = t->next;
+ }
+ plugin->cur_connections--;
+
+ struct MHD_Daemon *d = NULL;
+
+ if (s->addrlen == sizeof (struct IPv6HttpAddress))
+ d = plugin->server_v6;
+ if (s->addrlen == sizeof (struct IPv4HttpAddress))
+ d = plugin->server_v4;
+ server_reschedule (plugin, d, GNUNET_NO);
+
+ if ((s->server_send == NULL) && (s->server_recv == NULL))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Server: peer `%s' on address `%s' disconnected\n",
+ GNUNET_i2s (&s->target),
+ http_plugin_address_to_string (NULL, s->addr, s->addrlen));
+ if (s->msg_tk != NULL)
+ {
+ GNUNET_SERVER_mst_destroy (s->msg_tk);
+ s->msg_tk = NULL;
+ }
+
+ notify_session_end (s->plugin, &s->target, s);
+ }
+}
+
+int
+server_disconnect (struct Session *s)
+{
+ struct Plugin *plugin = s->plugin;
+ struct Session *t = plugin->head;
+
+ while (t != NULL)
+ {
+ if (t->inbound == GNUNET_YES)
+ {
+ if (t->server_send != NULL)
+ {
+ ((struct ServerConnection *) t->server_send)->disconnect = GNUNET_YES;
+ }
+ if (t->server_send != NULL)
+ {
+ ((struct ServerConnection *) t->server_send)->disconnect = GNUNET_YES;
+ }
+ }
+ t = t->next;
+ }
+ return GNUNET_OK;
+}
+
+int
+server_send (struct Session *s, struct HTTP_Message *msg)
+{
+ GNUNET_CONTAINER_DLL_insert (s->msg_head, s->msg_tail, msg);
+
+ if (s->addrlen == sizeof (struct IPv4HttpAddress))
+ {
+ server_reschedule (s->plugin, s->plugin->server_v4, GNUNET_YES);
+ }
+ else if (s->addrlen == sizeof (struct IPv6HttpAddress))
+ {
+ server_reschedule (s->plugin, s->plugin->server_v6, GNUNET_YES);
+ }
+ else
+ return GNUNET_SYSERR;
+ return GNUNET_OK;
+}
+
+
+
+/**
+ * Call MHD IPv4 to process pending requests and then go back
+ * and schedule the next run.
+ * @param cls plugin as closure
+ * @param tc task context
+ */
+static void
+server_v4_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ GNUNET_assert (cls != NULL);
+
+ plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Running IPv4 server\n");
+
+ GNUNET_assert (MHD_YES == MHD_run (plugin->server_v4));
+ if (plugin->server_v4 != NULL)
+ plugin->server_v4_task =
+ server_schedule (plugin, plugin->server_v4, GNUNET_NO);
+}
+
+
+/**
+ * Call MHD IPv6 to process pending requests and then go back
+ * and schedule the next run.
+ * @param cls plugin as closure
+ * @param tc task context
+ */
+static void
+server_v6_run (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ GNUNET_assert (cls != NULL);
+
+ plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Running IPv6 server\n");
+
+ GNUNET_assert (MHD_YES == MHD_run (plugin->server_v6));
+ if (plugin->server_v6 != NULL)
+ plugin->server_v6_task =
+ server_schedule (plugin, plugin->server_v6, GNUNET_NO);
+}
+
+/**
+ * Function that queries MHD's select sets and
+ * starts the task waiting for them.
+ * @param plugin plugin
+ * @param daemon_handle the MHD daemon handle
+ * @return gnunet task identifier
+ */
+static GNUNET_SCHEDULER_TaskIdentifier
+server_schedule (struct Plugin *plugin, struct MHD_Daemon *daemon_handle,
+ int now)
+{
+ GNUNET_SCHEDULER_TaskIdentifier ret;
+ fd_set rs;
+ fd_set ws;
+ fd_set es;
+ struct GNUNET_NETWORK_FDSet *wrs;
+ struct GNUNET_NETWORK_FDSet *wws;
+ struct GNUNET_NETWORK_FDSet *wes;
+ int max;
+ unsigned long long timeout;
+ static unsigned long long last_timeout = 0;
+ int haveto;
+
+ struct GNUNET_TIME_Relative tv;
+
+ ret = GNUNET_SCHEDULER_NO_TASK;
+ FD_ZERO (&rs);
+ FD_ZERO (&ws);
+ FD_ZERO (&es);
+ wrs = GNUNET_NETWORK_fdset_create ();
+ wes = GNUNET_NETWORK_fdset_create ();
+ wws = GNUNET_NETWORK_fdset_create ();
+ max = -1;
+ GNUNET_assert (MHD_YES == MHD_get_fdset (daemon_handle, &rs, &ws, &es, &max));
+ haveto = MHD_get_timeout (daemon_handle, &timeout);
+ if (haveto == MHD_YES)
+ {
+ if (timeout != last_timeout)
+ {
+#if VERBOSE_SERVER
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "SELECT Timeout changed from %llu to %llu\n",
+ last_timeout, timeout);
+#endif
+ last_timeout = timeout;
+ }
+ tv.rel_value = (uint64_t) timeout;
+ }
+ else
+ tv = GNUNET_TIME_UNIT_SECONDS;
+ /* Force immediate run, since we have outbound data to send */
+ if (now == GNUNET_YES)
+ tv = GNUNET_TIME_UNIT_MILLISECONDS;
+ GNUNET_NETWORK_fdset_copy_native (wrs, &rs, max + 1);
+ GNUNET_NETWORK_fdset_copy_native (wws, &ws, max + 1);
+ GNUNET_NETWORK_fdset_copy_native (wes, &es, max + 1);
+
+ if (daemon_handle == plugin->server_v4)
+ {
+ if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
+ plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+#if VERBOSE_SERVER
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Scheduling IPv4 server task in %llu ms\n", tv);
+#endif
+ ret =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws,
+ &server_v4_run, plugin);
+ }
+ if (daemon_handle == plugin->server_v6)
+ {
+ if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
+ plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+#if VERBOSE_SERVER
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Scheduling IPv6 server task in %llu ms\n", tv);
+#endif
+ ret =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK, tv, wrs, wws,
+ &server_v6_run, plugin);
+ }
+ GNUNET_NETWORK_fdset_destroy (wrs);
+ GNUNET_NETWORK_fdset_destroy (wws);
+ GNUNET_NETWORK_fdset_destroy (wes);
+ return ret;
+}
+
+int
+server_start (struct Plugin *plugin)
+{
+ int res = GNUNET_OK;
+ unsigned int timeout;
+
+#if BUILD_HTTPS
+ res = server_load_certificate (plugin);
+ if (res == GNUNET_SYSERR)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ "Could not load or create server certificate! Loading plugin failed!\n");
+ return res;
+ }
+#endif
+
+
+#if MHD_VERSION >= 0x00090E00
+ timeout = HTTP_NOT_VALIDATED_TIMEOUT.rel_value / 1000;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "MHD can set timeout per connection! Default time out %u sec.\n",
+ timeout);
+#else
+ timeout = GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT.rel_value / 1000;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, plugin->name,
+ "MHD cannot set timeout per connection! Default time out %u sec.\n",
+ timeout);
+#endif
+ plugin->server_v4 = NULL;
+ if (plugin->ipv4 == GNUNET_YES)
+ {
+ plugin->server_v4 = MHD_start_daemon (
+#if VERBOSE_SERVER
+ MHD_USE_DEBUG |
+#endif
+#if BUILD_HTTPS
+ MHD_USE_SSL |
+#endif
+ MHD_NO_FLAG, plugin->port,
+ &server_accept_cb, plugin,
+ &server_access_cb, plugin,
+ MHD_OPTION_SOCK_ADDR,
+ (struct sockaddr_in *)
+ plugin->server_addr_v4,
+ MHD_OPTION_CONNECTION_LIMIT,
+ (unsigned int)
+ plugin->max_connections,
+#if BUILD_HTTPS
+ MHD_OPTION_HTTPS_PRIORITIES,
+ plugin->crypto_init,
+ MHD_OPTION_HTTPS_MEM_KEY,
+ plugin->key,
+ MHD_OPTION_HTTPS_MEM_CERT,
+ plugin->cert,
+#endif
+ MHD_OPTION_CONNECTION_TIMEOUT,
+ timeout,
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+ (size_t) (2 *
+ GNUNET_SERVER_MAX_MESSAGE_SIZE),
+ MHD_OPTION_NOTIFY_COMPLETED,
+ &server_disconnect_cb, plugin,
+ MHD_OPTION_EXTERNAL_LOGGER,
+ server_log, NULL, MHD_OPTION_END);
+ }
+ plugin->server_v6 = NULL;
+ if (plugin->ipv6 == GNUNET_YES)
+ {
+ plugin->server_v6 = MHD_start_daemon (
+#if VERBOSE_SERVER
+ MHD_USE_DEBUG |
+#endif
+#if BUILD_HTTPS
+ MHD_USE_SSL |
+#endif
+ MHD_USE_IPv6, plugin->port,
+ &server_accept_cb, plugin,
+ &server_access_cb, plugin,
+ MHD_OPTION_SOCK_ADDR,
+ (struct sockaddr_in6 *)
+ plugin->server_addr_v6,
+ MHD_OPTION_CONNECTION_LIMIT,
+ (unsigned int)
+ plugin->max_connections,
+#if BUILD_HTTPS
+ MHD_OPTION_HTTPS_PRIORITIES,
+ plugin->crypto_init,
+ MHD_OPTION_HTTPS_MEM_KEY,
+ plugin->key,
+ MHD_OPTION_HTTPS_MEM_CERT,
+ plugin->cert,
+#endif
+ MHD_OPTION_CONNECTION_TIMEOUT,
+ timeout,
+ MHD_OPTION_CONNECTION_MEMORY_LIMIT,
+ (size_t) (2 *
+ GNUNET_SERVER_MAX_MESSAGE_SIZE),
+ MHD_OPTION_NOTIFY_COMPLETED,
+ &server_disconnect_cb, plugin,
+ MHD_OPTION_EXTERNAL_LOGGER,
+ server_log, NULL, MHD_OPTION_END);
+
+ }
+
+ if ((plugin->ipv4 == GNUNET_YES) && (plugin->server_v4 == NULL))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ "Failed to start %s IPv4 server component on port %u\n",
+ plugin->name, plugin->port);
+ return GNUNET_SYSERR;
+ }
+ server_reschedule (plugin, plugin->server_v4, GNUNET_NO);
+
+ if ((plugin->ipv6 == GNUNET_YES) && (plugin->server_v6 == NULL))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, plugin->name,
+ "Failed to start %s IPv6 server component on port %u\n",
+ plugin->name, plugin->port);
+ return GNUNET_SYSERR;
+ }
+ server_reschedule (plugin, plugin->server_v6, GNUNET_NO);
+
+
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "%s server component started on port %u\n", plugin->name,
+ plugin->port);
+#endif
+ return res;
+}
+
+void
+server_stop (struct Plugin *plugin)
+{
+ struct Session *s = NULL;
+ struct Session *t = NULL;
+
+ struct MHD_Daemon *server_v4_tmp = plugin->server_v4;
+
+ plugin->server_v4 = NULL;
+ struct MHD_Daemon *server_v6_tmp = plugin->server_v6;
+
+ plugin->server_v6 = NULL;
+
+ if (plugin->server_v4_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_v4_task);
+ plugin->server_v4_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (plugin->server_v6_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_v6_task);
+ plugin->server_v6_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (server_v6_tmp != NULL)
+ {
+ MHD_stop_daemon (server_v4_tmp);
+ }
+ if (server_v6_tmp != NULL)
+ {
+ MHD_stop_daemon (server_v6_tmp);
+ }
+
+ /* cleaning up semi-sessions never propagated */
+ s = plugin->server_semi_head;
+ while (s != NULL)
+ {
+#if VERBOSE_SERVER
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "Deleting semi-sessions %p\n", s);
+#endif
+ t = s->next;
+ struct HTTP_Message *msg = s->msg_head;
+ struct HTTP_Message *tmp = NULL;
+
+ while (msg != NULL)
+ {
+ tmp = msg->next;
+
+ GNUNET_CONTAINER_DLL_remove (s->msg_head, s->msg_tail, msg);
+ if (msg->transmit_cont != NULL)
+ {
+ msg->transmit_cont (msg->transmit_cont_cls, &s->target, GNUNET_SYSERR);
+ }
+ GNUNET_free (msg);
+ msg = tmp;
+ }
+
+ delete_session (s);
+ s = t;
+ }
+
+#if BUILD_HTTPS
+ GNUNET_free_non_null (plugin->crypto_init);
+ GNUNET_free_non_null (plugin->cert);
+ GNUNET_free_non_null (plugin->key);
+#endif
+
+#if DEBUG_HTTP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, plugin->name,
+ "%s server component stopped\n", plugin->name);
+#endif
+}
+
+
+
+/* end of plugin_transport_http.c */
diff --git a/src/transport/plugin_transport_tcp.c b/src/transport/plugin_transport_tcp.c
new file mode 100644
index 0000000..2b2d728
--- /dev/null
+++ b/src/transport/plugin_transport_tcp.c
@@ -0,0 +1,2115 @@
+/*
+ This file is part of GNUnet
+ (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/plugin_transport_tcp.c
+ * @brief Implementation of the TCP transport service
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_constants.h"
+#include "gnunet_connection_lib.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_nat_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_service_lib.h"
+#include "gnunet_signatures.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_transport_plugin.h"
+#include "transport.h"
+
+#define DEBUG_TCP GNUNET_EXTRA_LOGGING
+
+#define DEBUG_TCP_NAT GNUNET_EXTRA_LOGGING
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Initial handshake message for a session.
+ */
+struct WelcomeMessage
+{
+ /**
+ * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Identity of the node connecting (TCP client)
+ */
+ struct GNUNET_PeerIdentity clientIdentity;
+
+};
+
+
+/**
+ * Basically a WELCOME message, but with the purpose
+ * of giving the waiting peer a client handle to use
+ */
+struct TCP_NAT_ProbeMessage
+{
+ /**
+ * Type is GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Identity of the sender of the message.
+ */
+ struct GNUNET_PeerIdentity clientIdentity;
+
+};
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * Context for sending a NAT probe via TCP.
+ */
+struct TCPProbeContext
+{
+
+ /**
+ * Active probes are kept in a DLL.
+ */
+ struct TCPProbeContext *next;
+
+ /**
+ * Active probes are kept in a DLL.
+ */
+ struct TCPProbeContext *prev;
+
+ /**
+ * Probe connection.
+ */
+ struct GNUNET_CONNECTION_Handle *sock;
+
+ /**
+ * Message to be sent.
+ */
+ struct TCP_NAT_ProbeMessage message;
+
+ /**
+ * Handle to the transmission.
+ */
+ struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
+
+ /**
+ * Transport plugin handle.
+ */
+ struct Plugin *plugin;
+};
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Network format for IPv4 addresses.
+ */
+struct IPv4TcpAddress
+{
+ /**
+ * IPv4 address, in network byte order.
+ */
+ uint32_t ipv4_addr GNUNET_PACKED;
+
+ /**
+ * Port number, in network byte order.
+ */
+ uint16_t t4_port GNUNET_PACKED;
+
+};
+
+
+/**
+ * Network format for IPv6 addresses.
+ */
+struct IPv6TcpAddress
+{
+ /**
+ * IPv6 address.
+ */
+ struct in6_addr ipv6_addr GNUNET_PACKED;
+
+ /**
+ * Port number, in network byte order.
+ */
+ uint16_t t6_port GNUNET_PACKED;
+
+};
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin;
+
+
+/**
+ * Information kept for each message that is yet to
+ * be transmitted.
+ */
+struct PendingMessage
+{
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct PendingMessage *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct PendingMessage *prev;
+
+ /**
+ * The pending message
+ */
+ const char *msg;
+
+ /**
+ * Continuation function to call once the message
+ * has been sent. Can be NULL if there is no
+ * continuation to call.
+ */
+ GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
+
+ /**
+ * Closure for transmit_cont.
+ */
+ void *transmit_cont_cls;
+
+ /**
+ * Timeout value for the pending message.
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * So that the gnunet-service-transport can group messages together,
+ * these pending messages need to accept a message buffer and size
+ * instead of just a GNUNET_MessageHeader.
+ */
+ size_t message_size;
+
+};
+
+
+/**
+ * Session handle for TCP connections.
+ */
+struct Session
+{
+
+ /**
+ * API requirement.
+ */
+ struct SessionHeader header;
+
+ /**
+ * Stored in a linked list.
+ */
+ struct Session *next;
+
+ /**
+ * Pointer to the global plugin struct.
+ */
+ struct Plugin *plugin;
+
+ /**
+ * The client (used to identify this connection)
+ */
+ struct GNUNET_SERVER_Client *client;
+
+ /**
+ * Messages currently pending for transmission
+ * to this peer, if any.
+ */
+ struct PendingMessage *pending_messages_head;
+
+ /**
+ * Messages currently pending for transmission
+ * to this peer, if any.
+ */
+ struct PendingMessage *pending_messages_tail;
+
+ /**
+ * Handle for pending transmission request.
+ */
+ struct GNUNET_CONNECTION_TransmitHandle *transmit_handle;
+
+ /**
+ * To whom are we talking to (set to our identity
+ * if we are still waiting for the welcome message)
+ */
+ struct GNUNET_PeerIdentity target;
+
+ /**
+ * ID of task used to delay receiving more to throttle sender.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier receive_delay_task;
+
+ /**
+ * Address of the other peer (either based on our 'connect'
+ * call or on our 'accept' call).
+ *
+ * struct IPv4TcpAddress or struct IPv6TcpAddress
+ *
+ */
+ void *addr;
+
+ /**
+ * Length of connect_addr.
+ */
+ size_t addrlen;
+
+ /**
+ * Last activity on this connection. Used to select preferred
+ * connection.
+ */
+ struct GNUNET_TIME_Absolute last_activity;
+
+ /**
+ * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO)
+ */
+ int expecting_welcome;
+
+ /**
+ * Was this a connection that was inbound (we accepted)? (GNUNET_YES/GNUNET_NO)
+ */
+ int inbound;
+
+ /**
+ * Was this session created using NAT traversal?
+ */
+ int is_nat;
+
+ /**
+ * ATS network type in NBO
+ */
+ uint32_t ats_address_network_type;
+};
+
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin
+{
+ /**
+ * Our environment.
+ */
+ struct GNUNET_TRANSPORT_PluginEnvironment *env;
+
+ /**
+ * The listen socket.
+ */
+ struct GNUNET_CONNECTION_Handle *lsock;
+
+ /**
+ * Our handle to the NAT module.
+ */
+ struct GNUNET_NAT_Handle *nat;
+
+ struct GNUNET_CONTAINER_MultiHashMap * sessionmap;
+
+ /**
+ * Handle to the network service.
+ */
+ struct GNUNET_SERVICE_Context *service;
+
+ /**
+ * Handle to the server for this service.
+ */
+ struct GNUNET_SERVER_Handle *server;
+
+ /**
+ * Copy of the handler array where the closures are
+ * set to this struct's instance.
+ */
+ struct GNUNET_SERVER_MessageHandler *handlers;
+
+ /**
+ * Map of peers we have tried to contact behind a NAT
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *nat_wait_conns;
+
+ /**
+ * List of active TCP probes.
+ */
+ struct TCPProbeContext *probe_head;
+
+ /**
+ * List of active TCP probes.
+ */
+ struct TCPProbeContext *probe_tail;
+
+ /**
+ * Handle for (DYN)DNS lookup of our external IP.
+ */
+ struct GNUNET_RESOLVER_RequestHandle *ext_dns;
+
+ /**
+ * How many more TCP sessions are we allowed to open right now?
+ */
+ unsigned long long max_connections;
+
+ /**
+ * ID of task used to update our addresses when one expires.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier address_update_task;
+
+ /**
+ * Port that we are actually listening on.
+ */
+ uint16_t open_port;
+
+ /**
+ * Port that the user said we would have visible to the
+ * rest of the world.
+ */
+ uint16_t adv_port;
+
+};
+
+
+/**
+ * Function to check if an inbound connection is acceptable.
+ * Mostly used to limit the total number of open connections
+ * we can have.
+ *
+ * @param cls the 'struct Plugin'
+ * @param ucred credentials, if available, otherwise NULL
+ * @param addr address
+ * @param addrlen length of address
+ * @return GNUNET_YES to allow, GNUNET_NO to deny, GNUNET_SYSERR
+ * for unknown address family (will be denied).
+ */
+static int
+plugin_tcp_access_check (void *cls,
+ const struct GNUNET_CONNECTION_Credentials *ucred,
+ const struct sockaddr *addr, socklen_t addrlen)
+{
+ struct Plugin *plugin = cls;
+
+ if (0 == plugin->max_connections)
+ return GNUNET_NO;
+ plugin->max_connections--;
+ return GNUNET_YES;
+}
+
+
+/**
+ * Our external IP address/port mapping has changed.
+ *
+ * @param cls closure, the 'struct LocalAddrList'
+ * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
+ * the previous (now invalid) one
+ * @param addr either the previous or the new public IP address
+ * @param addrlen actual lenght of the address
+ */
+static void
+tcp_nat_port_map_callback (void *cls, int add_remove,
+ const struct sockaddr *addr, socklen_t addrlen)
+{
+ struct Plugin *plugin = cls;
+ struct IPv4TcpAddress t4;
+ struct IPv6TcpAddress t6;
+ void *arg;
+ size_t args;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "NPMC called with %d for address `%s'\n", add_remove,
+ GNUNET_a2s (addr, addrlen));
+ /* convert 'addr' to our internal format */
+ switch (addr->sa_family)
+ {
+ case AF_INET:
+ GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
+ t4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ t4.t4_port = ((struct sockaddr_in *) addr)->sin_port;
+ arg = &t4;
+ args = sizeof (t4);
+ break;
+ case AF_INET6:
+ GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
+ memcpy (&t6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr,
+ sizeof (struct in6_addr));
+ t6.t6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
+ arg = &t6;
+ args = sizeof (t6);
+ break;
+ default:
+ GNUNET_break (0);
+ return;
+ }
+ /* modify our published address list */
+ plugin->env->notify_address (plugin->env->cls, add_remove, arg, args);
+}
+
+
+/**
+ * Function called for a quick conversion of the binary address to
+ * a numeric address. Note that the caller must not free the
+ * address and that the next call to this function is allowed
+ * to override the address again.
+ *
+ * @param cls closure ('struct Plugin*')
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return string representing the same address
+ */
+static const char *
+tcp_address_to_string (void *cls, const void *addr, size_t addrlen)
+{
+ static char rbuf[INET6_ADDRSTRLEN + 12];
+ char buf[INET6_ADDRSTRLEN];
+ const void *sb;
+ struct in_addr a4;
+ struct in6_addr a6;
+ const struct IPv4TcpAddress *t4;
+ const struct IPv6TcpAddress *t6;
+ int af;
+ uint16_t port;
+
+ if (addrlen == sizeof (struct IPv6TcpAddress))
+ {
+ t6 = addr;
+ af = AF_INET6;
+ port = ntohs (t6->t6_port);
+ memcpy (&a6, &t6->ipv6_addr, sizeof (a6));
+ sb = &a6;
+ }
+ else if (addrlen == sizeof (struct IPv4TcpAddress))
+ {
+ t4 = addr;
+ af = AF_INET;
+ port = ntohs (t4->t4_port);
+ memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
+ sb = &a4;
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp",
+ _("Unexpected address length: %u bytes\n"),
+ (unsigned int) addrlen);
+ GNUNET_break (0);
+ return NULL;
+ }
+ if (NULL == inet_ntop (af, sb, buf, INET6_ADDRSTRLEN))
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "inet_ntop");
+ return NULL;
+ }
+ GNUNET_snprintf (rbuf, sizeof (rbuf), (af == AF_INET6) ? "[%s]:%u" : "%s:%u",
+ buf, port);
+ return rbuf;
+}
+
+
+struct SessionClientCtx
+{
+ const struct GNUNET_SERVER_Client *client;
+ struct Session *ret;
+};
+
+int session_lookup_by_client_it (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct SessionClientCtx *sc_ctx = cls;
+ struct Session *s = value;
+
+ if (s->client == sc_ctx->client)
+ {
+ sc_ctx->ret = s;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+/**
+ * Find the session handle for the given client.
+ *
+ * @param plugin the plugin
+ * @param client which client to find the session handle for
+ * @return NULL if no matching session exists
+ */
+static struct Session *
+lookup_session_by_client (struct Plugin *plugin,
+ const struct GNUNET_SERVER_Client *client)
+{
+ struct SessionClientCtx sc_ctx;
+ sc_ctx.client = client;
+ sc_ctx.ret = NULL;
+
+ GNUNET_CONTAINER_multihashmap_iterate (plugin->sessionmap, &session_lookup_by_client_it, &sc_ctx);
+
+ return sc_ctx.ret;
+}
+
+
+/**
+ * Create a new session. Also queues a welcome message.
+ *
+ * @param plugin the plugin
+ * @param target peer to connect to
+ * @param client client to use
+ * @param is_nat this a NAT session, we should wait for a client to
+ * connect to us from an address, then assign that to
+ * the session
+ * @return new session object
+ */
+static struct Session *
+create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
+ struct GNUNET_SERVER_Client *client, int is_nat)
+{
+ struct Session *ret;
+ struct PendingMessage *pm;
+ struct WelcomeMessage welcome;
+
+ if (is_nat != GNUNET_YES)
+ GNUNET_assert (client != NULL);
+ else
+ GNUNET_assert (client == NULL);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Creating new session for peer `%4s'\n",
+ GNUNET_i2s (target));
+
+ ret = GNUNET_malloc (sizeof (struct Session));
+ ret->last_activity = GNUNET_TIME_absolute_get ();
+ ret->plugin = plugin;
+ ret->is_nat = is_nat;
+ ret->client = client;
+ ret->target = *target;
+ ret->expecting_welcome = GNUNET_YES;
+ ret->ats_address_network_type = htonl (GNUNET_ATS_NET_UNSPECIFIED);
+ pm = GNUNET_malloc (sizeof (struct PendingMessage) +
+ sizeof (struct WelcomeMessage));
+ pm->msg = (const char *) &pm[1];
+ pm->message_size = sizeof (struct WelcomeMessage);
+ welcome.header.size = htons (sizeof (struct WelcomeMessage));
+ welcome.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME);
+ welcome.clientIdentity = *plugin->env->my_identity;
+ memcpy (&pm[1], &welcome, sizeof (welcome));
+ pm->timeout = GNUNET_TIME_UNIT_FOREVER_ABS;
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ gettext_noop ("# bytes currently in TCP buffers"),
+ pm->message_size, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_insert (ret->pending_messages_head,
+ ret->pending_messages_tail, pm);
+ if (is_nat != GNUNET_YES)
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ gettext_noop ("# TCP sessions active"), 1,
+ GNUNET_NO);
+ return ret;
+}
+
+
+/**
+ * If we have pending messages, ask the server to
+ * transmit them (schedule the respective tasks, etc.)
+ *
+ * @param session for which session should we do this
+ */
+static void
+process_pending_messages (struct Session *session);
+
+
+/**
+ * Function called to notify a client about the socket
+ * being ready to queue more data. "buf" will be
+ * NULL and "size" zero if the socket was closed for
+ * writing in the meantime.
+ *
+ * @param cls closure
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+do_transmit (void *cls, size_t size, void *buf)
+{
+ struct Session *session = cls;
+ struct GNUNET_PeerIdentity pid;
+ struct Plugin *plugin;
+ struct PendingMessage *pos;
+ struct PendingMessage *hd;
+ struct PendingMessage *tl;
+ struct GNUNET_TIME_Absolute now;
+ char *cbuf;
+ size_t ret;
+
+ GNUNET_assert (session != NULL);
+ session->transmit_handle = NULL;
+ plugin = session->plugin;
+ if (buf == NULL)
+ {
+#if DEBUG_TCP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Timeout trying to transmit to peer `%4s', discarding message queue.\n",
+ GNUNET_i2s (&session->target));
+#endif
+ /* timeout; cancel all messages that have already expired */
+ hd = NULL;
+ tl = NULL;
+ ret = 0;
+ now = GNUNET_TIME_absolute_get ();
+ while ((NULL != (pos = session->pending_messages_head)) &&
+ (pos->timeout.abs_value <= now.abs_value))
+ {
+ GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
+ session->pending_messages_tail, pos);
+#if DEBUG_TCP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Failed to transmit %u byte message to `%4s'.\n",
+ pos->message_size, GNUNET_i2s (&session->target));
+#endif
+ ret += pos->message_size;
+ GNUNET_CONTAINER_DLL_insert_after (hd, tl, tl, pos);
+ }
+ /* do this call before callbacks (so that if callbacks destroy
+ * session, they have a chance to cancel actions done by this
+ * call) */
+ process_pending_messages (session);
+ pid = session->target;
+ /* no do callbacks and do not use session again since
+ * the callbacks may abort the session */
+ while (NULL != (pos = hd))
+ {
+ GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
+ if (pos->transmit_cont != NULL)
+ pos->transmit_cont (pos->transmit_cont_cls, &pid, GNUNET_SYSERR);
+ GNUNET_free (pos);
+ }
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ gettext_noop ("# bytes currently in TCP buffers"),
+ -(int64_t) ret, GNUNET_NO);
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ gettext_noop
+ ("# bytes discarded by TCP (timeout)"), ret,
+ GNUNET_NO);
+ return 0;
+ }
+ /* copy all pending messages that would fit */
+ ret = 0;
+ cbuf = buf;
+ hd = NULL;
+ tl = NULL;
+ while (NULL != (pos = session->pending_messages_head))
+ {
+ if (ret + pos->message_size > size)
+ break;
+ GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
+ session->pending_messages_tail, pos);
+ GNUNET_assert (size >= pos->message_size);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Transmitting message of type %u\n",
+ ntohs (((struct GNUNET_MessageHeader *) pos->msg)->type));
+ /* FIXME: this memcpy can be up to 7% of our total runtime */
+ memcpy (cbuf, pos->msg, pos->message_size);
+ cbuf += pos->message_size;
+ ret += pos->message_size;
+ size -= pos->message_size;
+ GNUNET_CONTAINER_DLL_insert_tail (hd, tl, pos);
+ }
+ /* schedule 'continuation' before callbacks so that callbacks that
+ * cancel everything don't cause us to use a session that no longer
+ * exists... */
+ process_pending_messages (session);
+ session->last_activity = GNUNET_TIME_absolute_get ();
+ pid = session->target;
+ /* we'll now call callbacks that may cancel the session; hence
+ * we should not use 'session' after this point */
+ while (NULL != (pos = hd))
+ {
+ GNUNET_CONTAINER_DLL_remove (hd, tl, pos);
+ if (pos->transmit_cont != NULL)
+ pos->transmit_cont (pos->transmit_cont_cls, &pid, GNUNET_OK);
+ GNUNET_free (pos);
+ }
+ GNUNET_assert (hd == NULL);
+ GNUNET_assert (tl == NULL);
+#if DEBUG_TCP > 1
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Transmitting %u bytes\n",
+ ret);
+#endif
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ gettext_noop ("# bytes currently in TCP buffers"),
+ -(int64_t) ret, GNUNET_NO);
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ gettext_noop ("# bytes transmitted via TCP"), ret,
+ GNUNET_NO);
+ return ret;
+}
+
+
+/**
+ * If we have pending messages, ask the server to
+ * transmit them (schedule the respective tasks, etc.)
+ *
+ * @param session for which session should we do this
+ */
+static void
+process_pending_messages (struct Session *session)
+{
+ struct PendingMessage *pm;
+
+ GNUNET_assert (session->client != NULL);
+ if (session->transmit_handle != NULL)
+ return;
+ if (NULL == (pm = session->pending_messages_head))
+ return;
+
+ session->transmit_handle =
+ GNUNET_SERVER_notify_transmit_ready (session->client, pm->message_size,
+ GNUNET_TIME_absolute_get_remaining
+ (pm->timeout), &do_transmit,
+ session);
+}
+
+
+/**
+ * Functions with this signature are called whenever we need
+ * to close a session due to a disconnect or failure to
+ * establish a connection.
+ *
+ * @param session session to close down
+ */
+static void
+disconnect_session (struct Session *session)
+{
+ struct PendingMessage *pm;
+ struct Plugin * plugin = session->plugin;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Disconnecting session %p for peer `%s' address `%s'\n",
+ session,
+ GNUNET_i2s (&session->target),
+ tcp_address_to_string(NULL, session->addr, session->addrlen));
+
+ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove(plugin->sessionmap, &session->target.hashPubKey, session));
+
+ /* clean up state */
+ if (session->transmit_handle != NULL)
+ {
+ GNUNET_CONNECTION_notify_transmit_ready_cancel (session->transmit_handle);
+ session->transmit_handle = NULL;
+ }
+ session->plugin->env->session_end (session->plugin->env->cls,
+ &session->target, session);
+ while (NULL != (pm = session->pending_messages_head))
+ {
+#if DEBUG_TCP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ pm->transmit_cont !=
+ NULL ? "Could not deliver message to `%4s'.\n" :
+ "Could not deliver message to `%4s', notifying.\n",
+ GNUNET_i2s (&session->target));
+#endif
+ GNUNET_STATISTICS_update (session->plugin->env->stats,
+ gettext_noop ("# bytes currently in TCP buffers"),
+ -(int64_t) pm->message_size, GNUNET_NO);
+ GNUNET_STATISTICS_update (session->plugin->env->stats,
+ gettext_noop
+ ("# bytes discarded by TCP (disconnect)"),
+ pm->message_size, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (session->pending_messages_head,
+ session->pending_messages_tail, pm);
+ if (NULL != pm->transmit_cont)
+ pm->transmit_cont (pm->transmit_cont_cls, &session->target,
+ GNUNET_SYSERR);
+ GNUNET_free (pm);
+ }
+ GNUNET_break (session->client != NULL);
+ if (session->receive_delay_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (session->receive_delay_task);
+ if (session->client != NULL)
+ GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR);
+ }
+ if (session->client != NULL)
+ {
+ GNUNET_SERVER_client_drop (session->client);
+ session->client = NULL;
+ }
+ GNUNET_STATISTICS_update (session->plugin->env->stats,
+ gettext_noop ("# TCP sessions active"), -1,
+ GNUNET_NO);
+ GNUNET_free_non_null (session->addr);
+ GNUNET_assert (NULL == session->transmit_handle);
+ GNUNET_free (session);
+}
+
+
+/**
+ * Function that can be used by the transport service to transmit
+ * a message using the plugin. Note that in the case of a
+ * peer disconnecting, the continuation MUST be called
+ * prior to the disconnect notification itself. This function
+ * will be called with this peer's HELLO message to initiate
+ * a fresh connection to another peer.
+ *
+ * @param cls closure
+ * @param session which session must be used
+ * @param msgbuf the message to transmit
+ * @param msgbuf_size number of bytes in 'msgbuf'
+ * @param priority how important is the message (most plugins will
+ * ignore message priority and just FIFO)
+ * @param to how long to wait at most for the transmission (does not
+ * require plugins to discard the message after the timeout,
+ * just advisory for the desired delay; most plugins will ignore
+ * this as well)
+ * @param cont continuation to call once the message has
+ * been transmitted (or if the transport is ready
+ * for the next transmission call; or if the
+ * peer disconnected...); can be NULL
+ * @param cont_cls closure for cont
+ * @return number of bytes used (on the physical network, with overheads);
+ * -1 on hard errors (i.e. address invalid); 0 is a legal value
+ * and does NOT mean that the message was not transmitted (DV)
+ */
+static ssize_t
+tcp_plugin_send (void *cls,
+ struct Session *session,
+ const char *msgbuf, size_t msgbuf_size,
+ unsigned int priority,
+ struct GNUNET_TIME_Relative to,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct Plugin * plugin = cls;
+ struct PendingMessage *pm;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (session != NULL);
+ GNUNET_assert (session->client != NULL);
+
+ GNUNET_SERVER_client_set_timeout (session->client,
+ GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ gettext_noop ("# bytes currently in TCP buffers"),
+ msgbuf_size, GNUNET_NO);
+ /* create new message entry */
+ pm = GNUNET_malloc (sizeof (struct PendingMessage) + msgbuf_size);
+ pm->msg = (const char *) &pm[1];
+ memcpy (&pm[1], msgbuf, msgbuf_size);
+ pm->message_size = msgbuf_size;
+ pm->timeout = GNUNET_TIME_relative_to_absolute (to);
+ pm->transmit_cont = cont;
+ pm->transmit_cont_cls = cont_cls;
+
+ /* append pm to pending_messages list */
+ GNUNET_CONTAINER_DLL_insert_tail (session->pending_messages_head,
+ session->pending_messages_tail, pm);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Asked to transmit %u bytes to `%s', added message to list.\n",
+ msgbuf_size, GNUNET_i2s (&session->target));
+
+ process_pending_messages (session);
+ return msgbuf_size;
+}
+
+struct SessionItCtx
+{
+ void * addr;
+ size_t addrlen;
+ struct Session * result;
+};
+
+int session_lookup_it (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct SessionItCtx * si_ctx = cls;
+ struct Session * session = value;
+#if 0
+ char * a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen));
+ char * a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen));
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp",
+ "Comparing: %s %u <-> %s %u\n",
+ a1,
+ session->addrlen,
+ a2,
+ si_ctx->addrlen);
+ GNUNET_free (a1);
+ GNUNET_free (a2);
+#endif
+ if (session->addrlen != si_ctx->addrlen)
+ {
+ return GNUNET_YES;
+ }
+ if (0 != memcmp (session->addr, si_ctx->addr, si_ctx->addrlen))
+ {
+ return GNUNET_YES;
+ }
+#if 0
+ a1 = strdup (tcp_address_to_string(NULL, session->addr, session->addrlen));
+ a2 = strdup (tcp_address_to_string(NULL, si_ctx->addr, si_ctx->addrlen));
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp",
+ "Comparing: %s %u <-> %s %u , OK!\n",
+ a1,
+ session->addrlen,
+ a2,
+ si_ctx->addrlen);
+ GNUNET_free (a1);
+ GNUNET_free (a2);
+#endif
+ /* Found existing session */
+ si_ctx->result = session;
+ return GNUNET_NO;
+}
+
+
+/**
+ * Create a new session to transmit data to the target
+ * This session will used to send data to this peer and the plugin will
+ * notify us by calling the env->session_end function
+ *
+ * @param cls closure
+ * @param address pointer to the GNUNET_HELLO_Address
+ * @return the session if the address is valid, NULL otherwise
+ */
+static struct Session *
+tcp_plugin_get_session (void *cls,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct Plugin * plugin = cls;
+ struct Session * session = NULL;
+
+ int af;
+ const void *sb;
+ size_t sbs;
+ struct GNUNET_CONNECTION_Handle *sa;
+ struct sockaddr_in a4;
+ struct sockaddr_in6 a6;
+ const struct IPv4TcpAddress *t4;
+ const struct IPv6TcpAddress *t6;
+ struct GNUNET_ATS_Information ats;
+ unsigned int is_natd = GNUNET_NO;
+ size_t addrlen = 0;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (address != NULL);
+
+ addrlen = address->address_length;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Trying to get session for `%s' address length %i\n",
+ tcp_address_to_string(NULL, address->address, address->address_length),
+ addrlen);
+
+ /* look for existing session */
+ if (GNUNET_CONTAINER_multihashmap_contains(plugin->sessionmap, &address->peer.hashPubKey))
+ {
+ struct SessionItCtx si_ctx;
+
+ si_ctx.addr = (void *) address->address;
+ si_ctx.addrlen = address->address_length;
+
+ si_ctx.result = NULL;
+
+ GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessionmap, &address->peer.hashPubKey, &session_lookup_it, &si_ctx);
+ if (si_ctx.result != NULL)
+ {
+ session = si_ctx.result;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Found exisiting session for `%s' address `%s' session %p\n",
+ GNUNET_i2s (&address->peer),
+ tcp_address_to_string(NULL, address->address, address->address_length),
+ session);
+ return session;
+ }
+ }
+
+ if (addrlen == sizeof (struct IPv6TcpAddress))
+ {
+ GNUNET_assert (NULL != address->address); /* make static analysis happy */
+ t6 = address->address;
+ af = AF_INET6;
+ memset (&a6, 0, sizeof (a6));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ a6.sin6_len = sizeof (a6);
+#endif
+ a6.sin6_family = AF_INET6;
+ a6.sin6_port = t6->t6_port;
+ if (t6->t6_port == 0)
+ is_natd = GNUNET_YES;
+ memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr));
+ sb = &a6;
+ sbs = sizeof (a6);
+ }
+ else if (addrlen == sizeof (struct IPv4TcpAddress))
+ {
+ GNUNET_assert (NULL != address->address); /* make static analysis happy */
+ t4 = address->address;
+ af = AF_INET;
+ memset (&a4, 0, sizeof (a4));
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ a4.sin_len = sizeof (a4);
+#endif
+ a4.sin_family = AF_INET;
+ a4.sin_port = t4->t4_port;
+ if (t4->t4_port == 0)
+ is_natd = GNUNET_YES;
+ a4.sin_addr.s_addr = t4->ipv4_addr;
+ sb = &a4;
+ sbs = sizeof (a4);
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp",
+ _("Address of unexpected length: %u\n"), addrlen);
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ ats = plugin->env->get_address_type (plugin->env->cls, sb ,sbs);
+
+ if ((is_natd == GNUNET_YES) && (addrlen == sizeof (struct IPv6TcpAddress)))
+ {
+ /* NAT client only works with IPv4 addresses */
+ return NULL;
+ }
+
+ if (0 == plugin->max_connections)
+ {
+ /* saturated */
+ return NULL;
+ }
+
+ if ((is_natd == GNUNET_YES) &&
+ (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns,
+ &address->peer.hashPubKey)))
+ {
+ /* Only do one NAT punch attempt per peer identity */
+ return NULL;
+ }
+
+ if ((is_natd == GNUNET_YES) && (NULL != plugin->nat) &&
+ (GNUNET_NO ==
+ GNUNET_CONTAINER_multihashmap_contains (plugin->nat_wait_conns,
+ &address->peer.hashPubKey)))
+ {
+#if DEBUG_TCP_NAT
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ _("Found valid IPv4 NAT address (creating session)!\n"));
+#endif
+ session = create_session (plugin, &address->peer, NULL, GNUNET_YES);
+ session->addrlen = 0;
+ session->addr = NULL;
+ session->ats_address_network_type = ats.value;
+ GNUNET_assert (session != NULL);
+
+ GNUNET_assert (GNUNET_CONTAINER_multihashmap_put
+ (plugin->nat_wait_conns, &address->peer.hashPubKey, session,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY) == GNUNET_OK);
+#if DEBUG_TCP_NAT
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Created NAT WAIT connection to `%4s' at `%s'\n",
+ GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs));
+#endif
+ GNUNET_NAT_run_client (plugin->nat, &a4);
+ return session;
+ }
+
+ /* create new outbound session */
+ GNUNET_assert (0 != plugin->max_connections);
+ sa = GNUNET_CONNECTION_create_from_sockaddr (af, sb, sbs);
+ if (sa == NULL)
+ {
+#if DEBUG_TCP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Failed to create connection to `%4s' at `%s'\n",
+ GNUNET_i2s (&session->target), GNUNET_a2s (sb, sbs));
+#endif
+ return NULL;
+ }
+ plugin->max_connections--;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Asked to transmit to `%4s', creating fresh session using address `%s'.\n",
+ GNUNET_i2s (&address->peer), GNUNET_a2s (sb, sbs));
+
+ session = create_session (plugin,
+ &address->peer,
+ GNUNET_SERVER_connect_socket (plugin->server, sa),
+ GNUNET_NO);
+ session->addr = GNUNET_malloc (addrlen);
+ memcpy (session->addr, address->address, addrlen);
+ session->addrlen = addrlen;
+ session->ats_address_network_type = ats.value;
+
+ GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &address->peer.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Creating new session for `%s' address `%s' session %p\n",
+ GNUNET_i2s (&address->peer),
+ tcp_address_to_string(NULL, address->address, address->address_length),
+ session);
+
+ /* Send TCP Welcome */
+ process_pending_messages (session);
+
+ return session;
+}
+
+
+int session_disconnect_it (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct Session *session = value;
+
+ GNUNET_STATISTICS_update (session->plugin->env->stats,
+ gettext_noop
+ ("# transport-service disconnect requests for TCP"),
+ 1, GNUNET_NO);
+ disconnect_session (session);
+ return GNUNET_YES;
+}
+
+int session_nat_disconnect_it (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct Session *session = value;
+
+ if (session != NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Cleaning up pending NAT session for peer `%4s'\n", GNUNET_i2s (&session->target));
+ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (session->plugin->nat_wait_conns, &session->target.hashPubKey, session));
+ GNUNET_SERVER_client_drop (session->client);
+ GNUNET_SERVER_receive_done (session->client, GNUNET_SYSERR);
+ GNUNET_free (session);
+ }
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * Function that can be called to force a disconnect from the
+ * specified neighbour. This should also cancel all previously
+ * scheduled transmissions. Obviously the transmission may have been
+ * partially completed already, which is OK. The plugin is supposed
+ * to close the connection (if applicable) and no longer call the
+ * transmit continuation(s).
+ *
+ * Finally, plugin MUST NOT call the services's receive function to
+ * notify the service that the connection to the specified target was
+ * closed after a getting this call.
+ *
+ * @param cls closure
+ * @param target peer for which the last transmission is
+ * to be cancelled
+ */
+static void
+tcp_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
+{
+ struct Plugin *plugin = cls;
+ struct Session *nat_session = NULL;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Disconnecting peer `%4s'\n", GNUNET_i2s (target));
+
+ GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessionmap, &target->hashPubKey, session_disconnect_it, plugin);
+
+ nat_session = GNUNET_CONTAINER_multihashmap_get(plugin->nat_wait_conns, &target->hashPubKey);
+ if (nat_session != NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Cleaning up pending NAT session for peer `%4s'\n", GNUNET_i2s (target));
+ GNUNET_assert (GNUNET_YES == GNUNET_CONTAINER_multihashmap_remove (plugin->nat_wait_conns, &target->hashPubKey, nat_session));
+ GNUNET_SERVER_client_drop (nat_session->client);
+ GNUNET_SERVER_receive_done (nat_session->client, GNUNET_SYSERR);
+ GNUNET_free (nat_session);
+ }
+}
+
+
+/**
+ * Context for address to string conversion.
+ */
+struct PrettyPrinterContext
+{
+ /**
+ * Function to call with the result.
+ */
+ GNUNET_TRANSPORT_AddressStringCallback asc;
+
+ /**
+ * Clsoure for 'asc'.
+ */
+ void *asc_cls;
+
+ /**
+ * Port to add after the IP address.
+ */
+ uint16_t port;
+};
+
+
+/**
+ * Append our port and forward the result.
+ *
+ * @param cls the 'struct PrettyPrinterContext*'
+ * @param hostname hostname part of the address
+ */
+static void
+append_port (void *cls, const char *hostname)
+{
+ struct PrettyPrinterContext *ppc = cls;
+ char *ret;
+
+ if (hostname == NULL)
+ {
+ ppc->asc (ppc->asc_cls, NULL);
+ GNUNET_free (ppc);
+ return;
+ }
+ GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
+ ppc->asc (ppc->asc_cls, ret);
+ GNUNET_free (ret);
+}
+
+
+/**
+ * Convert the transports address to a nice, human-readable
+ * format.
+ *
+ * @param cls closure
+ * @param type name of the transport that generated the address
+ * @param addr one of the addresses of the host, NULL for the last address
+ * the specific address format depends on the transport
+ * @param addrlen length of the address
+ * @param numeric should (IP) addresses be displayed in numeric form?
+ * @param timeout after how long should we give up?
+ * @param asc function to call on each string
+ * @param asc_cls closure for asc
+ */
+static void
+tcp_plugin_address_pretty_printer (void *cls, const char *type,
+ const void *addr, size_t addrlen,
+ int numeric,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_AddressStringCallback asc,
+ void *asc_cls)
+{
+ struct PrettyPrinterContext *ppc;
+ const void *sb;
+ size_t sbs;
+ struct sockaddr_in a4;
+ struct sockaddr_in6 a6;
+ const struct IPv4TcpAddress *t4;
+ const struct IPv6TcpAddress *t6;
+ uint16_t port;
+
+ if (addrlen == sizeof (struct IPv6TcpAddress))
+ {
+ t6 = addr;
+ memset (&a6, 0, sizeof (a6));
+ a6.sin6_family = AF_INET6;
+ a6.sin6_port = t6->t6_port;
+ memcpy (&a6.sin6_addr, &t6->ipv6_addr, sizeof (struct in6_addr));
+ port = ntohs (t6->t6_port);
+ sb = &a6;
+ sbs = sizeof (a6);
+ }
+ else if (addrlen == sizeof (struct IPv4TcpAddress))
+ {
+ t4 = addr;
+ memset (&a4, 0, sizeof (a4));
+ a4.sin_family = AF_INET;
+ a4.sin_port = t4->t4_port;
+ a4.sin_addr.s_addr = t4->ipv4_addr;
+ port = ntohs (t4->t4_port);
+ sb = &a4;
+ sbs = sizeof (a4);
+ }
+ else
+ {
+ /* invalid address */
+ GNUNET_break_op (0);
+ asc (asc_cls, NULL);
+ return;
+ }
+ ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
+ ppc->asc = asc;
+ ppc->asc_cls = asc_cls;
+ ppc->port = port;
+ GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc);
+}
+
+
+/**
+ * Check if the given port is plausible (must be either our listen
+ * port or our advertised port), or any port if we are behind NAT
+ * and do not have a port open. If it is neither, we return
+ * GNUNET_SYSERR.
+ *
+ * @param plugin global variables
+ * @param in_port port number to check
+ * @return GNUNET_OK if port is either open_port or adv_port
+ */
+static int
+check_port (struct Plugin *plugin, uint16_t in_port)
+{
+ if ((in_port == plugin->adv_port) || (in_port == plugin->open_port))
+ return GNUNET_OK;
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Function that will be called to check if a binary address for this
+ * plugin is well-formed and corresponds to an address for THIS peer
+ * (as per our configuration). Naturally, if absolutely necessary,
+ * plugins can be a bit conservative in their answer, but in general
+ * plugins should make sure that the address does not redirect
+ * traffic to a 3rd party that might try to man-in-the-middle our
+ * traffic.
+ *
+ * @param cls closure, our 'struct Plugin*'
+ * @param addr pointer to the address
+ * @param addrlen length of addr
+ * @return GNUNET_OK if this is a plausible address for this peer
+ * and transport, GNUNET_SYSERR if not
+ */
+static int
+tcp_plugin_check_address (void *cls, const void *addr, size_t addrlen)
+{
+ struct Plugin *plugin = cls;
+ struct IPv4TcpAddress *v4;
+ struct IPv6TcpAddress *v6;
+
+ if ((addrlen != sizeof (struct IPv4TcpAddress)) &&
+ (addrlen != sizeof (struct IPv6TcpAddress)))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (addrlen == sizeof (struct IPv4TcpAddress))
+ {
+ v4 = (struct IPv4TcpAddress *) addr;
+ if (GNUNET_OK != check_port (plugin, ntohs (v4->t4_port)))
+ return GNUNET_SYSERR;
+ if (GNUNET_OK !=
+ GNUNET_NAT_test_address (plugin->nat, &v4->ipv4_addr,
+ sizeof (struct in_addr)))
+ return GNUNET_SYSERR;
+ }
+ else
+ {
+ v6 = (struct IPv6TcpAddress *) addr;
+ if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK != check_port (plugin, ntohs (v6->t6_port)))
+ return GNUNET_SYSERR;
+ if (GNUNET_OK !=
+ GNUNET_NAT_test_address (plugin->nat, &v6->ipv6_addr,
+ sizeof (struct in6_addr)))
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * We've received a nat probe from this peer via TCP. Finish
+ * creating the client session and resume sending of queued
+ * messages.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_tcp_nat_probe (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct Plugin *plugin = cls;
+ struct Session *session;
+ const struct TCP_NAT_ProbeMessage *tcp_nat_probe;
+ size_t alen;
+ void *vaddr;
+ struct IPv4TcpAddress *t4;
+ struct IPv6TcpAddress *t6;
+ const struct sockaddr_in *s4;
+ const struct sockaddr_in6 *s6;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "received NAT probe\n");
+
+ /* We have received a TCP NAT probe, meaning we (hopefully) initiated
+ * a connection to this peer by running gnunet-nat-client. This peer
+ * received the punch message and now wants us to use the new connection
+ * as the default for that peer. Do so and then send a WELCOME message
+ * so we can really be connected!
+ */
+ if (ntohs (message->size) != sizeof (struct TCP_NAT_ProbeMessage))
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ tcp_nat_probe = (const struct TCP_NAT_ProbeMessage *) message;
+ if (0 ==
+ memcmp (&tcp_nat_probe->clientIdentity, plugin->env->my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ /* refuse connections from ourselves */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ session =
+ GNUNET_CONTAINER_multihashmap_get (plugin->nat_wait_conns,
+ &tcp_nat_probe->
+ clientIdentity.hashPubKey);
+ if (session == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Did NOT find session for NAT probe!\n");
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Found session for NAT probe!\n");
+
+ GNUNET_assert (GNUNET_CONTAINER_multihashmap_remove
+ (plugin->nat_wait_conns,
+ &tcp_nat_probe->clientIdentity.hashPubKey,
+ session) == GNUNET_YES);
+ if (GNUNET_OK != GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
+ {
+ GNUNET_break (0);
+ GNUNET_free (session);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+
+ GNUNET_SERVER_client_keep (client);
+ session->client = client;
+ session->last_activity = GNUNET_TIME_absolute_get ();
+ session->inbound = GNUNET_NO;
+
+#if DEBUG_TCP_NAT
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Found address `%s' for incoming connection\n",
+ GNUNET_a2s (vaddr, alen));
+#endif
+ switch (((const struct sockaddr *) vaddr)->sa_family)
+ {
+ case AF_INET:
+ s4 = vaddr;
+ t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
+ t4->t4_port = s4->sin_port;
+ t4->ipv4_addr = s4->sin_addr.s_addr;
+ session->addr = t4;
+ session->addrlen = sizeof (struct IPv4TcpAddress);
+ break;
+ case AF_INET6:
+ s6 = vaddr;
+ t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress));
+ t6->t6_port = s6->sin6_port;
+ memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr));
+ session->addr = t6;
+ session->addrlen = sizeof (struct IPv6TcpAddress);
+ break;
+ default:
+ GNUNET_break_op (0);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Bad address for incoming connection!\n");
+ GNUNET_free (vaddr);
+
+ GNUNET_SERVER_client_drop (client);
+ GNUNET_free (session);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ GNUNET_free (vaddr);
+
+ GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &session->target.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ gettext_noop ("# TCP sessions active"), 1,
+ GNUNET_NO);
+ process_pending_messages (session);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * We've received a welcome from this peer via TCP. Possibly create a
+ * fresh client record and send back our welcome.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_tcp_welcome (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct Plugin *plugin = cls;
+ const struct WelcomeMessage *wm = (const struct WelcomeMessage *) message;
+ struct Session *session;
+ size_t alen;
+ void *vaddr;
+ struct IPv4TcpAddress *t4;
+ struct IPv6TcpAddress *t6;
+ const struct sockaddr_in *s4;
+ const struct sockaddr_in6 *s6;
+
+ if (0 ==
+ memcmp (&wm->clientIdentity, plugin->env->my_identity,
+ sizeof (struct GNUNET_PeerIdentity)))
+ {
+ /* refuse connections from ourselves */
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Received %s message from `%4s'\n", "WELCOME",
+ GNUNET_i2s (&wm->clientIdentity));
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ gettext_noop ("# TCP WELCOME messages received"), 1,
+ GNUNET_NO);
+
+ session = lookup_session_by_client (plugin, client);
+ if (session != NULL)
+ {
+ if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Found existing session %p for peer `%s'\n",
+ session,
+ GNUNET_a2s (vaddr, alen));
+ GNUNET_free (vaddr);
+ }
+ }
+ else
+ {
+ GNUNET_SERVER_client_keep (client);
+ session = create_session (plugin, &wm->clientIdentity, client, GNUNET_NO);
+ session->inbound = GNUNET_YES;
+
+ if (GNUNET_OK == GNUNET_SERVER_client_get_address (client, &vaddr, &alen))
+ {
+ if (alen == sizeof (struct sockaddr_in))
+ {
+ s4 = vaddr;
+ t4 = GNUNET_malloc (sizeof (struct IPv4TcpAddress));
+ t4->t4_port = s4->sin_port;
+ t4->ipv4_addr = s4->sin_addr.s_addr;
+ session->addr = t4;
+ session->addrlen = sizeof (struct IPv4TcpAddress);
+ }
+ else if (alen == sizeof (struct sockaddr_in6))
+ {
+ s6 = vaddr;
+ t6 = GNUNET_malloc (sizeof (struct IPv6TcpAddress));
+ t6->t6_port = s6->sin6_port;
+ memcpy (&t6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr));
+ session->addr = t6;
+ session->addrlen = sizeof (struct IPv6TcpAddress);
+ }
+
+ struct GNUNET_ATS_Information ats;
+ ats = plugin->env->get_address_type (plugin->env->cls, vaddr ,alen);
+ session->ats_address_network_type = ats.value;
+
+ GNUNET_free (vaddr);
+ }
+ else
+ {
+#if DEBUG_TCP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Did not obtain TCP socket address for incoming connection\n");
+#endif
+ }
+ GNUNET_CONTAINER_multihashmap_put(plugin->sessionmap, &wm->clientIdentity.hashPubKey, session, GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+ }
+
+ if (session->expecting_welcome != GNUNET_YES)
+ {
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ session->last_activity = GNUNET_TIME_absolute_get ();
+ session->expecting_welcome = GNUNET_NO;
+
+
+ process_pending_messages (session);
+
+ GNUNET_SERVER_client_set_timeout (client,
+ GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT);
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+}
+
+
+/**
+ * Task to signal the server that we can continue
+ * receiving from the TCP client now.
+ *
+ * @param cls the 'struct Session*'
+ * @param tc task context (unused)
+ */
+static void
+delayed_done (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Session *session = cls;
+ struct GNUNET_TIME_Relative delay;
+ struct GNUNET_ATS_Information ats;
+
+ session->receive_delay_task = GNUNET_SCHEDULER_NO_TASK;
+ delay =
+ session->plugin->env->receive (session->plugin->env->cls,
+ &session->target, NULL, &ats, 0, session,
+ NULL, 0);
+ if (delay.rel_value == 0)
+ GNUNET_SERVER_receive_done (session->client, GNUNET_OK);
+ else
+ session->receive_delay_task =
+ GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
+}
+
+
+/**
+ * We've received data for this peer via TCP. Unbox,
+ * compute latency and forward.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ * @param message the actual message
+ */
+static void
+handle_tcp_data (void *cls, struct GNUNET_SERVER_Client *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct Plugin *plugin = cls;
+ struct Session *session;
+ struct GNUNET_TIME_Relative delay;
+ uint16_t type;
+
+ type = ntohs (message->type);
+ if ((GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME == type) ||
+ (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE == type))
+ {
+ /* We don't want to propagate WELCOME and NAT Probe messages up! */
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ return;
+ }
+ session = lookup_session_by_client (plugin, client);
+ if (NULL == session)
+ {
+ /* No inbound session found */
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+ else if (GNUNET_YES == session->expecting_welcome)
+ {
+ /* Session is expecting WELCOME message */
+ GNUNET_break_op (0);
+ GNUNET_SERVER_receive_done (client, GNUNET_SYSERR);
+ return;
+ }
+
+ session->last_activity = GNUNET_TIME_absolute_get ();
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Passing %u bytes of type %u from `%4s' to transport service.\n",
+ (unsigned int) ntohs (message->size),
+ (unsigned int) ntohs (message->type),
+ GNUNET_i2s (&session->target));
+
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ gettext_noop ("# bytes received via TCP"),
+ ntohs (message->size), GNUNET_NO);
+ struct GNUNET_ATS_Information distance[2];
+
+ distance[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
+ distance[0].value = htonl (1);
+ distance[1].type = htonl (GNUNET_ATS_NETWORK_TYPE);
+ distance[1].value = session->ats_address_network_type;
+ GNUNET_break (ntohl(session->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED);
+
+ delay = plugin->env->receive (plugin->env->cls,
+ &session->target,
+ message,
+ (const struct GNUNET_ATS_Information *) &distance,
+ 1, session,
+ (GNUNET_YES == session->inbound) ? NULL : session->addr,
+ (GNUNET_YES == session->inbound) ? 0 : session->addrlen);
+ if (delay.rel_value == 0)
+ {
+ GNUNET_SERVER_receive_done (client, GNUNET_OK);
+ }
+ else
+ {
+#if DEBUG_TCP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Throttling receiving from `%s' for %llu ms\n",
+ GNUNET_i2s (&session->target),
+ (unsigned long long) delay.rel_value);
+#endif
+ GNUNET_SERVER_disable_receive_done_warning (client);
+ session->receive_delay_task =
+ GNUNET_SCHEDULER_add_delayed (delay, &delayed_done, session);
+ }
+}
+
+
+/**
+ * Functions with this signature are called whenever a peer
+ * is disconnected on the network level.
+ *
+ * @param cls closure
+ * @param client identification of the client
+ */
+static void
+disconnect_notify (void *cls, struct GNUNET_SERVER_Client *client)
+{
+ struct Plugin *plugin = cls;
+ struct Session *session;
+
+ if (client == NULL)
+ return;
+ plugin->max_connections++;
+ session = lookup_session_by_client (plugin, client);
+ if (session == NULL)
+ return; /* unknown, nothing to do */
+#if DEBUG_TCP
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp",
+ "Destroying session of `%4s' with %s due to network-level disconnect.\n",
+ GNUNET_i2s (&session->target),
+ (session->addr !=
+ NULL) ? tcp_address_to_string (session->plugin,
+ session->addr,
+ session->addrlen) :
+ "*");
+#endif
+ GNUNET_STATISTICS_update (session->plugin->env->stats,
+ gettext_noop
+ ("# network-level TCP disconnect events"), 1,
+ GNUNET_NO);
+ disconnect_session (session);
+}
+
+
+/**
+ * We can now send a probe message, copy into buffer to really send.
+ *
+ * @param cls closure, a struct TCPProbeContext
+ * @param size max size to copy
+ * @param buf buffer to copy message to
+ * @return number of bytes copied into buf
+ */
+static size_t
+notify_send_probe (void *cls, size_t size, void *buf)
+{
+ struct TCPProbeContext *tcp_probe_ctx = cls;
+ struct Plugin *plugin = tcp_probe_ctx->plugin;
+ size_t ret;
+
+ tcp_probe_ctx->transmit_handle = NULL;
+ GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail,
+ tcp_probe_ctx);
+ if (buf == NULL)
+ {
+ GNUNET_CONNECTION_destroy (tcp_probe_ctx->sock, GNUNET_NO);
+ GNUNET_free (tcp_probe_ctx);
+ return 0;
+ }
+ GNUNET_assert (size >= sizeof (tcp_probe_ctx->message));
+ memcpy (buf, &tcp_probe_ctx->message, sizeof (tcp_probe_ctx->message));
+ GNUNET_SERVER_connect_socket (tcp_probe_ctx->plugin->server,
+ tcp_probe_ctx->sock);
+ ret = sizeof (tcp_probe_ctx->message);
+ GNUNET_free (tcp_probe_ctx);
+ return ret;
+}
+
+
+/**
+ * Function called by the NAT subsystem suggesting another peer wants
+ * to connect to us via connection reversal. Try to connect back to the
+ * given IP.
+ *
+ * @param cls closure
+ * @param addr address to try
+ * @param addrlen number of bytes in addr
+ */
+static void
+try_connection_reversal (void *cls, const struct sockaddr *addr,
+ socklen_t addrlen)
+{
+ struct Plugin *plugin = cls;
+ struct GNUNET_CONNECTION_Handle *sock;
+ struct TCPProbeContext *tcp_probe_ctx;
+
+ /**
+ * We have received an ICMP response, ostensibly from a peer
+ * that wants to connect to us! Send a message to establish a connection.
+ */
+ sock = GNUNET_CONNECTION_create_from_sockaddr (AF_INET, addr, addrlen);
+ if (sock == NULL)
+ {
+ /* failed for some odd reason (out of sockets?); ignore attempt */
+ return;
+ }
+
+ /* FIXME: do we need to track these probe context objects so that
+ * we can clean them up on plugin unload? */
+ tcp_probe_ctx = GNUNET_malloc (sizeof (struct TCPProbeContext));
+ tcp_probe_ctx->message.header.size =
+ htons (sizeof (struct TCP_NAT_ProbeMessage));
+ tcp_probe_ctx->message.header.type =
+ htons (GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE);
+ memcpy (&tcp_probe_ctx->message.clientIdentity, plugin->env->my_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ tcp_probe_ctx->plugin = plugin;
+ tcp_probe_ctx->sock = sock;
+ GNUNET_CONTAINER_DLL_insert (plugin->probe_head, plugin->probe_tail,
+ tcp_probe_ctx);
+ tcp_probe_ctx->transmit_handle =
+ GNUNET_CONNECTION_notify_transmit_ready (sock,
+ ntohs (tcp_probe_ctx->
+ message.header.size),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ &notify_send_probe,
+ tcp_probe_ctx);
+
+}
+
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
+ * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
+ */
+void *
+libgnunet_plugin_transport_tcp_init (void *cls)
+{
+ static const struct GNUNET_SERVER_MessageHandler my_handlers[] = {
+ {&handle_tcp_welcome, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_WELCOME,
+ sizeof (struct WelcomeMessage)},
+ {&handle_tcp_nat_probe, NULL, GNUNET_MESSAGE_TYPE_TRANSPORT_TCP_NAT_PROBE,
+ sizeof (struct TCP_NAT_ProbeMessage)},
+ {&handle_tcp_data, NULL, GNUNET_MESSAGE_TYPE_ALL, 0},
+ {NULL, NULL, 0, 0}
+ };
+ struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
+ struct GNUNET_TRANSPORT_PluginFunctions *api;
+ struct Plugin *plugin;
+ struct GNUNET_SERVICE_Context *service;
+ unsigned long long aport;
+ unsigned long long bport;
+ unsigned long long max_connections;
+ unsigned int i;
+ struct GNUNET_TIME_Relative idle_timeout;
+ int ret;
+ struct sockaddr **addrs;
+ socklen_t *addrlens;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
+ "MAX_CONNECTIONS",
+ &max_connections))
+ max_connections = 128;
+
+ aport = 0;
+ if ((GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp", "PORT",
+ &bport)) || (bport > 65535) ||
+ ((GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-tcp",
+ "ADVERTISED-PORT", &aport)) &&
+ (aport > 65535)))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp",
+ _
+ ("Require valid port number for service `%s' in configuration!\n"),
+ "transport-tcp");
+ return NULL;
+ }
+ if (aport == 0)
+ aport = bport;
+ if (bport == 0)
+ aport = 0;
+ if (bport != 0)
+ {
+ service = GNUNET_SERVICE_start ("transport-tcp", env->cfg);
+ if (service == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, "tcp",
+ _("Failed to start service.\n"));
+ return NULL;
+ }
+ }
+ else
+ service = NULL;
+
+
+
+ plugin = GNUNET_malloc (sizeof (struct Plugin));
+ plugin->sessionmap = GNUNET_CONTAINER_multihashmap_create(max_connections);
+ plugin->max_connections = max_connections;
+ plugin->open_port = bport;
+ plugin->adv_port = aport;
+ plugin->env = env;
+ plugin->lsock = NULL;
+ if ((service != NULL) &&
+ (GNUNET_SYSERR !=
+ (ret =
+ GNUNET_SERVICE_get_server_addresses ("transport-tcp", env->cfg, &addrs,
+ &addrlens))))
+ {
+ plugin->nat =
+ GNUNET_NAT_register (env->cfg, GNUNET_YES, aport, (unsigned int) ret,
+ (const struct sockaddr **) addrs, addrlens,
+ &tcp_nat_port_map_callback,
+ &try_connection_reversal, plugin);
+ while (ret > 0)
+ {
+ ret--;
+ GNUNET_assert (addrs[ret] != NULL);
+ GNUNET_free (addrs[ret]);
+ }
+ GNUNET_free_non_null (addrs);
+ GNUNET_free_non_null (addrlens);
+ }
+ else
+ {
+ plugin->nat =
+ GNUNET_NAT_register (env->cfg, GNUNET_YES, 0, 0, NULL, NULL, NULL,
+ &try_connection_reversal, plugin);
+ }
+ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
+ api->cls = plugin;
+ api->send = &tcp_plugin_send;
+ api->get_session = &tcp_plugin_get_session;
+
+ api->disconnect = &tcp_plugin_disconnect;
+ api->address_pretty_printer = &tcp_plugin_address_pretty_printer;
+ api->check_address = &tcp_plugin_check_address;
+ api->address_to_string = &tcp_address_to_string;
+ plugin->service = service;
+ if (service != NULL)
+ {
+ plugin->server = GNUNET_SERVICE_get_server (service);
+ }
+ else
+ {
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_time (env->cfg, "transport-tcp",
+ "TIMEOUT", &idle_timeout))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "tcp",
+ _("Failed to find option %s in section %s!\n"),
+ "TIMEOUT", "transport-tcp");
+ if (plugin->nat != NULL)
+ GNUNET_NAT_unregister (plugin->nat);
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+ return NULL;
+ }
+ plugin->server =
+ GNUNET_SERVER_create_with_sockets (&plugin_tcp_access_check, plugin,
+ NULL, idle_timeout, GNUNET_YES);
+ }
+ plugin->handlers = GNUNET_malloc (sizeof (my_handlers));
+ memcpy (plugin->handlers, my_handlers, sizeof (my_handlers));
+ for (i = 0;
+ i < sizeof (my_handlers) / sizeof (struct GNUNET_SERVER_MessageHandler);
+ i++)
+ plugin->handlers[i].callback_cls = plugin;
+ GNUNET_SERVER_add_handlers (plugin->server, plugin->handlers);
+ GNUNET_SERVER_disconnect_notify (plugin->server, &disconnect_notify, plugin);
+ plugin->nat_wait_conns = GNUNET_CONTAINER_multihashmap_create (16);
+ if (bport != 0)
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp",
+ _("TCP transport listening on port %llu\n"), bport);
+ else
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp",
+ _
+ ("TCP transport not listening on any port (client only)\n"));
+ if (aport != bport)
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, "tcp",
+ _
+ ("TCP transport advertises itself as being on port %llu\n"),
+ aport);
+ return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ */
+void *
+libgnunet_plugin_transport_tcp_done (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
+ struct Plugin *plugin = api->cls;
+ struct TCPProbeContext *tcp_probe;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "tcp", "Shutting down TCP plugin\n");
+
+
+ /* Removing leftover sessions */
+ GNUNET_CONTAINER_multihashmap_iterate(plugin->sessionmap, &session_disconnect_it, NULL);
+ /* Removing leftover NAT sessions */
+ GNUNET_CONTAINER_multihashmap_iterate(plugin->nat_wait_conns, &session_nat_disconnect_it, NULL);
+
+ if (plugin->service != NULL)
+ GNUNET_SERVICE_stop (plugin->service);
+ else
+ GNUNET_SERVER_destroy (plugin->server);
+ GNUNET_free (plugin->handlers);
+ if (plugin->nat != NULL)
+ GNUNET_NAT_unregister (plugin->nat);
+ while (NULL != (tcp_probe = plugin->probe_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (plugin->probe_head, plugin->probe_tail,
+ tcp_probe);
+ GNUNET_CONNECTION_destroy (tcp_probe->sock, GNUNET_NO);
+ GNUNET_free (tcp_probe);
+ }
+ GNUNET_CONTAINER_multihashmap_destroy (plugin->nat_wait_conns);
+ GNUNET_CONTAINER_multihashmap_destroy (plugin->sessionmap);
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+ return NULL;
+}
+
+/* end of plugin_transport_tcp.c */
diff --git a/src/transport/plugin_transport_template.c b/src/transport/plugin_transport_template.c
new file mode 100644
index 0000000..d307262
--- /dev/null
+++ b/src/transport/plugin_transport_template.c
@@ -0,0 +1,299 @@
+/*
+ This file is part of GNUnet
+ (C) 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_template.c
+ * @brief template for a new transport service
+ * @author Christian Grothoff
+ */
+
+#include "platform.h"
+#include "gnunet_protocols.h"
+#include "gnunet_connection_lib.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_service_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_transport_plugin.h"
+
+#define DEBUG_TEMPLATE GNUNET_EXTRA_LOGGING
+
+/**
+ * After how long do we expire an address that we
+ * learned from another peer if it is not reconfirmed
+ * by anyone?
+ */
+#define LEARNED_ADDRESS_EXPIRATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 6)
+
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin;
+
+
+/**
+ * Session handle for connections.
+ */
+struct Session
+{
+
+ /**
+ * Stored in a linked list.
+ */
+ struct Session *next;
+
+ /**
+ * Pointer to the global plugin struct.
+ */
+ struct Plugin *plugin;
+
+ /**
+ * The client (used to identify this connection)
+ */
+ /* void *client; */
+
+ /**
+ * Continuation function to call once the transmission buffer
+ * has again space available. NULL if there is no
+ * continuation to call.
+ */
+ GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
+
+ /**
+ * Closure for transmit_cont.
+ */
+ void *transmit_cont_cls;
+
+ /**
+ * To whom are we talking to (set to our identity
+ * if we are still waiting for the welcome message)
+ */
+ struct GNUNET_PeerIdentity sender;
+
+ /**
+ * At what time did we reset last_received last?
+ */
+ struct GNUNET_TIME_Absolute last_quota_update;
+
+ /**
+ * How many bytes have we received since the "last_quota_update"
+ * timestamp?
+ */
+ uint64_t last_received;
+
+ /**
+ * Number of bytes per ms that this peer is allowed
+ * to send to us.
+ */
+ uint32_t quota;
+
+};
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin
+{
+ /**
+ * Our environment.
+ */
+ struct GNUNET_TRANSPORT_PluginEnvironment *env;
+
+ /**
+ * List of open sessions.
+ */
+ struct Session *sessions;
+
+};
+
+
+/**
+ * Function that can be used by the transport service to transmit
+ * a message using the plugin. Note that in the case of a
+ * peer disconnecting, the continuation MUST be called
+ * prior to the disconnect notification itself. This function
+ * will be called with this peer's HELLO message to initiate
+ * a fresh connection to another peer.
+ *
+ * @param cls closure
+ * @param session which session must be used
+ * @param msgbuf the message to transmit
+ * @param msgbuf_size number of bytes in 'msgbuf'
+ * @param priority how important is the message (most plugins will
+ * ignore message priority and just FIFO)
+ * @param to how long to wait at most for the transmission (does not
+ * require plugins to discard the message after the timeout,
+ * just advisory for the desired delay; most plugins will ignore
+ * this as well)
+ * @param cont continuation to call once the message has
+ * been transmitted (or if the transport is ready
+ * for the next transmission call; or if the
+ * peer disconnected...); can be NULL
+ * @param cont_cls closure for cont
+ * @return number of bytes used (on the physical network, with overheads);
+ * -1 on hard errors (i.e. address invalid); 0 is a legal value
+ * and does NOT mean that the message was not transmitted (DV)
+ */
+static ssize_t
+template_plugin_send (void *cls,
+ struct Session *session,
+ const char *msgbuf, size_t msgbuf_size,
+ unsigned int priority,
+ struct GNUNET_TIME_Relative to,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct Plugin *plugin = cls;
+ int bytes_sent = 0;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (session != NULL);
+
+ /* struct Plugin *plugin = cls; */
+ return bytes_sent;
+}
+
+
+
+/**
+ * Function that can be used to force the plugin to disconnect
+ * from the given peer and cancel all previous transmissions
+ * (and their continuationc).
+ *
+ * @param cls closure
+ * @param target peer from which to disconnect
+ */
+static void
+template_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
+{
+ // struct Plugin *plugin = cls;
+ // FIXME
+}
+
+
+/**
+ * Convert the transports address to a nice, human-readable
+ * format.
+ *
+ * @param cls closure
+ * @param type name of the transport that generated the address
+ * @param addr one of the addresses of the host, NULL for the last address
+ * the specific address format depends on the transport
+ * @param addrlen length of the address
+ * @param numeric should (IP) addresses be displayed in numeric form?
+ * @param timeout after how long should we give up?
+ * @param asc function to call on each string
+ * @param asc_cls closure for asc
+ */
+static void
+template_plugin_address_pretty_printer (void *cls, const char *type,
+ const void *addr, size_t addrlen,
+ int numeric,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_AddressStringCallback
+ asc, void *asc_cls)
+{
+ asc (asc_cls, NULL);
+}
+
+
+
+/**
+ * Another peer has suggested an address for this
+ * peer and transport plugin. Check that this could be a valid
+ * address. If so, consider adding it to the list
+ * of addresses.
+ *
+ * @param cls closure
+ * @param addr pointer to the address
+ * @param addrlen length of addr
+ * @return GNUNET_OK if this is a plausible address for this peer
+ * and transport
+ */
+static int
+template_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
+{
+ /* struct Plugin *plugin = cls; */
+
+ /* check if the address is plausible; if so,
+ * add it to our list! */
+ return GNUNET_OK;
+}
+
+
+/**
+ * Function called for a quick conversion of the binary address to
+ * a numeric address. Note that the caller must not free the
+ * address and that the next call to this function is allowed
+ * to override the address again.
+ *
+ * @param cls closure
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return string representing the same address
+ */
+static const char *
+template_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
+{
+ GNUNET_break (0);
+ return NULL;
+}
+
+
+
+
+/**
+ * Entry point for the plugin.
+ */
+void *
+gnunet_plugin_transport_template_init (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
+ struct GNUNET_TRANSPORT_PluginFunctions *api;
+ struct Plugin *plugin;
+
+ plugin = GNUNET_malloc (sizeof (struct Plugin));
+ plugin->env = env;
+ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
+ api->cls = plugin;
+ api->send = &template_plugin_send;
+ api->disconnect = &template_plugin_disconnect;
+ api->address_pretty_printer = &template_plugin_address_pretty_printer;
+ api->check_address = &template_plugin_address_suggested;
+ api->address_to_string = &template_plugin_address_to_string;
+ return api;
+}
+
+
+/**
+ * Exit point from the plugin.
+ */
+void *
+gnunet_plugin_transport_template_done (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
+ struct Plugin *plugin = api->cls;
+
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+ return NULL;
+}
+
+/* end of plugin_transport_template.c */
diff --git a/src/transport/plugin_transport_udp.c b/src/transport/plugin_transport_udp.c
new file mode 100644
index 0000000..7141563
--- /dev/null
+++ b/src/transport/plugin_transport_udp.c
@@ -0,0 +1,2297 @@
+/*
+ This file is part of GNUnet
+ (C) 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_udp.c
+ * @brief Implementation of the UDP transport protocol
+ * @author Christian Grothoff
+ * @author Nathan Evans
+ * @author Matthias Wachs
+ */
+#include "platform.h"
+#include "plugin_transport_udp.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_fragmentation_lib.h"
+#include "gnunet_nat_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_signatures.h"
+#include "gnunet_constants.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_transport_plugin.h"
+#include "transport.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__)
+
+
+/**
+ * Number of messages we can defragment in parallel. We only really
+ * defragment 1 message at a time, but if messages get re-ordered, we
+ * may want to keep knowledge about the previous message to avoid
+ * discarding the current message in favor of a single fragment of a
+ * previous message. 3 should be good since we don't expect massive
+ * message reorderings with UDP.
+ */
+#define UDP_MAX_MESSAGES_IN_DEFRAG 3
+
+/**
+ * We keep a defragmentation queue per sender address. How many
+ * sender addresses do we support at the same time? Memory consumption
+ * is roughly a factor of 32k * UDP_MAX_MESSAGES_IN_DEFRAG times this
+ * value. (So 128 corresponds to 12 MB and should suffice for
+ * connecting to roughly 128 peers via UDP).
+ */
+#define UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG 128
+
+
+
+/**
+ * Closure for 'append_port'.
+ */
+struct PrettyPrinterContext
+{
+ /**
+ * Function to call with the result.
+ */
+ GNUNET_TRANSPORT_AddressStringCallback asc;
+
+ /**
+ * Clsoure for 'asc'.
+ */
+ void *asc_cls;
+
+ /**
+ * Port to add after the IP address.
+ */
+ uint16_t port;
+};
+
+struct Session
+{
+ /**
+ * Which peer is this session for?
+ */
+ struct GNUNET_PeerIdentity target;
+
+ /**
+ * Address of the other peer
+ */
+ const struct sockaddr *sock_addr;
+
+ size_t addrlen;
+
+ /**
+ * Desired delay for next sending we send to other peer
+ */
+ struct GNUNET_TIME_Relative flow_delay_for_other_peer;
+
+ /**
+ * Desired delay for next sending we received from other peer
+ */
+ struct GNUNET_TIME_Absolute flow_delay_from_other_peer;
+
+ /**
+ * expected delay for ACKs
+ */
+ struct GNUNET_TIME_Relative last_expected_delay;
+
+
+ struct GNUNET_ATS_Information ats;
+
+ struct FragmentationContext * frag_ctx;
+};
+
+
+struct SessionCompareContext
+{
+ struct Session *res;
+ const struct GNUNET_HELLO_Address *addr;
+};
+
+
+/**
+ * Closure for 'process_inbound_tokenized_messages'
+ */
+struct SourceInformation
+{
+ /**
+ * Sender identity.
+ */
+ struct GNUNET_PeerIdentity sender;
+
+ /**
+ * Source address.
+ */
+ const void *arg;
+
+ /**
+ * Number of bytes in source address.
+ */
+ size_t args;
+
+ struct Session *session;
+};
+
+
+/**
+ * Closure for 'find_receive_context'.
+ */
+struct FindReceiveContext
+{
+ /**
+ * Where to store the result.
+ */
+ struct DefragContext *rc;
+
+ /**
+ * Address to find.
+ */
+ const struct sockaddr *addr;
+
+ /**
+ * Number of bytes in 'addr'.
+ */
+ socklen_t addr_len;
+
+ struct Session *session;
+};
+
+
+
+/**
+ * Data structure to track defragmentation contexts based
+ * on the source of the UDP traffic.
+ */
+struct DefragContext
+{
+
+ /**
+ * Defragmentation context.
+ */
+ struct GNUNET_DEFRAGMENT_Context *defrag;
+
+ /**
+ * Source address this receive context is for (allocated at the
+ * end of the struct).
+ */
+ const struct sockaddr *src_addr;
+
+ /**
+ * Reference to master plugin struct.
+ */
+ struct Plugin *plugin;
+
+ /**
+ * Node in the defrag heap.
+ */
+ struct GNUNET_CONTAINER_HeapNode *hnode;
+
+ /**
+ * Length of 'src_addr'
+ */
+ size_t addr_len;
+};
+
+
+
+/**
+ * Closure for 'process_inbound_tokenized_messages'
+ */
+struct FragmentationContext
+{
+ struct FragmentationContext * next;
+ struct FragmentationContext * prev;
+
+ struct Plugin * plugin;
+ struct GNUNET_FRAGMENT_Context * frag;
+ struct Session * session;
+
+ struct GNUNET_TIME_Absolute timeout;
+
+
+ /**
+ * Function to call upon completion of the transmission.
+ */
+ GNUNET_TRANSPORT_TransmitContinuation cont;
+
+ /**
+ * Closure for 'cont'.
+ */
+ void *cont_cls;
+
+ size_t bytes_to_send;
+};
+
+
+struct UDPMessageWrapper
+{
+ struct Session *session;
+ struct UDPMessageWrapper *prev;
+ struct UDPMessageWrapper *next;
+ char *udp;
+ size_t msg_size;
+
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * Function to call upon completion of the transmission.
+ */
+ GNUNET_TRANSPORT_TransmitContinuation cont;
+
+ /**
+ * Closure for 'cont'.
+ */
+ void *cont_cls;
+
+ struct FragmentationContext *frag_ctx;
+
+};
+
+
+/**
+ * UDP ACK Message-Packet header (after defragmentation).
+ */
+struct UDP_ACK_Message
+{
+ /**
+ * Message header.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Desired delay for flow control
+ */
+ uint32_t delay;
+
+ /**
+ * What is the identity of the sender
+ */
+ struct GNUNET_PeerIdentity sender;
+
+};
+
+/**
+ * We have been notified that our readset has something to read. We don't
+ * know which socket needs to be read, so we have to check each one
+ * Then reschedule this function to be called again once more is available.
+ *
+ * @param cls the plugin handle
+ * @param tc the scheduling context (for rescheduling this function again)
+ */
+static void
+udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+ * We have been notified that our readset has something to read. We don't
+ * know which socket needs to be read, so we have to check each one
+ * Then reschedule this function to be called again once more is available.
+ *
+ * @param cls the plugin handle
+ * @param tc the scheduling context (for rescheduling this function again)
+ */
+static void
+udp_plugin_select_v6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+ * Function called for a quick conversion of the binary address to
+ * a numeric address. Note that the caller must not free the
+ * address and that the next call to this function is allowed
+ * to override the address again.
+ *
+ * @param cls closure
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return string representing the same address
+ */
+const char *
+udp_address_to_string (void *cls, const void *addr, size_t addrlen)
+{
+ static char rbuf[INET6_ADDRSTRLEN + 10];
+ char buf[INET6_ADDRSTRLEN];
+ const void *sb;
+ struct in_addr a4;
+ struct in6_addr a6;
+ const struct IPv4UdpAddress *t4;
+ const struct IPv6UdpAddress *t6;
+ int af;
+ uint16_t port;
+
+ if (addrlen == sizeof (struct IPv6UdpAddress))
+ {
+ t6 = addr;
+ af = AF_INET6;
+ port = ntohs (t6->u6_port);
+ memcpy (&a6, &t6->ipv6_addr, sizeof (a6));
+ sb = &a6;
+ }
+ else if (addrlen == sizeof (struct IPv4UdpAddress))
+ {
+ t4 = addr;
+ af = AF_INET;
+ port = ntohs (t4->u4_port);
+ memcpy (&a4, &t4->ipv4_addr, sizeof (a4));
+ sb = &a4;
+ }
+ else
+ {
+ GNUNET_break_op (0);
+ return NULL;
+ }
+ inet_ntop (af, sb, buf, INET6_ADDRSTRLEN);
+ GNUNET_snprintf (rbuf, sizeof (rbuf), (af == AF_INET6) ? "[%s]:%u" : "%s:%u",
+ buf, port);
+ return rbuf;
+}
+
+
+/**
+ * Append our port and forward the result.
+ *
+ * @param cls a 'struct PrettyPrinterContext'
+ * @param hostname result from DNS resolver
+ */
+static void
+append_port (void *cls, const char *hostname)
+{
+ struct PrettyPrinterContext *ppc = cls;
+ char *ret;
+
+ if (hostname == NULL)
+ {
+ ppc->asc (ppc->asc_cls, NULL);
+ GNUNET_free (ppc);
+ return;
+ }
+ GNUNET_asprintf (&ret, "%s:%d", hostname, ppc->port);
+ ppc->asc (ppc->asc_cls, ret);
+ GNUNET_free (ret);
+}
+
+
+/**
+ * Convert the transports address to a nice, human-readable
+ * format.
+ *
+ * @param cls closure
+ * @param type name of the transport that generated the address
+ * @param addr one of the addresses of the host, NULL for the last address
+ * the specific address format depends on the transport
+ * @param addrlen length of the address
+ * @param numeric should (IP) addresses be displayed in numeric form?
+ * @param timeout after how long should we give up?
+ * @param asc function to call on each string
+ * @param asc_cls closure for asc
+ */
+static void
+udp_plugin_address_pretty_printer (void *cls, const char *type,
+ const void *addr, size_t addrlen,
+ int numeric,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_AddressStringCallback asc,
+ void *asc_cls)
+{
+ struct PrettyPrinterContext *ppc;
+ const void *sb;
+ size_t sbs;
+ struct sockaddr_in a4;
+ struct sockaddr_in6 a6;
+ const struct IPv4UdpAddress *u4;
+ const struct IPv6UdpAddress *u6;
+ uint16_t port;
+
+ if (addrlen == sizeof (struct IPv6UdpAddress))
+ {
+ u6 = addr;
+ memset (&a6, 0, sizeof (a6));
+ a6.sin6_family = AF_INET6;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ a6.sin6_len = sizeof (a6);
+#endif
+ a6.sin6_port = u6->u6_port;
+ memcpy (&a6.sin6_addr, &u6->ipv6_addr, sizeof (struct in6_addr));
+ port = ntohs (u6->u6_port);
+ sb = &a6;
+ sbs = sizeof (a6);
+ }
+ else if (addrlen == sizeof (struct IPv4UdpAddress))
+ {
+ u4 = addr;
+ memset (&a4, 0, sizeof (a4));
+ a4.sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ a4.sin_len = sizeof (a4);
+#endif
+ a4.sin_port = u4->u4_port;
+ a4.sin_addr.s_addr = u4->ipv4_addr;
+ port = ntohs (u4->u4_port);
+ sb = &a4;
+ sbs = sizeof (a4);
+ }
+ else
+ {
+ /* invalid address */
+ GNUNET_break_op (0);
+ asc (asc_cls, NULL);
+ return;
+ }
+ ppc = GNUNET_malloc (sizeof (struct PrettyPrinterContext));
+ ppc->asc = asc;
+ ppc->asc_cls = asc_cls;
+ ppc->port = port;
+ GNUNET_RESOLVER_hostname_get (sb, sbs, !numeric, timeout, &append_port, ppc);
+}
+
+
+/**
+ * Check if the given port is plausible (must be either our listen
+ * port or our advertised port). If it is neither, we return
+ * GNUNET_SYSERR.
+ *
+ * @param plugin global variables
+ * @param in_port port number to check
+ * @return GNUNET_OK if port is either open_port or adv_port
+ */
+static int
+check_port (struct Plugin *plugin, uint16_t in_port)
+{
+ if ((in_port == plugin->port) || (in_port == plugin->aport))
+ return GNUNET_OK;
+ return GNUNET_SYSERR;
+}
+
+
+
+/**
+ * Function that will be called to check if a binary address for this
+ * plugin is well-formed and corresponds to an address for THIS peer
+ * (as per our configuration). Naturally, if absolutely necessary,
+ * plugins can be a bit conservative in their answer, but in general
+ * plugins should make sure that the address does not redirect
+ * traffic to a 3rd party that might try to man-in-the-middle our
+ * traffic.
+ *
+ * @param cls closure, should be our handle to the Plugin
+ * @param addr pointer to the address
+ * @param addrlen length of addr
+ * @return GNUNET_OK if this is a plausible address for this peer
+ * and transport, GNUNET_SYSERR if not
+ *
+ */
+static int
+udp_plugin_check_address (void *cls, const void *addr, size_t addrlen)
+{
+ struct Plugin *plugin = cls;
+ struct IPv4UdpAddress *v4;
+ struct IPv6UdpAddress *v6;
+
+ if ((addrlen != sizeof (struct IPv4UdpAddress)) &&
+ (addrlen != sizeof (struct IPv6UdpAddress)))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (addrlen == sizeof (struct IPv4UdpAddress))
+ {
+ v4 = (struct IPv4UdpAddress *) addr;
+ if (GNUNET_OK != check_port (plugin, ntohs (v4->u4_port)))
+ return GNUNET_SYSERR;
+ if (GNUNET_OK !=
+ GNUNET_NAT_test_address (plugin->nat, &v4->ipv4_addr,
+ sizeof (struct in_addr)))
+ return GNUNET_SYSERR;
+ }
+ else
+ {
+ v6 = (struct IPv6UdpAddress *) addr;
+ if (IN6_IS_ADDR_LINKLOCAL (&v6->ipv6_addr))
+ {
+ GNUNET_break_op (0);
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_OK != check_port (plugin, ntohs (v6->u6_port)))
+ return GNUNET_SYSERR;
+ if (GNUNET_OK !=
+ GNUNET_NAT_test_address (plugin->nat, &v6->ipv6_addr,
+ sizeof (struct in6_addr)))
+ return GNUNET_SYSERR;
+ }
+ return GNUNET_OK;
+}
+
+
+/**
+ * Destroy a session, plugin is being unloaded.
+ *
+ * @param cls unused
+ * @param key hash of public key of target peer
+ * @param value a 'struct PeerSession*' to clean up
+ * @return GNUNET_OK (continue to iterate)
+ */
+static int
+disconnect_and_free_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct Plugin *plugin = cls;
+ struct Session *s = value;
+ struct UDPMessageWrapper *udpw;
+ struct UDPMessageWrapper *next;
+
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Session %p to peer `%s' address ended \n",
+ s,
+ GNUNET_i2s (&s->target),
+ GNUNET_a2s (s->sock_addr, s->addrlen));
+#endif
+
+ if (s->frag_ctx != NULL)
+ {
+ GNUNET_FRAGMENT_context_destroy(s->frag_ctx->frag);
+ GNUNET_free (s->frag_ctx);
+ s->frag_ctx = NULL;
+ }
+
+ udpw = plugin->ipv4_queue_head;
+ while (udpw != NULL)
+ {
+ next = udpw->next;
+ if (udpw->session == s)
+ {
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw);
+
+ if (udpw->cont != NULL)
+ udpw->cont (udpw->cont_cls, &s->target, GNUNET_SYSERR);
+ GNUNET_free (udpw);
+ }
+ udpw = next;
+ }
+
+ udpw = plugin->ipv6_queue_head;
+ while (udpw != NULL)
+ {
+ next = udpw->next;
+ if (udpw->session == s)
+ {
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw);
+
+ if (udpw->cont != NULL)
+ udpw->cont (udpw->cont_cls, &s->target, GNUNET_SYSERR);
+ GNUNET_free (udpw);
+ }
+ udpw = next;
+ }
+
+ plugin->env->session_end (plugin->env->cls, &s->target, s);
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (plugin->sessions,
+ &s->target.hashPubKey,
+ s));
+
+
+ GNUNET_free (s);
+ return GNUNET_OK;
+}
+
+
+/**
+ * Disconnect from a remote node. Clean up session if we have one for this peer
+ *
+ * @param cls closure for this call (should be handle to Plugin)
+ * @param target the peeridentity of the peer to disconnect
+ * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
+ */
+static void
+udp_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
+{
+ struct Plugin *plugin = cls;
+ GNUNET_assert (plugin != NULL);
+
+ GNUNET_assert (target != NULL);
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Disconnecting from peer `%s'\n", GNUNET_i2s (target));
+#endif
+ /* Clean up sessions */
+ GNUNET_CONTAINER_multihashmap_get_multiple (plugin->sessions, &target->hashPubKey, &disconnect_and_free_it, plugin);
+}
+
+static struct Session *
+create_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *target,
+ const void *addr, size_t addrlen,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct Session *s;
+ const struct IPv4UdpAddress *t4;
+ const struct IPv6UdpAddress *t6;
+ struct sockaddr_in *v4;
+ struct sockaddr_in6 *v6;
+ size_t len;
+
+ switch (addrlen)
+ {
+ case sizeof (struct IPv4UdpAddress):
+ if (NULL == plugin->sockv4)
+ {
+ return NULL;
+ }
+ t4 = addr;
+ s = GNUNET_malloc (sizeof (struct Session) + sizeof (struct sockaddr_in));
+ len = sizeof (struct sockaddr_in);
+ v4 = (struct sockaddr_in *) &s[1];
+ v4->sin_family = AF_INET;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ v4->sin_len = sizeof (struct sockaddr_in);
+#endif
+ v4->sin_port = t4->u4_port;
+ v4->sin_addr.s_addr = t4->ipv4_addr;
+ s->ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) v4, sizeof (struct sockaddr_in));
+ break;
+ case sizeof (struct IPv6UdpAddress):
+ if (NULL == plugin->sockv6)
+ {
+ return NULL;
+ }
+ t6 = addr;
+ s =
+ GNUNET_malloc (sizeof (struct Session) + sizeof (struct sockaddr_in6));
+ len = sizeof (struct sockaddr_in6);
+ v6 = (struct sockaddr_in6 *) &s[1];
+ v6->sin6_family = AF_INET6;
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ v6->sin6_len = sizeof (struct sockaddr_in6);
+#endif
+ v6->sin6_port = t6->u6_port;
+ v6->sin6_addr = t6->ipv6_addr;
+ s->ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) v6, sizeof (struct sockaddr_in6));
+ break;
+ default:
+ /* Must have a valid address to send to */
+ GNUNET_break_op (0);
+ return NULL;
+ }
+
+ s->addrlen = len;
+ s->target = *target;
+ s->sock_addr = (const struct sockaddr *) &s[1];
+ s->flow_delay_for_other_peer = GNUNET_TIME_relative_get_zero();
+ s->flow_delay_from_other_peer = GNUNET_TIME_absolute_get_zero();
+ s->last_expected_delay = GNUNET_TIME_UNIT_SECONDS;
+
+ return s;
+}
+
+static int session_cmp_it (void *cls,
+ const GNUNET_HashCode * key,
+ void *value)
+{
+ struct SessionCompareContext * cctx = cls;
+ const struct GNUNET_HELLO_Address *address = cctx->addr;
+ struct Session *s = value;
+
+ socklen_t s_addrlen = s->addrlen;
+
+#if VERBOSE_UDP
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing address %s <-> %s\n",
+ udp_address_to_string (NULL, (void *) address->address, address->address_length),
+ GNUNET_a2s (s->sock_addr, s->addrlen));
+#endif
+
+ if ((address->address_length == sizeof (struct IPv4UdpAddress)) &&
+ (s_addrlen == sizeof (struct sockaddr_in)))
+ {
+ struct IPv4UdpAddress * u4 = NULL;
+ u4 = (struct IPv4UdpAddress *) address->address;
+ const struct sockaddr_in *s4 = (const struct sockaddr_in *) s->sock_addr;
+ if ((0 == memcmp ((const void *) &u4->ipv4_addr,(const void *) &s4->sin_addr, sizeof (struct in_addr))) &&
+ (u4->u4_port == s4->sin_port))
+ {
+ cctx->res = s;
+ return GNUNET_NO;
+ }
+
+ }
+ if ((address->address_length == sizeof (struct IPv6UdpAddress)) &&
+ (s_addrlen == sizeof (struct sockaddr_in6)))
+ {
+ struct IPv6UdpAddress * u6 = NULL;
+ u6 = (struct IPv6UdpAddress *) address->address;
+ const struct sockaddr_in6 *s6 = (const struct sockaddr_in6 *) s->sock_addr;
+ if ((0 == memcmp (&u6->ipv6_addr, &s6->sin6_addr, sizeof (struct in6_addr))) &&
+ (u6->u6_port == s6->sin6_port))
+ {
+ cctx->res = s;
+ return GNUNET_NO;
+ }
+ }
+
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * Creates a new outbound session the transport service will use to send data to the
+ * peer
+ *
+ * @param cls the plugin
+ * @param address the address
+ * @return the session or NULL of max connections exceeded
+ */
+static struct Session *
+udp_plugin_get_session (void *cls,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct Session * s = NULL;
+ struct Plugin * plugin = cls;
+ struct IPv6UdpAddress * udp_a6;
+ struct IPv4UdpAddress * udp_a4;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (address != NULL);
+
+
+ if ((address->address == NULL) ||
+ ((address->address_length != sizeof (struct IPv4UdpAddress)) &&
+ (address->address_length != sizeof (struct IPv6UdpAddress))))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ if (address->address_length == sizeof (struct IPv4UdpAddress))
+ {
+ if (plugin->sockv4 == NULL)
+ return NULL;
+ udp_a4 = (struct IPv4UdpAddress *) address->address;
+ if (udp_a4->u4_port == 0)
+ return NULL;
+ }
+
+ if (address->address_length == sizeof (struct IPv6UdpAddress))
+ {
+ if (plugin->sockv6 == NULL)
+ return NULL;
+ udp_a6 = (struct IPv6UdpAddress *) address->address;
+ if (udp_a6->u6_port == 0)
+ return NULL;
+ }
+
+ /* check if session already exists */
+ struct SessionCompareContext cctx;
+ cctx.addr = address;
+ cctx.res = NULL;
+#if VERBOSE_UDP
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Looking for existing session for peer `%s' `%s' \n", GNUNET_i2s (&address->peer), udp_address_to_string(NULL, address->address, address->address_length));
+#endif
+ GNUNET_CONTAINER_multihashmap_get_multiple(plugin->sessions, &address->peer.hashPubKey, session_cmp_it, &cctx);
+ if (cctx.res != NULL)
+ {
+#if VERBOSE_UDP
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found existing session %p\n", cctx.res);
+#endif
+ return cctx.res;
+ }
+
+ /* otherwise create new */
+ s = create_session (plugin,
+ &address->peer,
+ address->address,
+ address->address_length,
+ NULL, NULL);
+#if VERBOSE
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Creating new session %p for peer `%s' address `%s'\n",
+ s,
+ GNUNET_i2s(&address->peer),
+ udp_address_to_string(NULL,address->address,address->address_length));
+#endif
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (plugin->sessions,
+ &s->target.hashPubKey,
+ s,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE));
+
+ return s;
+}
+
+static void enqueue (struct Plugin *plugin, struct UDPMessageWrapper * udpw)
+{
+
+ if (udpw->session->addrlen == sizeof (struct sockaddr_in))
+ GNUNET_CONTAINER_DLL_insert(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw);
+ if (udpw->session->addrlen == sizeof (struct sockaddr_in6))
+ GNUNET_CONTAINER_DLL_insert(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw);
+}
+
+/**
+ * Function that is called with messages created by the fragmentation
+ * module. In the case of the 'proc' callback of the
+ * GNUNET_FRAGMENT_context_create function, this function must
+ * eventually call 'GNUNET_FRAGMENT_context_transmission_done'.
+ *
+ * @param cls closure, the 'struct FragmentationContext'
+ * @param msg the message that was created
+ */
+static void
+enqueue_fragment (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct FragmentationContext *frag_ctx = cls;
+ struct Plugin *plugin = frag_ctx->plugin;
+ struct UDPMessageWrapper * udpw;
+ struct Session *s;
+
+ size_t msg_len = ntohs (msg->size);
+
+#if VERBOSE_UDP
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Enqueuing fragment with %u bytes %u\n", msg_len , sizeof (struct UDPMessageWrapper));
+#endif
+
+ udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + msg_len);
+ udpw->session = frag_ctx->session;
+ s = udpw->session;
+ udpw->udp = (char *) &udpw[1];
+
+ udpw->msg_size = msg_len;
+ udpw->cont = frag_ctx->cont;
+ udpw->cont_cls = frag_ctx->cont_cls;
+ udpw->timeout = frag_ctx->timeout;
+ udpw->frag_ctx = frag_ctx;
+ memcpy (udpw->udp, msg, msg_len);
+
+ enqueue (plugin, udpw);
+
+
+ if (s->addrlen == sizeof (struct sockaddr_in))
+ {
+ if (plugin->with_v4_ws == GNUNET_NO)
+ {
+ if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel(plugin->select_task);
+
+ plugin->select_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs_v4,
+ plugin->ws_v4,
+ &udp_plugin_select, plugin);
+ plugin->with_v4_ws = GNUNET_YES;
+ }
+ }
+
+ else if (s->addrlen == sizeof (struct sockaddr_in6))
+ {
+ if (plugin->with_v6_ws == GNUNET_NO)
+ {
+ if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel(plugin->select_task_v6);
+
+ plugin->select_task_v6 =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs_v6,
+ plugin->ws_v6,
+ &udp_plugin_select_v6, plugin);
+ plugin->with_v6_ws = GNUNET_YES;
+ }
+ }
+
+}
+
+
+
+
+/**
+ * Function that can be used by the transport service to transmit
+ * a message using the plugin. Note that in the case of a
+ * peer disconnecting, the continuation MUST be called
+ * prior to the disconnect notification itself. This function
+ * will be called with this peer's HELLO message to initiate
+ * a fresh connection to another peer.
+ *
+ * @param cls closure
+ * @param s which session must be used
+ * @param msgbuf the message to transmit
+ * @param msgbuf_size number of bytes in 'msgbuf'
+ * @param priority how important is the message (most plugins will
+ * ignore message priority and just FIFO)
+ * @param to how long to wait at most for the transmission (does not
+ * require plugins to discard the message after the timeout,
+ * just advisory for the desired delay; most plugins will ignore
+ * this as well)
+ * @param cont continuation to call once the message has
+ * been transmitted (or if the transport is ready
+ * for the next transmission call; or if the
+ * peer disconnected...); can be NULL
+ * @param cont_cls closure for cont
+ * @return number of bytes used (on the physical network, with overheads);
+ * -1 on hard errors (i.e. address invalid); 0 is a legal value
+ * and does NOT mean that the message was not transmitted (DV)
+ */
+static ssize_t
+udp_plugin_send (void *cls,
+ struct Session *s,
+ const char *msgbuf, size_t msgbuf_size,
+ unsigned int priority,
+ struct GNUNET_TIME_Relative to,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct Plugin *plugin = cls;
+ size_t mlen = msgbuf_size + sizeof (struct UDPMessage);
+
+ struct UDPMessageWrapper * udpw;
+ struct UDPMessage *udp;
+ char mbuf[mlen];
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (s != NULL);
+
+ if ((s->addrlen == sizeof (struct sockaddr_in6)) && (plugin->sockv6 == NULL))
+ return GNUNET_SYSERR;
+
+ if ((s->addrlen == sizeof (struct sockaddr_in)) && (plugin->sockv4 == NULL))
+ return GNUNET_SYSERR;
+
+
+ if (mlen >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ if (GNUNET_YES != GNUNET_CONTAINER_multihashmap_contains_value(plugin->sessions, &s->target.hashPubKey, s))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "UDP transmits %u-byte message to `%s' using address `%s'\n",
+ msgbuf_size,
+ GNUNET_i2s (&s->target),
+ GNUNET_a2s(s->sock_addr, s->addrlen));
+
+ /* Message */
+ udp = (struct UDPMessage *) mbuf;
+ udp->header.size = htons (mlen);
+ udp->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE);
+ udp->reserved = htonl (0);
+ udp->sender = *plugin->env->my_identity;
+
+ if (mlen <= UDP_MTU)
+ {
+ udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + mlen);
+ udpw->session = s;
+ udpw->udp = (char *) &udpw[1];
+ udpw->msg_size = mlen;
+ udpw->timeout = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), to);
+ udpw->cont = cont;
+ udpw->cont_cls = cont_cls;
+ udpw->frag_ctx = NULL;
+
+ memcpy (udpw->udp, udp, sizeof (struct UDPMessage));
+ memcpy (&udpw->udp[sizeof (struct UDPMessage)], msgbuf, msgbuf_size);
+
+ enqueue (plugin, udpw);
+ }
+ else
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "UDP has to fragment message \n");
+ if (s->frag_ctx != NULL)
+ return GNUNET_SYSERR;
+ memcpy (&udp[1], msgbuf, msgbuf_size);
+ struct FragmentationContext * frag_ctx = GNUNET_malloc(sizeof (struct FragmentationContext));
+
+ frag_ctx->plugin = plugin;
+ frag_ctx->session = s;
+ frag_ctx->cont = cont;
+ frag_ctx->cont_cls = cont_cls;
+ frag_ctx->timeout = GNUNET_TIME_absolute_add(GNUNET_TIME_absolute_get(), to);
+ frag_ctx->bytes_to_send = mlen;
+ frag_ctx->frag = GNUNET_FRAGMENT_context_create (plugin->env->stats,
+ UDP_MTU,
+ &plugin->tracker,
+ s->last_expected_delay,
+ &udp->header,
+ &enqueue_fragment,
+ frag_ctx);
+
+ s->frag_ctx = frag_ctx;
+
+ }
+
+ if (s->addrlen == sizeof (struct sockaddr_in))
+ {
+ if (plugin->with_v4_ws == GNUNET_NO)
+ {
+ if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel(plugin->select_task);
+
+ plugin->select_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs_v4,
+ plugin->ws_v4,
+ &udp_plugin_select, plugin);
+ plugin->with_v4_ws = GNUNET_YES;
+ }
+ }
+
+ else if (s->addrlen == sizeof (struct sockaddr_in6))
+ {
+ if (plugin->with_v6_ws == GNUNET_NO)
+ {
+ if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel(plugin->select_task_v6);
+
+ plugin->select_task_v6 =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs_v6,
+ plugin->ws_v6,
+ &udp_plugin_select_v6, plugin);
+ plugin->with_v6_ws = GNUNET_YES;
+ }
+ }
+
+ return mlen;
+}
+
+
+/**
+ * Our external IP address/port mapping has changed.
+ *
+ * @param cls closure, the 'struct LocalAddrList'
+ * @param add_remove GNUNET_YES to mean the new public IP address, GNUNET_NO to mean
+ * the previous (now invalid) one
+ * @param addr either the previous or the new public IP address
+ * @param addrlen actual lenght of the address
+ */
+static void
+udp_nat_port_map_callback (void *cls, int add_remove,
+ const struct sockaddr *addr, socklen_t addrlen)
+{
+ struct Plugin *plugin = cls;
+ struct IPv4UdpAddress u4;
+ struct IPv6UdpAddress u6;
+ void *arg;
+ size_t args;
+
+ /* convert 'addr' to our internal format */
+ switch (addr->sa_family)
+ {
+ case AF_INET:
+ GNUNET_assert (addrlen == sizeof (struct sockaddr_in));
+ u4.ipv4_addr = ((struct sockaddr_in *) addr)->sin_addr.s_addr;
+ u4.u4_port = ((struct sockaddr_in *) addr)->sin_port;
+ arg = &u4;
+ args = sizeof (u4);
+ break;
+ case AF_INET6:
+ GNUNET_assert (addrlen == sizeof (struct sockaddr_in6));
+ memcpy (&u6.ipv6_addr, &((struct sockaddr_in6 *) addr)->sin6_addr,
+ sizeof (struct in6_addr));
+ u6.u6_port = ((struct sockaddr_in6 *) addr)->sin6_port;
+ arg = &u6;
+ args = sizeof (u6);
+ break;
+ default:
+ GNUNET_break (0);
+ return;
+ }
+ /* modify our published address list */
+ plugin->env->notify_address (plugin->env->cls, add_remove, arg, args);
+}
+
+
+
+/**
+ * Message tokenizer has broken up an incomming message. Pass it on
+ * to the service.
+ *
+ * @param cls the 'struct Plugin'
+ * @param client the 'struct SourceInformation'
+ * @param hdr the actual message
+ */
+static void
+process_inbound_tokenized_messages (void *cls, void *client,
+ const struct GNUNET_MessageHeader *hdr)
+{
+ struct Plugin *plugin = cls;
+ struct SourceInformation *si = client;
+ struct GNUNET_ATS_Information ats[2];
+ struct GNUNET_TIME_Relative delay;
+
+ GNUNET_assert (si->session != NULL);
+ /* setup ATS */
+ ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
+ ats[0].value = htonl (1);
+ ats[1] = si->session->ats;
+ GNUNET_break (ntohl(ats[1].value) != GNUNET_ATS_NET_UNSPECIFIED);
+
+ delay = plugin->env->receive (plugin->env->cls,
+ &si->sender,
+ hdr,
+ (const struct GNUNET_ATS_Information *) &ats, 2,
+ NULL,
+ si->arg,
+ si->args);
+ si->session->flow_delay_for_other_peer = delay;
+}
+
+
+/**
+ * We've received a UDP Message. Process it (pass contents to main service).
+ *
+ * @param plugin plugin context
+ * @param msg the message
+ * @param sender_addr sender address
+ * @param sender_addr_len number of bytes in sender_addr
+ */
+static void
+process_udp_message (struct Plugin *plugin, const struct UDPMessage *msg,
+ const struct sockaddr *sender_addr,
+ socklen_t sender_addr_len)
+{
+ struct SourceInformation si;
+ struct Session * s = NULL;
+ struct IPv4UdpAddress u4;
+ struct IPv6UdpAddress u6;
+ const void *arg;
+ size_t args;
+
+ if (0 != ntohl (msg->reserved))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ if (ntohs (msg->header.size) <
+ sizeof (struct GNUNET_MessageHeader) + sizeof (struct UDPMessage))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+
+ /* convert address */
+ switch (sender_addr->sa_family)
+ {
+ case AF_INET:
+ GNUNET_assert (sender_addr_len == sizeof (struct sockaddr_in));
+ u4.ipv4_addr = ((struct sockaddr_in *) sender_addr)->sin_addr.s_addr;
+ u4.u4_port = ((struct sockaddr_in *) sender_addr)->sin_port;
+ arg = &u4;
+ args = sizeof (u4);
+ break;
+ case AF_INET6:
+ GNUNET_assert (sender_addr_len == sizeof (struct sockaddr_in6));
+ u6.ipv6_addr = ((struct sockaddr_in6 *) sender_addr)->sin6_addr;
+ u6.u6_port = ((struct sockaddr_in6 *) sender_addr)->sin6_port;
+ arg = &u6;
+ args = sizeof (u6);
+ break;
+ default:
+ GNUNET_break (0);
+ return;
+ }
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received message with %u bytes from peer `%s' at `%s'\n",
+ (unsigned int) ntohs (msg->header.size), GNUNET_i2s (&msg->sender),
+ GNUNET_a2s (sender_addr, sender_addr_len));
+#endif
+
+ struct GNUNET_HELLO_Address * address = GNUNET_HELLO_address_allocate(&msg->sender, "udp", arg, args);
+ s = udp_plugin_get_session(plugin, address);
+ GNUNET_free (address);
+
+ /* iterate over all embedded messages */
+ si.session = s;
+ si.sender = msg->sender;
+ si.arg = arg;
+ si.args = args;
+
+ GNUNET_SERVER_mst_receive (plugin->mst, &si, (const char *) &msg[1],
+ ntohs (msg->header.size) -
+ sizeof (struct UDPMessage), GNUNET_YES, GNUNET_NO);
+}
+
+
+/**
+ * Scan the heap for a receive context with the given address.
+ *
+ * @param cls the 'struct FindReceiveContext'
+ * @param node internal node of the heap
+ * @param element value stored at the node (a 'struct ReceiveContext')
+ * @param cost cost associated with the node
+ * @return GNUNET_YES if we should continue to iterate,
+ * GNUNET_NO if not.
+ */
+static int
+find_receive_context (void *cls, struct GNUNET_CONTAINER_HeapNode *node,
+ void *element, GNUNET_CONTAINER_HeapCostType cost)
+{
+ struct FindReceiveContext *frc = cls;
+ struct DefragContext *e = element;
+
+ if ((frc->addr_len == e->addr_len) &&
+ (0 == memcmp (frc->addr, e->src_addr, frc->addr_len)))
+ {
+ frc->rc = e;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+
+/**
+ * Process a defragmented message.
+ *
+ * @param cls the 'struct ReceiveContext'
+ * @param msg the message
+ */
+static void
+fragment_msg_proc (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct DefragContext *rc = cls;
+
+ if (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE)
+ {
+ GNUNET_break (0);
+ return;
+ }
+ if (ntohs (msg->size) < sizeof (struct UDPMessage))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ process_udp_message (rc->plugin, (const struct UDPMessage *) msg,
+ rc->src_addr, rc->addr_len);
+}
+
+struct LookupContext
+{
+ const struct sockaddr * addr;
+ size_t addrlen;
+
+ struct Session *res;
+};
+
+static int
+lookup_session_by_addr_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct LookupContext *l_ctx = cls;
+ struct Session * s = value;
+
+ if ((s->addrlen == l_ctx->addrlen) &&
+ (0 == memcmp (s->sock_addr, l_ctx->addr, s->addrlen)))
+ {
+ l_ctx->res = s;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+/**
+ * Transmit an acknowledgement.
+ *
+ * @param cls the 'struct ReceiveContext'
+ * @param id message ID (unused)
+ * @param msg ack to transmit
+ */
+static void
+ack_proc (void *cls, uint32_t id, const struct GNUNET_MessageHeader *msg)
+{
+ struct DefragContext *rc = cls;
+
+ size_t msize = sizeof (struct UDP_ACK_Message) + ntohs (msg->size);
+ struct UDP_ACK_Message *udp_ack;
+ uint32_t delay = 0;
+ struct UDPMessageWrapper *udpw;
+ struct Session *s;
+
+ struct LookupContext l_ctx;
+ l_ctx.addr = rc->src_addr;
+ l_ctx.addrlen = rc->addr_len;
+ l_ctx.res = NULL;
+ GNUNET_CONTAINER_multihashmap_iterate (rc->plugin->sessions,
+ &lookup_session_by_addr_it,
+ &l_ctx);
+ s = l_ctx.res;
+
+ GNUNET_assert (s != NULL);
+
+ if (s->flow_delay_for_other_peer.rel_value <= UINT32_MAX)
+ delay = s->flow_delay_for_other_peer.rel_value;
+
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending ACK to `%s' including delay of %u ms\n",
+ GNUNET_a2s (rc->src_addr,
+ (rc->src_addr->sa_family ==
+ AF_INET) ? sizeof (struct sockaddr_in) : sizeof (struct
+ sockaddr_in6)),
+ delay);
+#endif
+ udpw = GNUNET_malloc (sizeof (struct UDPMessageWrapper) + msize);
+ udpw->cont = NULL;
+ udpw->cont_cls = NULL;
+ udpw->frag_ctx = NULL;
+ udpw->msg_size = msize;
+ udpw->session = s;
+ udpw->timeout = GNUNET_TIME_absolute_get_forever();
+ udpw->udp = (char *)&udpw[1];
+
+ udp_ack = (struct UDP_ACK_Message *) udpw->udp;
+ udp_ack->header.size = htons ((uint16_t) msize);
+ udp_ack->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK);
+ udp_ack->delay = htonl (delay);
+ udp_ack->sender = *rc->plugin->env->my_identity;
+ memcpy (&udp_ack[1], msg, ntohs (msg->size));
+
+ enqueue (rc->plugin, udpw);
+}
+
+
+static void read_process_msg (struct Plugin *plugin,
+ const struct GNUNET_MessageHeader *msg,
+ char *addr,
+ socklen_t fromlen)
+{
+ if (ntohs (msg->size) < sizeof (struct UDPMessage))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ process_udp_message (plugin, (const struct UDPMessage *) msg,
+ (const struct sockaddr *) addr, fromlen);
+ return;
+}
+
+static void read_process_ack (struct Plugin *plugin,
+ const struct GNUNET_MessageHeader *msg,
+ char *addr,
+ socklen_t fromlen)
+{
+ const struct GNUNET_MessageHeader *ack;
+ const struct UDP_ACK_Message *udp_ack;
+ struct LookupContext l_ctx;
+ struct Session *s = NULL;
+ struct GNUNET_TIME_Relative flow_delay;
+
+ if (ntohs (msg->size) <
+ sizeof (struct UDP_ACK_Message) + sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+
+ udp_ack = (const struct UDP_ACK_Message *) msg;
+
+ l_ctx.addr = (const struct sockaddr *) addr;
+ l_ctx.addrlen = fromlen;
+ l_ctx.res = NULL;
+ GNUNET_CONTAINER_multihashmap_iterate (plugin->sessions,
+ &lookup_session_by_addr_it,
+ &l_ctx);
+ s = l_ctx.res;
+
+ if ((s == NULL) || (s->frag_ctx == NULL))
+ return;
+
+ flow_delay.rel_value = (uint64_t) ntohl (udp_ack->delay);
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "We received a sending delay of %llu\n",
+ flow_delay.rel_value);
+ s->flow_delay_from_other_peer =
+ GNUNET_TIME_relative_to_absolute (flow_delay);
+
+ ack = (const struct GNUNET_MessageHeader *) &udp_ack[1];
+ if (ntohs (ack->size) !=
+ ntohs (msg->size) - sizeof (struct UDP_ACK_Message))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+
+ if (GNUNET_OK != GNUNET_FRAGMENT_process_ack (s->frag_ctx->frag, ack))
+ {
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "UDP processes %u-byte acknowledgement from `%s' at `%s'\n",
+ (unsigned int) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender),
+ GNUNET_a2s ((const struct sockaddr *) addr, fromlen));
+#endif
+ return;
+ }
+
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "FULL MESSAGE ACKed\n",
+ (unsigned int) ntohs (msg->size), GNUNET_i2s (&udp_ack->sender),
+ GNUNET_a2s ((const struct sockaddr *) addr, fromlen));
+#endif
+ s->last_expected_delay = GNUNET_FRAGMENT_context_destroy (s->frag_ctx->frag);
+
+ struct UDPMessageWrapper * udpw = NULL;
+ if (s->addrlen == sizeof (struct sockaddr_in6))
+ {
+ udpw = plugin->ipv6_queue_head;
+ while (udpw!= NULL)
+ {
+ if ((udpw->frag_ctx != NULL) && (udpw->frag_ctx == s->frag_ctx))
+ {
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw);
+ GNUNET_free (udpw);
+ }
+ udpw = udpw->next;
+ }
+ }
+ if (s->addrlen == sizeof (struct sockaddr_in))
+ {
+ udpw = plugin->ipv4_queue_head;
+ while (udpw!= NULL)
+ {
+ if ((udpw->frag_ctx != NULL) && (udpw->frag_ctx == s->frag_ctx))
+ {
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw);
+ GNUNET_free (udpw);
+ }
+ udpw = udpw->next;
+ }
+ }
+
+ if (s->frag_ctx->cont != NULL)
+ s->frag_ctx->cont
+ (s->frag_ctx->cont_cls, &udp_ack->sender, GNUNET_OK);
+ GNUNET_free (s->frag_ctx);
+ s->frag_ctx = NULL;
+ return;
+}
+
+static void read_process_fragment (struct Plugin *plugin,
+ const struct GNUNET_MessageHeader *msg,
+ char *addr,
+ socklen_t fromlen)
+{
+ struct DefragContext *d_ctx;
+ struct GNUNET_TIME_Absolute now;
+ struct FindReceiveContext frc;
+
+
+ frc.rc = NULL;
+ frc.addr = (const struct sockaddr *) addr;
+ frc.addr_len = fromlen;
+
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "UDP processes %u-byte fragment from `%s'\n",
+ (unsigned int) ntohs (msg->size),
+ GNUNET_a2s ((const struct sockaddr *) addr, fromlen));
+#endif
+
+ /* Lookup existing receive context for this address */
+ GNUNET_CONTAINER_heap_iterate (plugin->defrag_ctxs,
+ &find_receive_context,
+ &frc);
+ now = GNUNET_TIME_absolute_get ();
+ d_ctx = frc.rc;
+
+ if (d_ctx == NULL)
+ {
+ /* Create a new defragmentation context */
+ d_ctx = GNUNET_malloc (sizeof (struct DefragContext) + fromlen);
+ memcpy (&d_ctx[1], addr, fromlen);
+ d_ctx->src_addr = (const struct sockaddr *) &d_ctx[1];
+ d_ctx->addr_len = fromlen;
+ d_ctx->plugin = plugin;
+ d_ctx->defrag =
+ GNUNET_DEFRAGMENT_context_create (plugin->env->stats, UDP_MTU,
+ UDP_MAX_MESSAGES_IN_DEFRAG, d_ctx,
+ &fragment_msg_proc, &ack_proc);
+ d_ctx->hnode =
+ GNUNET_CONTAINER_heap_insert (plugin->defrag_ctxs, d_ctx,
+ (GNUNET_CONTAINER_HeapCostType)
+ now.abs_value);
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Created new defragmentation context for %u-byte fragment from `%s'\n",
+ (unsigned int) ntohs (msg->size),
+ GNUNET_a2s ((const struct sockaddr *) addr, fromlen));
+#endif
+ }
+ else
+ {
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Found existing defragmentation context for %u-byte fragment from `%s'\n",
+ (unsigned int) ntohs (msg->size),
+ GNUNET_a2s ((const struct sockaddr *) addr, fromlen));
+#endif
+ }
+
+ if (GNUNET_OK == GNUNET_DEFRAGMENT_process_fragment (d_ctx->defrag, msg))
+ {
+ /* keep this 'rc' from expiring */
+ GNUNET_CONTAINER_heap_update_cost (plugin->defrag_ctxs, d_ctx->hnode,
+ (GNUNET_CONTAINER_HeapCostType)
+ now.abs_value);
+ }
+ if (GNUNET_CONTAINER_heap_get_size (plugin->defrag_ctxs) >
+ UDP_MAX_SENDER_ADDRESSES_WITH_DEFRAG)
+ {
+ /* remove 'rc' that was inactive the longest */
+ d_ctx = GNUNET_CONTAINER_heap_remove_root (plugin->defrag_ctxs);
+ GNUNET_assert (NULL != d_ctx);
+ GNUNET_DEFRAGMENT_context_destroy (d_ctx->defrag);
+ GNUNET_free (d_ctx);
+ }
+}
+
+/**
+ * Read and process a message from the given socket.
+ *
+ * @param plugin the overall plugin
+ * @param rsock socket to read from
+ */
+static void
+udp_select_read (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *rsock)
+{
+ socklen_t fromlen;
+ char addr[32];
+ char buf[65536];
+ ssize_t size;
+ const struct GNUNET_MessageHeader *msg;
+
+ fromlen = sizeof (addr);
+ memset (&addr, 0, sizeof (addr));
+ size = GNUNET_NETWORK_socket_recvfrom (rsock, buf, sizeof (buf),
+ (struct sockaddr *) &addr, &fromlen);
+
+ if (size < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ msg = (const struct GNUNET_MessageHeader *) buf;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "UDP received %u-byte message from `%s' type %i\n", (unsigned int) size,
+ GNUNET_a2s ((const struct sockaddr *) addr, fromlen), ntohs (msg->type));
+
+ if (size != ntohs (msg->size))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+
+ switch (ntohs (msg->type))
+ {
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON:
+ udp_broadcast_receive (plugin, &buf, size, addr, fromlen);
+ return;
+
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_MESSAGE:
+ read_process_msg (plugin, msg, addr, fromlen);
+ return;
+
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_UDP_ACK:
+ read_process_ack (plugin, msg, addr, fromlen);;
+ return;
+
+ case GNUNET_MESSAGE_TYPE_FRAGMENT:
+ read_process_fragment (plugin, msg, addr, fromlen);
+ return;
+
+ default:
+ GNUNET_break_op (0);
+ return;
+ }
+}
+
+size_t
+udp_select_send (struct Plugin *plugin, struct GNUNET_NETWORK_Handle *sock)
+{
+ ssize_t sent;
+ size_t slen;
+ struct GNUNET_TIME_Absolute max;
+ struct GNUNET_TIME_Absolute ;
+
+ struct UDPMessageWrapper *udpw = NULL;
+
+ if (sock == plugin->sockv4)
+ {
+ udpw = plugin->ipv4_queue_head;
+ }
+ else if (sock == plugin->sockv6)
+ {
+ udpw = plugin->ipv6_queue_head;
+ }
+ else
+ {
+ GNUNET_break (0);
+ return 0;
+ }
+
+ const struct sockaddr * sa = udpw->session->sock_addr;
+ slen = udpw->session->addrlen;
+
+ max = GNUNET_TIME_absolute_max(udpw->timeout, GNUNET_TIME_absolute_get());
+
+ while (udpw != NULL)
+ {
+ if (max.abs_value != udpw->timeout.abs_value)
+ {
+ /* Message timed out */
+
+ if (udpw->cont != NULL)
+ udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR);
+ if (udpw->frag_ctx != NULL)
+ {
+#if DEBUG_UDP
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fragmented message for peer `%s' with size %u timed out\n",
+ GNUNET_i2s(&udpw->session->target), udpw->frag_ctx->bytes_to_send);
+#endif
+ udpw->session->last_expected_delay = GNUNET_FRAGMENT_context_destroy(udpw->frag_ctx->frag);
+ GNUNET_free (udpw->frag_ctx);
+ udpw->session->frag_ctx = NULL;
+ }
+ else
+ {
+#if DEBUG_UDP
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' with size %u timed out\n",
+ GNUNET_i2s(&udpw->session->target), udpw->msg_size);
+#endif
+ }
+
+ if (sock == plugin->sockv4)
+ {
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw);
+ GNUNET_free (udpw);
+ udpw = plugin->ipv4_queue_head;
+ }
+ else if (sock == plugin->sockv6)
+ {
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw);
+ GNUNET_free (udpw);
+ udpw = plugin->ipv6_queue_head;
+ }
+ }
+ else
+ {
+ struct GNUNET_TIME_Relative delta = GNUNET_TIME_absolute_get_remaining (udpw->session->flow_delay_from_other_peer);
+ if (delta.rel_value == 0)
+ {
+ /* this message is not delayed */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' (%u bytes) is not delayed \n",
+ GNUNET_i2s(&udpw->session->target), udpw->msg_size);
+ break;
+ }
+ else
+ {
+ /* this message is delayed, try next */
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Message for peer `%s' (%u bytes) is delayed for %llu \n",
+ GNUNET_i2s(&udpw->session->target), udpw->msg_size,
+ delta);
+ udpw = udpw->next;
+ }
+ }
+
+ }
+
+ if (udpw == NULL)
+ {
+ /* No message left */
+ return 0;
+ }
+
+ sent = GNUNET_NETWORK_socket_sendto (sock, udpw->udp, udpw->msg_size, sa, slen);
+
+ if (GNUNET_SYSERR == sent)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto");
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "UDP transmitted %u-byte message to %s (%d: %s)\n",
+ (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), (int) sent,
+ (sent < 0) ? STRERROR (errno) : "ok");
+ if (udpw->cont != NULL)
+ udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR);
+ }
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "UDP transmitted %u-byte message to %s (%d: %s)\n",
+ (unsigned int) (udpw->msg_size), GNUNET_a2s (sa, slen), (int) sent,
+ (sent < 0) ? STRERROR (errno) : "ok");
+
+ /* This was just a message fragment */
+ if (udpw->frag_ctx != NULL)
+ {
+ GNUNET_FRAGMENT_context_transmission_done (udpw->frag_ctx->frag);
+ }
+ /* This was a complete message*/
+ else
+ {
+ if (udpw->cont != NULL)
+ udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_OK);
+ }
+
+ if (sock == plugin->sockv4)
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw);
+ else if (sock == plugin->sockv6)
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw);
+ GNUNET_free (udpw);
+ udpw = NULL;
+
+ return sent;
+}
+
+/**
+ * We have been notified that our readset has something to read. We don't
+ * know which socket needs to be read, so we have to check each one
+ * Then reschedule this function to be called again once more is available.
+ *
+ * @param cls the plugin handle
+ * @param tc the scheduling context (for rescheduling this function again)
+ */
+static void
+udp_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+ plugin->with_v4_ws = GNUNET_NO;
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0)
+ {
+ if ((NULL != plugin->sockv4) &&
+ (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv4)))
+ udp_select_read (plugin, plugin->sockv4);
+
+ }
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0)
+ {
+ if ((NULL != plugin->sockv4) && (plugin->ipv4_queue_head != NULL) &&
+ (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->sockv4)))
+ {
+ udp_select_send (plugin, plugin->sockv4);
+ }
+ }
+
+ if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (plugin->select_task);
+ plugin->select_task = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs_v4,
+ (plugin->ipv4_queue_head != NULL) ? plugin->ws_v4 : NULL,
+ &udp_plugin_select, plugin);
+ if (plugin->ipv4_queue_head != NULL)
+ plugin->with_v4_ws = GNUNET_YES;
+ else
+ plugin->with_v4_ws = GNUNET_NO;
+}
+
+
+/**
+ * We have been notified that our readset has something to read. We don't
+ * know which socket needs to be read, so we have to check each one
+ * Then reschedule this function to be called again once more is available.
+ *
+ * @param cls the plugin handle
+ * @param tc the scheduling context (for rescheduling this function again)
+ */
+static void
+udp_plugin_select_v6 (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ plugin->select_task_v6 = GNUNET_SCHEDULER_NO_TASK;
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+
+ plugin->with_v6_ws = GNUNET_NO;
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0)
+ {
+ if ((NULL != plugin->sockv6) &&
+ (GNUNET_NETWORK_fdset_isset (tc->read_ready, plugin->sockv6)))
+ udp_select_read (plugin, plugin->sockv6);
+ }
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0)
+ {
+ if ((NULL != plugin->sockv6) && (plugin->ipv6_queue_head != NULL) &&
+ (GNUNET_NETWORK_fdset_isset (tc->write_ready, plugin->sockv6)))
+ {
+ udp_select_send (plugin, plugin->sockv6);
+ }
+ }
+ if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
+ plugin->select_task_v6 = GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs_v6,
+ (plugin->ipv6_queue_head != NULL) ? plugin->ws_v6 : NULL,
+ &udp_plugin_select_v6, plugin);
+ if (plugin->ipv6_queue_head != NULL)
+ plugin->with_v6_ws = GNUNET_YES;
+ else
+ plugin->with_v6_ws = GNUNET_NO;
+}
+
+
+static int
+setup_sockets (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct sockaddr_in *serverAddrv4)
+{
+ int tries;
+ int sockets_created = 0;
+ struct sockaddr *serverAddr;
+ struct sockaddr *addrs[2];
+ socklen_t addrlens[2];
+ socklen_t addrlen;
+
+ /* Create IPv6 socket */
+ if (plugin->enable_ipv6 == GNUNET_YES)
+ {
+ plugin->sockv6 = GNUNET_NETWORK_socket_create (PF_INET6, SOCK_DGRAM, 0);
+ if (NULL == plugin->sockv6)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Disabling IPv6 since it is not supported on this system!\n");
+ plugin->enable_ipv6 = GNUNET_NO;
+ }
+ else
+ {
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ serverAddrv6->sin6_len = sizeof (serverAddrv6);
+#endif
+ serverAddrv6->sin6_family = AF_INET6;
+ serverAddrv6->sin6_addr = in6addr_any;
+ serverAddrv6->sin6_port = htons (plugin->port);
+ addrlen = sizeof (struct sockaddr_in6);
+ serverAddr = (struct sockaddr *) serverAddrv6;
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv6 port %d\n",
+ ntohs (serverAddrv6->sin6_port));
+#endif
+ tries = 0;
+ while (GNUNET_NETWORK_socket_bind (plugin->sockv6, serverAddr, addrlen) !=
+ GNUNET_OK)
+ {
+ serverAddrv6->sin6_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "IPv6 Binding failed, trying new port %d\n",
+ ntohs (serverAddrv6->sin6_port));
+#endif
+ tries++;
+ if (tries > 10)
+ {
+ GNUNET_NETWORK_socket_close (plugin->sockv6);
+ plugin->sockv6 = NULL;
+ break;
+ }
+ }
+ if (plugin->sockv6 != NULL)
+ {
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "IPv6 socket created on port %d\n",
+ ntohs (serverAddrv6->sin6_port));
+#endif
+ addrs[sockets_created] = (struct sockaddr *) serverAddrv6;
+ addrlens[sockets_created] = sizeof (struct sockaddr_in6);
+ sockets_created++;
+ }
+ }
+ }
+
+ /* Create IPv4 socket */
+ plugin->sockv4 = GNUNET_NETWORK_socket_create (PF_INET, SOCK_DGRAM, 0);
+ if (NULL == plugin->sockv4)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "socket");
+ }
+ else
+ {
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ serverAddrv4->sin_len = sizeof (serverAddrv4);
+#endif
+ serverAddrv4->sin_family = AF_INET;
+ serverAddrv4->sin_addr.s_addr = INADDR_ANY;
+ serverAddrv4->sin_port = htons (plugin->port);
+ addrlen = sizeof (struct sockaddr_in);
+ serverAddr = (struct sockaddr *) serverAddrv4;
+
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Binding to IPv4 port %d\n",
+ ntohs (serverAddrv4->sin_port));
+#endif
+ tries = 0;
+ while (GNUNET_NETWORK_socket_bind (plugin->sockv4, serverAddr, addrlen) !=
+ GNUNET_OK)
+ {
+ serverAddrv4->sin_port = htons (GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_STRONG, 33537) + 32000); /* Find a good, non-root port */
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv4 Binding failed, trying new port %d\n",
+ ntohs (serverAddrv4->sin_port));
+#endif
+ tries++;
+ if (tries > 10)
+ {
+ GNUNET_NETWORK_socket_close (plugin->sockv4);
+ plugin->sockv4 = NULL;
+ break;
+ }
+ }
+ if (plugin->sockv4 != NULL)
+ {
+ addrs[sockets_created] = (struct sockaddr *) serverAddrv4;
+ addrlens[sockets_created] = sizeof (struct sockaddr_in);
+ sockets_created++;
+ }
+ }
+
+ /* Create file descriptors */
+ plugin->rs_v4 = GNUNET_NETWORK_fdset_create ();
+ plugin->ws_v4 = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_zero (plugin->rs_v4);
+ GNUNET_NETWORK_fdset_zero (plugin->ws_v4);
+ if (NULL != plugin->sockv4)
+ {
+ GNUNET_NETWORK_fdset_set (plugin->rs_v4, plugin->sockv4);
+ GNUNET_NETWORK_fdset_set (plugin->ws_v4, plugin->sockv4);
+ }
+
+ if (sockets_created == 0)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UDP sockets\n"));
+
+ plugin->select_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs_v4,
+ NULL,
+ &udp_plugin_select, plugin);
+ plugin->with_v4_ws = GNUNET_NO;
+
+ if (plugin->enable_ipv6 == GNUNET_YES)
+ {
+ plugin->rs_v6 = GNUNET_NETWORK_fdset_create ();
+ plugin->ws_v6 = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_zero (plugin->rs_v6);
+ GNUNET_NETWORK_fdset_zero (plugin->ws_v6);
+ if (NULL != plugin->sockv6)
+ {
+ GNUNET_NETWORK_fdset_set (plugin->rs_v6, plugin->sockv6);
+ GNUNET_NETWORK_fdset_set (plugin->ws_v6, plugin->sockv6);
+ }
+
+ plugin->select_task_v6 =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs_v6,
+ NULL,
+ &udp_plugin_select_v6, plugin);
+ plugin->with_v6_ws = GNUNET_NO;
+ }
+
+ plugin->nat = GNUNET_NAT_register (plugin->env->cfg,
+ GNUNET_NO, plugin->port,
+ sockets_created,
+ (const struct sockaddr **) addrs, addrlens,
+ &udp_nat_port_map_callback, NULL, plugin);
+
+ return sockets_created;
+}
+
+
+/**
+ * The exported method. Makes the core api available via a global and
+ * returns the udp transport API.
+ *
+ * @param cls our 'struct GNUNET_TRANSPORT_PluginEnvironment'
+ * @return our 'struct GNUNET_TRANSPORT_PluginFunctions'
+ */
+void *
+libgnunet_plugin_transport_udp_init (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
+ struct GNUNET_TRANSPORT_PluginFunctions *api;
+ struct Plugin *plugin;
+
+ unsigned long long port;
+ unsigned long long aport;
+ unsigned long long broadcast;
+ unsigned long long udp_max_bps;
+ unsigned long long enable_v6;
+ char * bind4_address;
+ char * bind6_address;
+ struct GNUNET_TIME_Relative interval;
+
+ struct sockaddr_in serverAddrv4;
+ struct sockaddr_in6 serverAddrv6;
+
+ int res;
+
+ /* Get port number */
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp", "PORT",
+ &port))
+ port = 2086;
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp",
+ "ADVERTISED_PORT", &aport))
+ aport = port;
+ if (port > 65535)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _("Given `%s' option is out of range: %llu > %u\n"), "PORT", port,
+ 65535);
+ return NULL;
+ }
+
+ /* Protocols */
+ if ((GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "nat",
+ "DISABLEV6")))
+ {
+ enable_v6 = GNUNET_NO;
+ }
+ else
+ enable_v6 = GNUNET_YES;
+
+
+ /* Addresses */
+ memset (&serverAddrv6, 0, sizeof (serverAddrv6));
+ memset (&serverAddrv4, 0, sizeof (serverAddrv4));
+
+ if (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_string (env->cfg, "transport-udp",
+ "BINDTO", &bind4_address))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Binding udp plugin to specific address: `%s'\n",
+ bind4_address);
+ if (1 != inet_pton (AF_INET, bind4_address, &serverAddrv4.sin_addr))
+ {
+ GNUNET_free (bind4_address);
+ return NULL;
+ }
+ }
+
+ if (GNUNET_YES ==
+ GNUNET_CONFIGURATION_get_value_string (env->cfg, "transport-udp",
+ "BINDTO6", &bind6_address))
+ {
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Binding udp plugin to specific address: `%s'\n",
+ bind6_address);
+ if (1 !=
+ inet_pton (AF_INET6, bind6_address, &serverAddrv6.sin6_addr))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, _("Invalid IPv6 address: `%s'\n"),
+ bind6_address);
+ GNUNET_free_non_null (bind4_address);
+ GNUNET_free (bind6_address);
+ return NULL;
+ }
+ }
+
+
+ /* Enable neighbour discovery */
+ broadcast = GNUNET_CONFIGURATION_get_value_yesno (env->cfg, "transport-udp",
+ "BROADCAST");
+ if (broadcast == GNUNET_SYSERR)
+ broadcast = GNUNET_NO;
+
+ if (GNUNET_SYSERR == GNUNET_CONFIGURATION_get_value_time (env->cfg, "transport-udp",
+ "BROADCAST_INTERVAL", &interval))
+ {
+ interval = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10);
+ }
+
+ /* Maximum datarate */
+ if (GNUNET_OK != GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-udp",
+ "MAX_BPS", &udp_max_bps))
+ {
+ udp_max_bps = 1024 * 1024 * 50; /* 50 MB/s == infinity for practical purposes */
+ }
+
+ plugin = GNUNET_malloc (sizeof (struct Plugin));
+ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
+
+ GNUNET_BANDWIDTH_tracker_init (&plugin->tracker,
+ GNUNET_BANDWIDTH_value_init ((uint32_t)udp_max_bps), 30);
+
+
+ plugin->sessions = GNUNET_CONTAINER_multihashmap_create (10);
+ plugin->defrag_ctxs = GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
+ plugin->mst = GNUNET_SERVER_mst_create (&process_inbound_tokenized_messages, plugin);
+ plugin->port = port;
+ plugin->aport = aport;
+ plugin->broadcast_interval = interval;
+ plugin->enable_ipv6 = enable_v6;
+ plugin->env = env;
+
+ api->cls = plugin;
+ api->send = NULL;
+ api->disconnect = &udp_disconnect;
+ api->address_pretty_printer = &udp_plugin_address_pretty_printer;
+ api->address_to_string = &udp_address_to_string;
+ api->check_address = &udp_plugin_check_address;
+ api->get_session = &udp_plugin_get_session;
+ api->send = &udp_plugin_send;
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Setting up sockets\n");
+ res = setup_sockets (plugin, &serverAddrv6, &serverAddrv4);
+ if ((res == 0) || ((plugin->sockv4 == NULL) && (plugin->sockv6 == NULL)))
+ {
+ LOG (GNUNET_ERROR_TYPE_ERROR, "Failed to create network sockets, plugin failed\n");
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+ return NULL;
+ }
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Starting broadcasting\n");
+ if (broadcast == GNUNET_YES)
+ setup_broadcast (plugin, &serverAddrv6, &serverAddrv4);
+
+
+ GNUNET_free_non_null (bind4_address);
+ GNUNET_free_non_null (bind6_address);
+ return api;
+}
+
+int heap_cleanup_iterator (void *cls,
+ struct GNUNET_CONTAINER_HeapNode *
+ node, void *element,
+ GNUNET_CONTAINER_HeapCostType
+ cost)
+{
+ struct DefragContext * d_ctx = element;
+
+ GNUNET_CONTAINER_heap_remove_node (node);
+ GNUNET_DEFRAGMENT_context_destroy(d_ctx->defrag);
+ GNUNET_free (d_ctx);
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * The exported method. Makes the core api available via a global and
+ * returns the udp transport API.
+ *
+ * @param cls our 'struct GNUNET_TRANSPORT_PluginEnvironment'
+ * @return our 'struct GNUNET_TRANSPORT_PluginFunctions'
+ */
+void *
+libgnunet_plugin_transport_udp_done (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
+ struct Plugin *plugin = api->cls;
+ stop_broadcast (plugin);
+
+ if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->select_task);
+ plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (plugin->select_task_v6 != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->select_task_v6);
+ plugin->select_task_v6 = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ /* Closing sockets */
+ if (plugin->sockv4 != NULL)
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv4));
+ plugin->sockv4 = NULL;
+ }
+ GNUNET_NETWORK_fdset_destroy (plugin->rs_v4);
+ GNUNET_NETWORK_fdset_destroy (plugin->ws_v4);
+
+ if (plugin->sockv6 != NULL)
+ {
+ GNUNET_break (GNUNET_OK == GNUNET_NETWORK_socket_close (plugin->sockv6));
+ plugin->sockv6 = NULL;
+
+ GNUNET_NETWORK_fdset_destroy (plugin->rs_v6);
+ GNUNET_NETWORK_fdset_destroy (plugin->ws_v6);
+ }
+
+ GNUNET_NAT_unregister (plugin->nat);
+
+ if (plugin->defrag_ctxs != NULL)
+ {
+ GNUNET_CONTAINER_heap_iterate(plugin->defrag_ctxs,
+ heap_cleanup_iterator, NULL);
+ GNUNET_CONTAINER_heap_destroy(plugin->defrag_ctxs);
+ plugin->defrag_ctxs = NULL;
+ }
+ if (plugin->mst != NULL)
+ {
+ GNUNET_SERVER_mst_destroy(plugin->mst);
+ plugin->mst = NULL;
+ }
+
+ /* Clean up leftover messages */
+ struct UDPMessageWrapper * udpw;
+ udpw = plugin->ipv4_queue_head;
+ while (udpw != NULL)
+ {
+ struct UDPMessageWrapper *tmp = udpw->next;
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv4_queue_head, plugin->ipv4_queue_tail, udpw);
+ if (udpw->cont != NULL)
+ udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR);
+ GNUNET_free (udpw);
+ udpw = tmp;
+ }
+ udpw = plugin->ipv6_queue_head;
+ while (udpw != NULL)
+ {
+ struct UDPMessageWrapper *tmp = udpw->next;
+ GNUNET_CONTAINER_DLL_remove(plugin->ipv6_queue_head, plugin->ipv6_queue_tail, udpw);
+ if (udpw->cont != NULL)
+ udpw->cont (udpw->cont_cls, &udpw->session->target, GNUNET_SYSERR);
+ GNUNET_free (udpw);
+ udpw = tmp;
+ }
+
+ /* Clean up sessions */
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Cleaning up sessions\n");
+#endif
+ GNUNET_CONTAINER_multihashmap_iterate (plugin->sessions, &disconnect_and_free_it, plugin);
+ GNUNET_CONTAINER_multihashmap_destroy (plugin->sessions);
+
+ plugin->nat = NULL;
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+ return NULL;
+}
+
+
+/* end of plugin_transport_udp.c */
diff --git a/src/transport/plugin_transport_udp.h b/src/transport/plugin_transport_udp.h
new file mode 100644
index 0000000..5637524
--- /dev/null
+++ b/src/transport/plugin_transport_udp.h
@@ -0,0 +1,291 @@
+/*
+ This file is part of GNUnet
+ (C) 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_udp.h
+ * @brief Implementation of the UDP transport protocol
+ * @author Christian Grothoff
+ * @author Nathan Evans
+ * @author Matthias Wachs
+ */
+#include "platform.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_fragmentation_lib.h"
+#include "gnunet_nat_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_signatures.h"
+#include "gnunet_constants.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_transport_plugin.h"
+#include "transport.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__)
+
+#define DEBUG_UDP GNUNET_NO
+#define DEBUG_UDP_BROADCASTING GNUNET_NO
+
+/**
+ * MTU for fragmentation subsystem. Should be conservative since
+ * all communicating peers MUST work with this MTU.
+ */
+#define UDP_MTU 1400
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+/**
+ * Network format for IPv4 addresses.
+ */
+struct IPv4UdpAddress
+{
+ /**
+ * IPv4 address, in network byte order.
+ */
+ uint32_t ipv4_addr GNUNET_PACKED;
+
+ /**
+ * Port number, in network byte order.
+ */
+ uint16_t u4_port GNUNET_PACKED;
+};
+
+
+/**
+ * Network format for IPv6 addresses.
+ */
+struct IPv6UdpAddress
+{
+
+ /**
+ * IPv6 address.
+ */
+ struct in6_addr ipv6_addr GNUNET_PACKED;
+
+ /**
+ * Port number, in network byte order.
+ */
+ uint16_t u6_port GNUNET_PACKED;
+};
+GNUNET_NETWORK_STRUCT_END
+
+
+/**
+ * UDP Message-Packet header (after defragmentation).
+ */
+struct UDPMessage
+{
+ /**
+ * Message header.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Always zero for now.
+ */
+ uint32_t reserved;
+
+ /**
+ * What is the identity of the sender
+ */
+ struct GNUNET_PeerIdentity sender;
+
+};
+
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin
+{
+
+ /**
+ * Our environment.
+ */
+ struct GNUNET_TRANSPORT_PluginEnvironment *env;
+
+ /**
+ * Session of peers with whom we are currently connected,
+ * map of peer identity to 'struct PeerSession'.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *sessions;
+
+ /**
+ * Heap with all of our defragmentation activities.
+ */
+ struct GNUNET_CONTAINER_Heap *defrag_ctxs;
+
+ /**
+ * ID of select task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier select_task;
+ GNUNET_SCHEDULER_TaskIdentifier select_task_v6;
+
+ /**
+ * Tokenizer for inbound messages.
+ */
+ struct GNUNET_SERVER_MessageStreamTokenizer *mst;
+
+ /**
+ * Bandwidth tracker to limit global UDP traffic.
+ */
+ struct GNUNET_BANDWIDTH_Tracker tracker;
+
+ /**
+ * Address we were told to bind to exclusively (IPv4).
+ */
+ char *bind4_address;
+
+ /**
+ * Address we were told to bind to exclusively (IPv6).
+ */
+ char *bind6_address;
+
+ /**
+ * Handle to NAT traversal support.
+ */
+ struct GNUNET_NAT_Handle *nat;
+
+ /**
+ * FD Read set
+ */
+ struct GNUNET_NETWORK_FDSet *rs_v4;
+
+ /**
+ * FD Write set
+ */
+ struct GNUNET_NETWORK_FDSet *ws_v4;
+
+
+ int with_v4_ws;
+
+ /**
+ * The read socket for IPv4
+ */
+ struct GNUNET_NETWORK_Handle *sockv4;
+
+
+ /**
+ * FD Read set
+ */
+ struct GNUNET_NETWORK_FDSet *rs_v6;
+
+ /**
+ * FD Write set
+ */
+ struct GNUNET_NETWORK_FDSet *ws_v6;
+
+ int with_v6_ws;
+
+ /**
+ * The read socket for IPv6
+ */
+ struct GNUNET_NETWORK_Handle *sockv6;
+
+ /**
+ * Beacon broadcasting
+ * -------------------
+ */
+
+ /**
+ * Broadcast interval
+ */
+ struct GNUNET_TIME_Relative broadcast_interval;
+
+ /**
+ * Broadcast with IPv4
+ */
+ int broadcast_ipv4;
+
+ /**
+ * Broadcast with IPv6
+ */
+ int broadcast_ipv6;
+
+
+ /**
+ * Tokenizer for inbound messages.
+ */
+ struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_ipv6_mst;
+ struct GNUNET_SERVER_MessageStreamTokenizer *broadcast_ipv4_mst;
+
+ /**
+ * ID of select broadcast task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier send_ipv4_broadcast_task;
+
+ /**
+ * ID of select broadcast task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier send_ipv6_broadcast_task;
+
+ /**
+ * IPv6 multicast address
+ */
+ struct sockaddr_in6 ipv6_multicast_address;
+
+ /**
+ * DLL of IPv4 broadcast addresses
+ */
+ struct BroadcastAddress *ipv4_broadcast_tail;
+ struct BroadcastAddress *ipv4_broadcast_head;
+
+ /**
+ * Enable IPv6
+ */
+ int enable_ipv6;
+
+ /**
+ * Port we broadcasting on.
+ */
+ uint16_t broadcast_port;
+
+ /**
+ * Port we listen on.
+ */
+ uint16_t port;
+
+ /**
+ * Port we advertise on.
+ */
+ uint16_t aport;
+
+ struct UDPMessageWrapper *ipv4_queue_head;
+ struct UDPMessageWrapper *ipv4_queue_tail;
+
+ struct UDPMessageWrapper *ipv6_queue_head;
+ struct UDPMessageWrapper *ipv6_queue_tail;
+};
+
+
+const char *
+udp_address_to_string (void *cls, const void *addr, size_t addrlen);
+
+void
+udp_broadcast_receive ();
+
+void
+setup_broadcast (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct sockaddr_in *serverAddrv4);
+
+void
+stop_broadcast (struct Plugin *plugin);
+
+/* end of plugin_transport_udp.h */
diff --git a/src/transport/plugin_transport_udp_broadcasting.c b/src/transport/plugin_transport_udp_broadcasting.c
new file mode 100644
index 0000000..e33af26
--- /dev/null
+++ b/src/transport/plugin_transport_udp_broadcasting.c
@@ -0,0 +1,522 @@
+/*
+ This file is part of GNUnet
+ (C) 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_udp_broadcasting.c
+ * @brief Neighbour discovery with UDP
+ * @author Christian Grothoff
+ * @author Matthias Wachs
+ */
+#include "platform.h"
+#include "plugin_transport_udp.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_fragmentation_lib.h"
+#include "gnunet_nat_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_signatures.h"
+#include "gnunet_constants.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_transport_plugin.h"
+#include "transport.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "transport-udp", __VA_ARGS__)
+
+
+struct UDP_Beacon_Message
+{
+ /**
+ * Message header.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * What is the identity of the sender
+ */
+ struct GNUNET_PeerIdentity sender;
+};
+
+
+struct BroadcastAddress
+{
+ struct BroadcastAddress *next;
+ struct BroadcastAddress *prev;
+
+ void *addr;
+ socklen_t addrlen;
+};
+
+
+struct Mstv4Context
+{
+ struct Plugin *plugin;
+
+ struct IPv4UdpAddress addr;
+ /**
+ * ATS network type in NBO
+ */
+ uint32_t ats_address_network_type;
+};
+
+struct Mstv6Context
+{
+ struct Plugin *plugin;
+
+ struct IPv6UdpAddress addr;
+ /**
+ * ATS network type in NBO
+ */
+ uint32_t ats_address_network_type;
+};
+
+
+
+void
+broadcast_ipv6_mst_cb (void *cls, void *client,
+ const struct GNUNET_MessageHeader *message)
+{
+
+ struct Plugin *plugin = cls;
+ struct Mstv6Context *mc = client;
+ const struct GNUNET_MessageHeader *hello;
+ struct UDP_Beacon_Message *msg;
+
+ msg = (struct UDP_Beacon_Message *) message;
+
+ if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON !=
+ ntohs (msg->header.type))
+ return;
+#if DEBUG_UDP_BROADCASTING
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received beacon with %u bytes from peer `%s' via address `%s'\n",
+ ntohs (msg->header.size), GNUNET_i2s (&msg->sender),
+ udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr)));
+#endif
+ struct GNUNET_ATS_Information atsi[2];
+
+ /* setup ATS */
+ atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
+ atsi[0].value = htonl (1);
+ atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE);
+ atsi[1].value = mc->ats_address_network_type;
+ GNUNET_break (ntohl(mc->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED);
+
+ hello = (struct GNUNET_MessageHeader *) &msg[1];
+ plugin->env->receive (plugin->env->cls, &msg->sender, hello,
+ (const struct GNUNET_ATS_Information *) &atsi, 2, NULL,
+ (const char *) &mc->addr, sizeof (mc->addr));
+
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ _
+ ("# IPv6 multicast HELLO beacons received via udp"),
+ 1, GNUNET_NO);
+ GNUNET_free (mc);
+}
+
+void
+broadcast_ipv4_mst_cb (void *cls, void *client,
+ const struct GNUNET_MessageHeader *message)
+{
+ struct Plugin *plugin = cls;
+ struct Mstv4Context *mc = client;
+ const struct GNUNET_MessageHeader *hello;
+ struct UDP_Beacon_Message *msg;
+
+ msg = (struct UDP_Beacon_Message *) message;
+
+ if (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON !=
+ ntohs (msg->header.type))
+ return;
+#if DEBUG_UDP_BROADCASTING
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received beacon with %u bytes from peer `%s' via address `%s'\n",
+ ntohs (msg->header.size), GNUNET_i2s (&msg->sender),
+ udp_address_to_string (NULL, &mc->addr, sizeof (mc->addr)));
+#endif
+
+ struct GNUNET_ATS_Information atsi[2];
+
+ /* setup ATS */
+ atsi[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
+ atsi[0].value = htonl (1);
+ atsi[1].type = htonl (GNUNET_ATS_NETWORK_TYPE);
+ atsi[1].value = mc->ats_address_network_type;
+ GNUNET_break (ntohl(mc->ats_address_network_type) != GNUNET_ATS_NET_UNSPECIFIED);
+
+ hello = (struct GNUNET_MessageHeader *) &msg[1];
+ plugin->env->receive (plugin->env->cls, &msg->sender, hello,
+ (const struct GNUNET_ATS_Information *) &atsi, 2, NULL,
+ (const char *) &mc->addr, sizeof (mc->addr));
+
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ _
+ ("# IPv4 broadcast HELLO beacons received via udp"),
+ 1, GNUNET_NO);
+ GNUNET_free (mc);
+}
+
+void
+udp_broadcast_receive (struct Plugin *plugin, const char * buf, ssize_t size, struct sockaddr *addr, size_t addrlen)
+{
+ struct GNUNET_ATS_Information ats;
+
+ if (addrlen == sizeof (struct sockaddr_in))
+ {
+#if DEBUG_UDP_BROADCASTING
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received IPv4 HELLO beacon broadcast with %i bytes from address %s\n",
+ size, GNUNET_a2s ((const struct sockaddr *) addr, addrlen));
+#endif
+ struct Mstv4Context *mc;
+
+ mc = GNUNET_malloc (sizeof (struct Mstv4Context));
+ struct sockaddr_in *av4 = (struct sockaddr_in *) addr;
+
+ mc->addr.ipv4_addr = av4->sin_addr.s_addr;
+ mc->addr.u4_port = av4->sin_port;
+ ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen);
+ mc->ats_address_network_type = ats.value;
+ if (GNUNET_OK !=
+ GNUNET_SERVER_mst_receive (plugin->broadcast_ipv4_mst, mc, buf, size,
+ GNUNET_NO, GNUNET_NO))
+ GNUNET_free (mc);
+ }
+ else if (addrlen == sizeof (struct sockaddr_in6))
+ {
+#if DEBUG_UDP_BROADCASTING
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Received IPv6 HELLO beacon broadcast with %i bytes from address %s\n",
+ size, GNUNET_a2s ((const struct sockaddr *) &addr, addrlen));
+#endif
+ struct Mstv6Context *mc;
+
+ mc = GNUNET_malloc (sizeof (struct Mstv6Context));
+ struct sockaddr_in6 *av6 = (struct sockaddr_in6 *) addr;
+
+ mc->addr.ipv6_addr = av6->sin6_addr;
+ mc->addr.u6_port = av6->sin6_port;
+ ats = plugin->env->get_address_type (plugin->env->cls, (const struct sockaddr *) addr, addrlen);
+ mc->ats_address_network_type = ats.value;
+
+ if (GNUNET_OK !=
+ GNUNET_SERVER_mst_receive (plugin->broadcast_ipv6_mst, mc, buf, size,
+ GNUNET_NO, GNUNET_NO))
+ GNUNET_free (mc);
+ }
+}
+
+static void
+udp_ipv4_broadcast_send (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+ int sent;
+ uint16_t msg_size;
+ uint16_t hello_size;
+ char buf[65536];
+
+ const struct GNUNET_MessageHeader *hello;
+ struct UDP_Beacon_Message *msg;
+ struct BroadcastAddress *baddr;
+
+ plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK;
+
+ hello = plugin->env->get_our_hello ();
+ hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
+ msg_size = hello_size + sizeof (struct UDP_Beacon_Message);
+
+ if (hello_size < (sizeof (struct GNUNET_MessageHeader)) ||
+ (msg_size > (UDP_MTU)))
+ return;
+
+ msg = (struct UDP_Beacon_Message *) buf;
+ msg->sender = *(plugin->env->my_identity);
+ msg->header.size = ntohs (msg_size);
+ msg->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON);
+ memcpy (&msg[1], hello, hello_size);
+ sent = 0;
+
+ baddr = plugin->ipv4_broadcast_head;
+ /* just IPv4 */
+ while ((baddr != NULL) && (baddr->addrlen == sizeof (struct sockaddr_in)))
+ {
+ struct sockaddr_in *addr = (struct sockaddr_in *) baddr->addr;
+
+ addr->sin_port = htons (plugin->port);
+
+ sent =
+ GNUNET_NETWORK_socket_sendto (plugin->sockv4, msg, msg_size,
+ (const struct sockaddr *) addr,
+ baddr->addrlen);
+ if (sent == GNUNET_SYSERR)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto");
+ else
+ {
+#if DEBUG_UDP_BROADCASTING
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sent HELLO beacon broadcast with %i bytes to address %s\n", sent,
+ GNUNET_a2s (baddr->addr, baddr->addrlen));
+#endif
+ }
+ baddr = baddr->next;
+ }
+
+ plugin->send_ipv4_broadcast_task =
+ GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval,
+ &udp_ipv4_broadcast_send, plugin);
+}
+
+static void
+udp_ipv6_broadcast_send (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+ int sent;
+ uint16_t msg_size;
+ uint16_t hello_size;
+ char buf[65536];
+
+ const struct GNUNET_MessageHeader *hello;
+ struct UDP_Beacon_Message *msg;
+
+ plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_NO_TASK;
+
+ hello = plugin->env->get_our_hello ();
+ hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
+ msg_size = hello_size + sizeof (struct UDP_Beacon_Message);
+
+ if (hello_size < (sizeof (struct GNUNET_MessageHeader)) ||
+ (msg_size > (UDP_MTU)))
+ return;
+
+ msg = (struct UDP_Beacon_Message *) buf;
+ msg->sender = *(plugin->env->my_identity);
+ msg->header.size = ntohs (msg_size);
+ msg->header.type = ntohs (GNUNET_MESSAGE_TYPE_TRANSPORT_BROADCAST_BEACON);
+ memcpy (&msg[1], hello, hello_size);
+ sent = 0;
+
+ sent =
+ GNUNET_NETWORK_socket_sendto (plugin->sockv6, msg, msg_size,
+ (const struct sockaddr *)
+ &plugin->ipv6_multicast_address,
+ sizeof (struct sockaddr_in6));
+ if (sent == GNUNET_SYSERR)
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "sendto");
+ else
+ {
+#if DEBUG_UDP_BROADCASTING
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending IPv6 HELLO beacon broadcast with %i bytes to address %s\n",
+ sent,
+ GNUNET_a2s ((const struct sockaddr *) &plugin->ipv6_multicast_address,
+ sizeof (struct sockaddr_in6)));
+#endif
+ }
+
+
+ plugin->send_ipv6_broadcast_task =
+ GNUNET_SCHEDULER_add_delayed (plugin->broadcast_interval,
+ &udp_ipv6_broadcast_send, plugin);
+}
+
+
+static int
+iface_proc (void *cls, const char *name, int isDefault,
+ const struct sockaddr *addr, const struct sockaddr *broadcast_addr,
+ const struct sockaddr *netmask, socklen_t addrlen)
+{
+ struct Plugin *plugin = cls;
+
+ if (addr != NULL)
+ {
+#if DEBUG_UDP_BROADCASTING
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "address %s for interface %s %p\n ",
+ GNUNET_a2s (addr, addrlen), name, addr);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "broadcast address %s for interface %s %p\n ",
+ GNUNET_a2s (broadcast_addr, addrlen), name, broadcast_addr);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "netmask %s for interface %s %p\n ",
+ GNUNET_a2s (netmask, addrlen), name, netmask);
+#endif
+
+ /* Collecting broadcast addresses */
+ if (broadcast_addr != NULL)
+ {
+ struct BroadcastAddress *ba =
+ GNUNET_malloc (sizeof (struct BroadcastAddress));
+ ba->addr = GNUNET_malloc (addrlen);
+ memcpy (ba->addr, broadcast_addr, addrlen);
+ ba->addrlen = addrlen;
+ GNUNET_CONTAINER_DLL_insert (plugin->ipv4_broadcast_head,
+ plugin->ipv4_broadcast_tail, ba);
+ }
+ }
+ return GNUNET_OK;
+}
+
+
+void
+setup_broadcast (struct Plugin *plugin, struct sockaddr_in6 *serverAddrv6, struct sockaddr_in *serverAddrv4)
+{
+ /* create IPv4 broadcast socket */
+ plugin->broadcast_ipv4 = GNUNET_NO;
+ if (plugin->sockv4 != NULL)
+ {
+ int yes = 1;
+
+ if (GNUNET_NETWORK_socket_setsockopt
+ (plugin->sockv4, SOL_SOCKET, SO_BROADCAST, &yes,
+ sizeof (int)) != GNUNET_OK)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ _
+ ("Failed to set IPv4 broadcast option for broadcast socket on port %d\n"),
+ ntohs (serverAddrv4->sin_port));
+ }
+ else
+ {
+ GNUNET_OS_network_interfaces_list (iface_proc, plugin);
+ plugin->send_ipv4_broadcast_task =
+ GNUNET_SCHEDULER_add_now (&udp_ipv4_broadcast_send, plugin);
+
+ plugin->broadcast_ipv4_mst =
+ GNUNET_SERVER_mst_create (broadcast_ipv4_mst_cb, plugin);
+
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv4 Broadcasting running\n");
+ plugin->broadcast_ipv4 = GNUNET_YES;
+ }
+ }
+
+ plugin->broadcast_ipv6 = GNUNET_NO;
+ if (plugin->sockv6 != NULL)
+ {
+ memset (&plugin->ipv6_multicast_address, 0, sizeof (struct sockaddr_in6));
+ GNUNET_assert (1 ==
+ inet_pton (AF_INET6, "FF05::13B",
+ &plugin->ipv6_multicast_address.sin6_addr));
+
+ plugin->ipv6_multicast_address.sin6_family = AF_INET6;
+ plugin->ipv6_multicast_address.sin6_port = htons (plugin->port);
+
+ plugin->broadcast_ipv6_mst =
+ GNUNET_SERVER_mst_create (broadcast_ipv6_mst_cb, plugin);
+
+ /* Create IPv6 multicast request */
+ struct ipv6_mreq multicastRequest;
+
+ multicastRequest.ipv6mr_multiaddr =
+ plugin->ipv6_multicast_address.sin6_addr;
+ /* TODO: 0 selects the "best" interface, tweak to use all interfaces
+ *
+ * http://tools.ietf.org/html/rfc2553#section-5.2:
+ *
+ * IPV6_JOIN_GROUP
+ *
+ * Join a multicast group on a specified local interface. If the
+ * interface index is specified as 0, the kernel chooses the local
+ * interface. For example, some kernels look up the multicast
+ * group in the normal IPv6 routing table and using the resulting
+ * interface.
+ * */
+ multicastRequest.ipv6mr_interface = 0;
+
+ /* Join the multicast group */
+ if (GNUNET_NETWORK_socket_setsockopt
+ (plugin->sockv6, IPPROTO_IPV6, IPV6_JOIN_GROUP,
+ (char *) &multicastRequest, sizeof (multicastRequest)) != GNUNET_OK)
+ {
+ LOG (GNUNET_ERROR_TYPE_WARNING,
+ "Failed to join IPv6 multicast group: IPv6 broadcasting not running\n");
+ }
+ else
+ {
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 broadcasting running\n");
+#endif
+ plugin->send_ipv6_broadcast_task =
+ GNUNET_SCHEDULER_add_now (&udp_ipv6_broadcast_send, plugin);
+ plugin->broadcast_ipv6 = GNUNET_YES;
+ }
+ }
+}
+
+void
+stop_broadcast (struct Plugin *plugin)
+{
+ if (plugin->broadcast_ipv4)
+ {
+ if (plugin->send_ipv4_broadcast_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->send_ipv4_broadcast_task);
+ plugin->send_ipv4_broadcast_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (plugin->broadcast_ipv4_mst != NULL)
+ GNUNET_SERVER_mst_destroy (plugin->broadcast_ipv4_mst);
+
+ while (plugin->ipv4_broadcast_head != NULL)
+ {
+ struct BroadcastAddress *p = plugin->ipv4_broadcast_head;
+
+ GNUNET_CONTAINER_DLL_remove (plugin->ipv4_broadcast_head,
+ plugin->ipv4_broadcast_tail, p);
+ GNUNET_free (p->addr);
+ GNUNET_free (p);
+ }
+ }
+
+ if (plugin->broadcast_ipv6)
+ {
+ /* Create IPv6 multicast request */
+ struct ipv6_mreq multicastRequest;
+
+ multicastRequest.ipv6mr_multiaddr =
+ plugin->ipv6_multicast_address.sin6_addr;
+ multicastRequest.ipv6mr_interface = 0;
+
+ /* Join the multicast address */
+ if (GNUNET_NETWORK_socket_setsockopt
+ (plugin->sockv6, IPPROTO_IPV6, IPV6_LEAVE_GROUP,
+ (char *) &multicastRequest, sizeof (multicastRequest)) != GNUNET_OK)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, setsockopt);
+ }
+ else
+ {
+#if DEBUG_UDP
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "IPv6 Broadcasting stopped\n");
+#endif
+ }
+
+ if (plugin->send_ipv6_broadcast_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->send_ipv6_broadcast_task);
+ plugin->send_ipv6_broadcast_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (plugin->broadcast_ipv6_mst != NULL)
+ GNUNET_SERVER_mst_destroy (plugin->broadcast_ipv6_mst);
+ }
+
+}
+
+/* end of plugin_transport_udp_broadcasting.c */
diff --git a/src/transport/plugin_transport_unix.c b/src/transport/plugin_transport_unix.c
new file mode 100644
index 0000000..499cc23
--- /dev/null
+++ b/src/transport/plugin_transport_unix.c
@@ -0,0 +1,1078 @@
+/*
+ This file is part of GNUnet
+ (C) 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/plugin_transport_unix.c
+ * @brief Transport plugin using unix domain sockets (!)
+ * Clearly, can only be used locally on Unix/Linux hosts...
+ * ONLY INTENDED FOR TESTING!!!
+ * @author Christian Grothoff
+ * @author Nathan Evans
+ */
+
+#include "platform.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_connection_lib.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_peerinfo_service.h"
+#include "gnunet_protocols.h"
+#include "gnunet_resolver_service.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_signatures.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_transport_plugin.h"
+#include "transport.h"
+
+#define DEBUG_UNIX GNUNET_EXTRALOGGING
+#define DETAILS GNUNET_NO
+
+#define MAX_PROBES 20
+
+/*
+ * Transport cost to peer, always 1 for UNIX (direct connection)
+ */
+#define UNIX_DIRECT_DISTANCE 1
+
+#define DEFAULT_NAT_PORT 0
+
+/**
+ * How long until we give up on transmitting the welcome message?
+ */
+#define HOSTNAME_RESOLVE_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+/**
+ * Starting port for listening and sending, eventually a config value
+ */
+#define UNIX_NAT_DEFAULT_PORT 22086
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * UNIX Message-Packet header.
+ */
+struct UNIXMessage
+{
+ /**
+ * Message header.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * What is the identity of the sender (GNUNET_hash of public key)
+ */
+ struct GNUNET_PeerIdentity sender;
+
+};
+
+struct Session
+{
+ void *addr;
+ size_t addrlen;
+ struct GNUNET_PeerIdentity target;
+};
+
+struct UNIXMessageWrapper
+{
+ struct UNIXMessageWrapper *next;
+ struct UNIXMessageWrapper *prev;
+
+ struct UNIXMessage * msg;
+ size_t msgsize;
+
+ struct GNUNET_TIME_Relative timeout;
+ unsigned int priority;
+
+ struct Session *session;
+ GNUNET_TRANSPORT_TransmitContinuation cont;
+ void *cont_cls;
+};
+
+/* Forward definition */
+struct Plugin;
+
+
+/**
+ * UNIX NAT "Session"
+ */
+struct PeerSession
+{
+
+ /**
+ * Stored in a linked list.
+ */
+ struct PeerSession *next;
+
+ /**
+ * Pointer to the global plugin struct.
+ */
+ struct Plugin *plugin;
+
+ /**
+ * To whom are we talking to (set to our identity
+ * if we are still waiting for the welcome message)
+ */
+ struct GNUNET_PeerIdentity target;
+
+ /**
+ * Address of the other peer (either based on our 'connect'
+ * call or on our 'accept' call).
+ */
+ void *connect_addr;
+
+ /**
+ * Length of connect_addr.
+ */
+ size_t connect_alen;
+
+ /**
+ * Are we still expecting the welcome message? (GNUNET_YES/GNUNET_NO)
+ */
+ int expecting_welcome;
+
+ /**
+ * From which socket do we need to send to this peer?
+ */
+ struct GNUNET_NETWORK_Handle *sock;
+
+ /*
+ * Queue of messages for this peer, in the case that
+ * we have to await a connection...
+ */
+ struct MessageQueue *messages;
+
+};
+
+/**
+ * Information we keep for each of our listen sockets.
+ */
+struct UNIX_Sock_Info
+{
+ /**
+ * The network handle
+ */
+ struct GNUNET_NETWORK_Handle *desc;
+
+ /**
+ * The port we bound to
+ */
+ uint16_t port;
+};
+
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin
+{
+ /**
+ * Our environment.
+ */
+ struct GNUNET_TRANSPORT_PluginEnvironment *env;
+
+ /*
+ * Session of peers with whom we are currently connected
+ */
+ struct PeerSession *sessions;
+
+ /*
+ * Sessions
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *session_map;
+
+ /**
+ * ID of task used to update our addresses when one expires.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier address_update_task;
+
+ /**
+ * ID of select task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier select_task;
+
+ /**
+ * Integer to append to unix domain socket.
+ */
+ uint16_t port;
+
+ /**
+ * FD Read set
+ */
+ struct GNUNET_NETWORK_FDSet *rs;
+
+ /**
+ * FD Write set
+ */
+ struct GNUNET_NETWORK_FDSet *ws;
+
+ int with_ws;
+
+ /**
+ * socket that we transmit all data with
+ */
+ struct UNIX_Sock_Info unix_sock;
+
+ /**
+ * Path of our unix domain socket (/tmp/unix-plugin-PORT)
+ */
+ char *unix_socket_path;
+
+ struct UNIXMessageWrapper *msg_head;
+ struct UNIXMessageWrapper *msg_tail;
+
+ /**
+ * ATS network
+ */
+ struct GNUNET_ATS_Information ats_network;
+};
+
+
+static int
+get_session_delete_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct Session *s = value;
+ struct Plugin *plugin = cls;
+ GNUNET_assert (plugin != NULL);
+
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Deleting session for peer `%s' `%s' \n", GNUNET_i2s (&s->target), s->addr);
+#endif
+
+ plugin->env->session_end (plugin->env->cls, &s->target, s);
+
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove(plugin->session_map, &s->target.hashPubKey, s));
+
+ GNUNET_free (s);
+
+ return GNUNET_YES;
+}
+
+/**
+ * Disconnect from a remote node. Clean up session if we have one for this peer
+ *
+ * @param cls closure for this call (should be handle to Plugin)
+ * @param target the peeridentity of the peer to disconnect
+ * @return GNUNET_OK on success, GNUNET_SYSERR if the operation failed
+ */
+void
+unix_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
+{
+ struct Plugin *plugin = cls;
+ GNUNET_assert (plugin != NULL);
+
+ GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &target->hashPubKey, &get_session_delete_it, plugin);
+ return;
+}
+
+/**
+ * Shutdown the server process (stop receiving inbound traffic). Maybe
+ * restarted later!
+ *
+ * @param cls Handle to the plugin for this transport
+ *
+ * @return returns the number of sockets successfully closed,
+ * should equal the number of sockets successfully opened
+ */
+static int
+unix_transport_server_stop (void *cls)
+{
+ struct Plugin *plugin = cls;
+
+ struct UNIXMessageWrapper * msgw = plugin->msg_head;
+
+ while (NULL != (msgw = plugin->msg_head))
+ {
+ GNUNET_CONTAINER_DLL_remove (plugin->msg_head, plugin->msg_tail, msgw);
+ if (msgw->cont != NULL)
+ msgw->cont (msgw->cont_cls, &msgw->session->target, GNUNET_SYSERR);
+ GNUNET_free (msgw->msg);
+ GNUNET_free (msgw);
+ }
+
+ if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->select_task);
+ plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ GNUNET_break (GNUNET_OK ==
+ GNUNET_NETWORK_socket_close (plugin->unix_sock.desc));
+ plugin->unix_sock.desc = NULL;
+ plugin->with_ws = GNUNET_NO;
+ return GNUNET_OK;
+}
+
+
+struct PeerSession *
+find_session (struct Plugin *plugin, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerSession *pos;
+
+ pos = plugin->sessions;
+ while (pos != NULL)
+ {
+ if (memcmp (&pos->target, peer, sizeof (struct GNUNET_PeerIdentity)) == 0)
+ return pos;
+ pos = pos->next;
+ }
+
+ return pos;
+}
+
+
+/**
+ * Actually send out the message, assume we've got the address and
+ * send_handle squared away!
+ *
+ * @param cls closure
+ * @param send_handle which handle to send message on
+ * @param target who should receive this message (ignored by UNIX)
+ * @param msgbuf one or more GNUNET_MessageHeader(s) strung together
+ * @param msgbuf_size the size of the msgbuf to send
+ * @param priority how important is the message (ignored by UNIX)
+ * @param timeout when should we time out (give up) if we can not transmit?
+ * @param addr the addr to send the message to, needs to be a sockaddr for us
+ * @param addrlen the len of addr
+ * @param cont continuation to call once the message has
+ * been transmitted (or if the transport is ready
+ * for the next transmission call; or if the
+ * peer disconnected...)
+ * @param cont_cls closure for cont
+ *
+ * @return the number of bytes written, -1 on errors
+ */
+static ssize_t
+unix_real_send (void *cls,
+ struct GNUNET_NETWORK_Handle *send_handle,
+ const struct GNUNET_PeerIdentity *target, const char *msgbuf,
+ size_t msgbuf_size, unsigned int priority,
+ struct GNUNET_TIME_Relative timeout, const void *addr,
+ size_t addrlen, GNUNET_TRANSPORT_TransmitContinuation cont,
+ void *cont_cls)
+{
+
+ ssize_t sent;
+ const void *sb;
+ size_t sbs;
+ struct sockaddr_un un;
+ size_t slen;
+ int retry;
+
+ if (send_handle == NULL)
+ {
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "unix_real_send with send_handle NULL!\n");
+#endif
+ /* failed to open send socket for AF */
+ if (cont != NULL)
+ cont (cont_cls, target, GNUNET_SYSERR);
+ return 0;
+ }
+ if ((addr == NULL) || (addrlen == 0))
+ {
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "unix_real_send called without address, returning!\n");
+#endif
+ if (cont != NULL)
+ cont (cont_cls, target, GNUNET_SYSERR);
+ return 0; /* Can never send if we don't have an address!! */
+ }
+
+ memset (&un, 0, sizeof (un));
+ un.sun_family = AF_UNIX;
+ slen = strlen (addr) + 1;
+ if (slen >= sizeof (un.sun_path))
+ slen = sizeof (un.sun_path) - 1;
+ sent = 0;
+ GNUNET_assert (slen < sizeof (un.sun_path));
+ memcpy (un.sun_path, addr, slen);
+ un.sun_path[slen] = '\0';
+ slen = sizeof (struct sockaddr_un);
+#if LINUX
+ un.sun_path[0] = '\0';
+#endif
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ un.sun_len = (u_char) slen;
+#endif
+ sb = (struct sockaddr *) &un;
+ sbs = slen;
+ retry = GNUNET_NO;
+ sent = GNUNET_NETWORK_socket_sendto (send_handle, msgbuf, msgbuf_size, sb, sbs);
+
+ if ((GNUNET_SYSERR == sent) && ((errno == EAGAIN) || (errno == ENOBUFS)))
+ retry = GNUNET_YES;
+
+ if ((GNUNET_SYSERR == sent) && (errno == EMSGSIZE))
+ {
+ socklen_t size = 0;
+ socklen_t len = sizeof (size);
+
+ GNUNET_NETWORK_socket_getsockopt ((struct GNUNET_NETWORK_Handle *)
+ send_handle, SOL_SOCKET, SO_SNDBUF, &size,
+ &len);
+
+ if (size < msgbuf_size)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Trying to increase socket buffer size from %i to %i for message size %i\n",
+ size, ((msgbuf_size / 1000) + 2) * 1000, msgbuf_size);
+ size = ((msgbuf_size / 1000) + 2) * 1000;
+ if (GNUNET_NETWORK_socket_setsockopt
+ ((struct GNUNET_NETWORK_Handle *) send_handle, SOL_SOCKET, SO_SNDBUF,
+ &size, sizeof (size)) == GNUNET_OK)
+ retry = GNUNET_YES;
+ else
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "setsockopt");
+ }
+ }
+
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "UNIX transmit %u-byte message to %s (%d: %s)\n",
+ (unsigned int) msgbuf_size, GNUNET_a2s (sb, sbs), (int) sent,
+ (sent < 0) ? STRERROR (errno) : "ok");
+#endif
+ /* Calling continuation */
+ if (cont != NULL)
+ {
+ if ((sent == GNUNET_SYSERR) && (retry == GNUNET_NO))
+ cont (cont_cls, target, GNUNET_SYSERR);
+ if (sent > 0)
+ cont (cont_cls, target, GNUNET_OK);
+ }
+
+ /* return number of bytes successfully sent */
+ if (sent > 0)
+ return sent;
+ /* failed and retry: return 0 */
+ if ((GNUNET_SYSERR == sent) && (retry == GNUNET_YES))
+ return 0;
+ /* failed and no retry: return -1 */
+ if ((GNUNET_SYSERR == sent) && (retry == GNUNET_NO))
+ return -1;
+
+ return sent;
+}
+
+struct gsi_ctx
+{
+ char *address;
+ size_t addrlen;
+ struct Session *res;
+};
+
+static int
+get_session_it (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct gsi_ctx *gsi = cls;
+ struct Session *s = value;
+
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Comparing session %s %s\n", gsi->address, s->addr);
+#endif
+ if ((gsi->addrlen == s->addrlen) &&
+ (0 == memcmp (gsi->address, s->addr, s->addrlen)))
+ {
+ gsi->res = s;
+ return GNUNET_NO;
+ }
+ return GNUNET_YES;
+}
+
+/**
+ * Creates a new outbound session the transport service will use to send data to the
+ * peer
+ *
+ * @param cls the plugin
+ * @param address the address
+ * @return the session or NULL of max connections exceeded
+ */
+static struct Session *
+unix_plugin_get_session (void *cls,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct Session * s = NULL;
+ struct Plugin *plugin = cls;
+ struct gsi_ctx gsi;
+
+ /* Checks */
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (address != NULL);
+
+ /* Check if already existing */
+ gsi.address = (char *) address->address;
+ gsi.addrlen = address->address_length;
+ gsi.res = NULL;
+ GNUNET_CONTAINER_multihashmap_get_multiple (plugin->session_map, &address->peer.hashPubKey, &get_session_it, &gsi);
+ if (gsi.res != NULL)
+ {
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Found existing session\n");
+#endif
+ return gsi.res;
+ }
+
+ /* Create a new session */
+
+ s = GNUNET_malloc (sizeof (struct Session) + address->address_length);
+ s->addr = &s[1];
+ s->addrlen = address->address_length;
+ memcpy(s->addr, address->address, s->addrlen);
+ memcpy(&s->target, &address->peer, sizeof (struct GNUNET_PeerIdentity));
+
+ GNUNET_CONTAINER_multihashmap_put (plugin->session_map,
+ &address->peer.hashPubKey, s,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_MULTIPLE);
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Creating new session\n");
+#endif
+
+ return s;
+}
+
+/*
+ * @param cls the plugin handle
+ * @param tc the scheduling context (for rescheduling this function again)
+ *
+ * We have been notified that our writeset has something to read. We don't
+ * know which socket needs to be read, so we have to check each one
+ * Then reschedule this function to be called again once more is available.
+ *
+ */
+static void
+unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+ * Function that can be used by the transport service to transmit
+ * a message using the plugin. Note that in the case of a
+ * peer disconnecting, the continuation MUST be called
+ * prior to the disconnect notification itself. This function
+ * will be called with this peer's HELLO message to initiate
+ * a fresh connection to another peer.
+ *
+ * @param cls closure
+ * @param session which session must be used
+ * @param msgbuf the message to transmit
+ * @param msgbuf_size number of bytes in 'msgbuf'
+ * @param priority how important is the message (most plugins will
+ * ignore message priority and just FIFO)
+ * @param to how long to wait at most for the transmission (does not
+ * require plugins to discard the message after the timeout,
+ * just advisory for the desired delay; most plugins will ignore
+ * this as well)
+ * @param cont continuation to call once the message has
+ * been transmitted (or if the transport is ready
+ * for the next transmission call; or if the
+ * peer disconnected...); can be NULL
+ * @param cont_cls closure for cont
+ * @return number of bytes used (on the physical network, with overheads);
+ * -1 on hard errors (i.e. address invalid); 0 is a legal value
+ * and does NOT mean that the message was not transmitted (DV)
+ */
+static ssize_t
+unix_plugin_send (void *cls,
+ struct Session *session,
+ const char *msgbuf, size_t msgbuf_size,
+ unsigned int priority,
+ struct GNUNET_TIME_Relative to,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct Plugin *plugin = cls;
+ struct UNIXMessageWrapper *wrapper;
+ struct UNIXMessage *message;
+ int ssize;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (session != NULL);
+
+ if (GNUNET_OK != GNUNET_CONTAINER_multihashmap_contains_value(plugin->session_map,
+ &session->target.hashPubKey, session))
+ {
+ GNUNET_break (0);
+ return GNUNET_SYSERR;
+ }
+
+ ssize = sizeof (struct UNIXMessage) + msgbuf_size;
+ message = GNUNET_malloc (sizeof (struct UNIXMessage) + msgbuf_size);
+ message->header.size = htons (ssize);
+ message->header.type = htons (0);
+ memcpy (&message->sender, plugin->env->my_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ memcpy (&message[1], msgbuf, msgbuf_size);
+
+ wrapper = GNUNET_malloc (sizeof (struct UNIXMessageWrapper));
+ wrapper->msg = message;
+ wrapper->msgsize = ssize;
+ wrapper->priority = priority;
+ wrapper->timeout = to;
+ wrapper->cont = cont;
+ wrapper->cont_cls = cont_cls;
+ wrapper->session = session;
+
+ GNUNET_CONTAINER_DLL_insert(plugin->msg_head, plugin->msg_tail, wrapper);
+
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sent %d bytes to `%s'\n", ssize,
+ (char *) session->addr);
+#endif
+
+ if (plugin->with_ws == GNUNET_NO)
+ {
+ if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel(plugin->select_task);
+
+ plugin->select_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs,
+ plugin->ws,
+ &unix_plugin_select, plugin);
+ plugin->with_ws = GNUNET_YES;
+ }
+ return ssize;
+}
+
+
+/**
+ * Demultiplexer for UNIX messages
+ *
+ * @param plugin the main plugin for this transport
+ * @param sender from which peer the message was received
+ * @param currhdr pointer to the header of the message
+ * @param un the address from which the message was received
+ * @param fromlen the length of the address
+ */
+static void
+unix_demultiplexer (struct Plugin *plugin, struct GNUNET_PeerIdentity *sender,
+ const struct GNUNET_MessageHeader *currhdr,
+ const struct sockaddr_un *un, size_t fromlen)
+{
+ struct GNUNET_ATS_Information ats[2];
+
+ ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
+ ats[0].value = htonl (UNIX_DIRECT_DISTANCE);
+ ats[1] = plugin->ats_network;
+ GNUNET_break (ntohl(plugin->ats_network.value) != GNUNET_ATS_NET_UNSPECIFIED);
+
+ GNUNET_assert (fromlen >= sizeof (struct sockaddr_un));
+
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Received message from %s\n",
+ un->sun_path);
+#endif
+ plugin->env->receive (plugin->env->cls, sender, currhdr,
+ (const struct GNUNET_ATS_Information *) &ats, 2,
+ NULL, un->sun_path, strlen (un->sun_path) + 1);
+}
+
+
+static void
+unix_plugin_select_read (struct Plugin * plugin)
+{
+ char buf[65536];
+ struct UNIXMessage *msg;
+ struct GNUNET_PeerIdentity sender;
+ struct sockaddr_un un;
+ socklen_t addrlen;
+ ssize_t ret;
+ int offset;
+ int tsize;
+ char *msgbuf;
+ const struct GNUNET_MessageHeader *currhdr;
+ uint16_t csize;
+
+ addrlen = sizeof (un);
+ memset (&un, 0, sizeof (un));
+
+ ret =
+ GNUNET_NETWORK_socket_recvfrom (plugin->unix_sock.desc, buf, sizeof (buf),
+ (struct sockaddr *) &un, &addrlen);
+
+ if ((GNUNET_SYSERR == ret) && ((errno == EAGAIN) || (errno == ENOBUFS)))
+ return;
+
+ if (ret == GNUNET_SYSERR)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "recvfrom");
+ return;
+ }
+ else
+ {
+#if LINUX
+ un.sun_path[0] = '/';
+#endif
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Read %d bytes from socket %s\n", ret,
+ &un.sun_path[0]);
+#endif
+ }
+
+ GNUNET_assert (AF_UNIX == (un.sun_family));
+
+ msg = (struct UNIXMessage *) buf;
+ csize = ntohs (msg->header.size);
+ if ((csize < sizeof (struct UNIXMessage)) || (csize > ret))
+ {
+ GNUNET_break_op (0);
+ return;
+ }
+ msgbuf = (char *) &msg[1];
+ memcpy (&sender, &msg->sender, sizeof (struct GNUNET_PeerIdentity));
+ offset = 0;
+ tsize = csize - sizeof (struct UNIXMessage);
+ while (offset + sizeof (struct GNUNET_MessageHeader) <= tsize)
+ {
+ currhdr = (struct GNUNET_MessageHeader *) &msgbuf[offset];
+ csize = ntohs (currhdr->size);
+ if ((csize < sizeof (struct GNUNET_MessageHeader)) ||
+ (csize > tsize - offset))
+ {
+ GNUNET_break_op (0);
+ break;
+ }
+ unix_demultiplexer (plugin, &sender, currhdr, &un, sizeof (un));
+ offset += csize;
+ }
+}
+
+static void
+unix_plugin_select_write (struct Plugin * plugin)
+{
+ int sent = 0;
+ struct UNIXMessageWrapper * msgw = plugin->msg_head;
+
+ sent = unix_real_send (plugin,
+ plugin->unix_sock.desc,
+ &msgw->session->target,
+ (const char *) msgw->msg,
+ msgw->msgsize,
+ msgw->priority,
+ msgw->timeout,
+ msgw->session->addr,
+ msgw->session->addrlen,
+ msgw->cont, msgw->cont_cls);
+
+ /* successfully sent bytes */
+ if (sent > 0)
+ {
+ GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
+ GNUNET_free (msgw->msg);
+ GNUNET_free (msgw);
+ return;
+ }
+
+ /* failed and no retry */
+ if (sent == -1)
+ {
+ GNUNET_CONTAINER_DLL_remove(plugin->msg_head, plugin->msg_tail, msgw);
+ GNUNET_free (msgw->msg);
+ GNUNET_free (msgw);
+ return;
+ }
+
+ /* failed and retry */
+ if (sent == 0)
+ return;
+}
+
+/*
+ * @param cls the plugin handle
+ * @param tc the scheduling context (for rescheduling this function again)
+ *
+ * We have been notified that our writeset has something to read. We don't
+ * know which socket needs to be read, so we have to check each one
+ * Then reschedule this function to be called again once more is available.
+ *
+ */
+static void
+unix_plugin_select (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ plugin->select_task = GNUNET_SCHEDULER_NO_TASK;
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+
+ plugin->with_ws = GNUNET_NO;
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_WRITE_READY) != 0)
+ {
+ GNUNET_assert (GNUNET_NETWORK_fdset_isset
+ (tc->write_ready, plugin->unix_sock.desc));
+ if (plugin->msg_head != NULL)
+ unix_plugin_select_write (plugin);
+ }
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_READ_READY) != 0)
+ {
+ GNUNET_assert (GNUNET_NETWORK_fdset_isset
+ (tc->read_ready, plugin->unix_sock.desc));
+ unix_plugin_select_read (plugin);
+ }
+
+ if (plugin->select_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (plugin->select_task);
+ plugin->select_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs,
+ (plugin->msg_head != NULL) ? plugin->ws : NULL,
+ &unix_plugin_select, plugin);
+ if (plugin->msg_head != NULL)
+ plugin->with_ws = GNUNET_YES;
+}
+
+/**
+ * Create a slew of UNIX sockets. If possible, use IPv6 and IPv4.
+ *
+ * @param cls closure for server start, should be a struct Plugin *
+ * @return number of sockets created or GNUNET_SYSERR on error
+*/
+static int
+unix_transport_server_start (void *cls)
+{
+ struct Plugin *plugin = cls;
+ struct sockaddr *serverAddr;
+ socklen_t addrlen;
+ struct sockaddr_un un;
+ size_t slen;
+
+ memset (&un, 0, sizeof (un));
+ un.sun_family = AF_UNIX;
+ slen = strlen (plugin->unix_socket_path) + 1;
+ if (slen >= sizeof (un.sun_path))
+ slen = sizeof (un.sun_path) - 1;
+
+ memcpy (un.sun_path, plugin->unix_socket_path, slen);
+ un.sun_path[slen] = '\0';
+ slen = sizeof (struct sockaddr_un);
+#if HAVE_SOCKADDR_IN_SIN_LEN
+ un.sun_len = (u_char) slen;
+#endif
+
+ serverAddr = (struct sockaddr *) &un;
+ addrlen = slen;
+#if LINUX
+ un.sun_path[0] = '\0';
+#endif
+ plugin->ats_network = plugin->env->get_address_type (plugin->env->cls, serverAddr, addrlen);
+ plugin->unix_sock.desc =
+ GNUNET_NETWORK_socket_create (AF_UNIX, SOCK_DGRAM, 0);
+ if (NULL == plugin->unix_sock.desc)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "socket");
+ return GNUNET_SYSERR;
+ }
+ if (GNUNET_NETWORK_socket_bind (plugin->unix_sock.desc, serverAddr, addrlen)
+ != GNUNET_OK)
+ {
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_ERROR, "bind");
+ GNUNET_NETWORK_socket_close (plugin->unix_sock.desc);
+ plugin->unix_sock.desc = NULL;
+ return GNUNET_SYSERR;
+ }
+#if DEBUG_UNIX
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "unix", "Bound to `%s'\n",
+ &un.sun_path[0]);
+#endif
+ plugin->rs = GNUNET_NETWORK_fdset_create ();
+ plugin->ws = GNUNET_NETWORK_fdset_create ();
+ GNUNET_NETWORK_fdset_zero (plugin->rs);
+ GNUNET_NETWORK_fdset_zero (plugin->ws);
+ GNUNET_NETWORK_fdset_set (plugin->rs, plugin->unix_sock.desc);
+ GNUNET_NETWORK_fdset_set (plugin->ws, plugin->unix_sock.desc);
+
+ plugin->select_task =
+ GNUNET_SCHEDULER_add_select (GNUNET_SCHEDULER_PRIORITY_DEFAULT,
+ GNUNET_SCHEDULER_NO_TASK,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->rs,
+ NULL,
+ &unix_plugin_select, plugin);
+ plugin->with_ws = GNUNET_NO;
+
+ return 1;
+}
+
+
+/**
+ * Function that will be called to check if a binary address for this
+ * plugin is well-formed and corresponds to an address for THIS peer
+ * (as per our configuration). Naturally, if absolutely necessary,
+ * plugins can be a bit conservative in their answer, but in general
+ * plugins should make sure that the address does not redirect
+ * traffic to a 3rd party that might try to man-in-the-middle our
+ * traffic.
+ *
+ * @param cls closure, should be our handle to the Plugin
+ * @param addr pointer to the address
+ * @param addrlen length of addr
+ * @return GNUNET_OK if this is a plausible address for this peer
+ * and transport, GNUNET_SYSERR if not
+ *
+ */
+static int
+unix_check_address (void *cls, const void *addr, size_t addrlen)
+{
+
+#if DEBUG_UNIX
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Informing transport service about my address `%s'\n",
+ (char *) addr);
+#endif
+ return GNUNET_OK;
+}
+
+
+/**
+ * Convert the transports address to a nice, human-readable
+ * format.
+ *
+ * @param cls closure
+ * @param type name of the transport that generated the address
+ * @param addr one of the addresses of the host, NULL for the last address
+ * the specific address format depends on the transport
+ * @param addrlen length of the address
+ * @param numeric should (IP) addresses be displayed in numeric form?
+ * @param timeout after how long should we give up?
+ * @param asc function to call on each string
+ * @param asc_cls closure for asc
+ */
+static void
+unix_plugin_address_pretty_printer (void *cls, const char *type,
+ const void *addr, size_t addrlen,
+ int numeric,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_AddressStringCallback asc,
+ void *asc_cls)
+{
+ if ((addr != NULL) && (addrlen > 0))
+ asc (asc_cls, (const char *) addr);
+ else
+ {
+ GNUNET_break (0);
+ asc (asc_cls, "Invalid UNIX address");
+ }
+
+}
+
+/**
+ * Function called for a quick conversion of the binary address to
+ * a numeric address. Note that the caller must not free the
+ * address and that the next call to this function is allowed
+ * to override the address again.
+ *
+ * @param cls closure
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return string representing the same address
+ */
+static const char *
+unix_address_to_string (void *cls, const void *addr, size_t addrlen)
+{
+ if ((addr != NULL) && (addrlen > 0))
+ return (const char *) addr;
+ else
+ return NULL;
+}
+
+/**
+ * Notify transport service about address
+ *
+ * @param cls the plugin
+ * @param tc unused
+ */
+static void
+address_notification (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ plugin->env->notify_address (plugin->env->cls, GNUNET_YES,
+ plugin->unix_socket_path,
+ strlen (plugin->unix_socket_path) + 1);
+}
+
+/**
+ * The exported method. Makes the core api available via a global and
+ * returns the unix transport API.
+ */
+void *
+libgnunet_plugin_transport_unix_init (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
+ unsigned long long port;
+ struct GNUNET_TRANSPORT_PluginFunctions *api;
+ struct Plugin *plugin;
+ int sockets_created;
+
+ if (GNUNET_OK !=
+ GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-unix", "PORT",
+ &port))
+ port = UNIX_NAT_DEFAULT_PORT;
+ plugin = GNUNET_malloc (sizeof (struct Plugin));
+ plugin->port = port;
+ plugin->env = env;
+ GNUNET_asprintf (&plugin->unix_socket_path, "/tmp/unix-plugin-sock.%d",
+ plugin->port);
+
+ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
+ api->cls = plugin;
+
+ api->get_session = &unix_plugin_get_session;
+ api->send = &unix_plugin_send;
+ api->disconnect = &unix_disconnect;
+ api->address_pretty_printer = &unix_plugin_address_pretty_printer;
+ api->address_to_string = &unix_address_to_string;
+ api->check_address = &unix_check_address;
+ sockets_created = unix_transport_server_start (plugin);
+ if (sockets_created == 0)
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, _("Failed to open UNIX sockets\n"));
+
+ plugin->session_map = GNUNET_CONTAINER_multihashmap_create(10);
+
+ GNUNET_SCHEDULER_add_now (address_notification, plugin);
+ return api;
+}
+
+void *
+libgnunet_plugin_transport_unix_done (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
+ struct Plugin *plugin = api->cls;
+
+ unix_transport_server_stop (plugin);
+
+ GNUNET_CONTAINER_multihashmap_iterate (plugin->session_map, &get_session_delete_it, plugin);
+ GNUNET_CONTAINER_multihashmap_destroy (plugin->session_map);
+
+ GNUNET_NETWORK_fdset_destroy (plugin->rs);
+ GNUNET_NETWORK_fdset_destroy (plugin->ws);
+ GNUNET_free (plugin->unix_socket_path);
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+ return NULL;
+}
+
+/* end of plugin_transport_unix.c */
diff --git a/src/transport/plugin_transport_wlan.c b/src/transport/plugin_transport_wlan.c
new file mode 100644
index 0000000..08f9c58
--- /dev/null
+++ b/src/transport/plugin_transport_wlan.c
@@ -0,0 +1,3201 @@
+/*
+ This file is part of GNUnet
+ (C) 2010 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file transport/plugin_transport_wlan.c
+ * @brief transport plugin for wlan
+ * @author David Brodski
+ */
+
+//TODO split rx and tx structures for better handling
+
+#include "platform.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_util_lib.h"
+#include "gnunet_statistics_service.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_transport_plugin.h"
+#include "plugin_transport_wlan.h"
+#include "gnunet_common.h"
+#include "gnunet_crypto_lib.h"
+#include "gnunet_fragmentation_lib.h"
+#include "gnunet_constants.h"
+
+/**
+ * DEBUG switch
+ */
+#define DEBUG_WLAN GNUNET_EXTRA_LOGGING
+
+
+#define PROTOCOL_PREFIX "wlan"
+
+#define PLUGIN_LOG_NAME "wlan-plugin"
+
+/**
+ * Max size of packet
+ */
+#define WLAN_MTU 1430
+
+/**
+ * time out of a session
+ */
+#define SESSION_TIMEOUT GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT
+
+/**
+ * time out of a mac endpoint
+ */
+#define MACENDPOINT_TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_CONSTANTS_IDLE_CONNECTION_TIMEOUT, 2)
+
+/**
+ * scaling factor for hello beacon
+ */
+#define HELLO_BEACON_SCALING_FACTOR 30
+
+/**
+ * scaling factor for restarting the helper
+ */
+#define HELPER_RESTART_SCALING_FACTOR 2
+
+/**
+ * max size of fragment queue
+ */
+#define FRAGMENT_QUEUE_SIZE 10
+/**
+ * max messages in fragment queue per session/client
+ */
+#define FRAGMENT_QUEUE_MESSAGES_OUT_PER_SESSION 1
+
+/**
+ * max messages in fragment queue per MAC
+ */
+#define FRAGMENT_QUEUE_MESSAGES_OUT_PER_MACENDPOINT 1
+
+/**
+ * max messages in in queue
+ */
+#define MESSAGES_IN_QUEUE_SIZE 10
+/**
+ * max messages in in queue per session/client
+ */
+#define MESSAGES_IN_DEFRAG_QUEUE_PER_MAC 1
+
+/**
+ * LLC fields for better compatibility
+ */
+#define WLAN_LLC_DSAP_FIELD 0x1f
+#define WLAN_LLC_SSAP_FIELD 0x1f
+
+
+#define IEEE80211_ADDR_LEN 6 /* size of 802.11 address */
+
+#define IEEE80211_FC0_VERSION_MASK 0x03
+#define IEEE80211_FC0_VERSION_SHIFT 0
+#define IEEE80211_FC0_VERSION_0 0x00
+#define IEEE80211_FC0_TYPE_MASK 0x0c
+#define IEEE80211_FC0_TYPE_SHIFT 2
+#define IEEE80211_FC0_TYPE_MGT 0x00
+#define IEEE80211_FC0_TYPE_CTL 0x04
+#define IEEE80211_FC0_TYPE_DATA 0x08
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/*
+ * generic definitions for IEEE 802.11 frames
+ */
+struct ieee80211_frame
+{
+ u_int8_t i_fc[2];
+ u_int8_t i_dur[2];
+ u_int8_t i_addr1[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr2[IEEE80211_ADDR_LEN];
+ u_int8_t i_addr3[IEEE80211_ADDR_LEN];
+ u_int8_t i_seq[2];
+ u_int8_t llc[4];
+} GNUNET_PACKED;
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * Encapsulation of all of the state of the plugin.
+ */
+struct Plugin
+{
+ /**
+ * Our environment.
+ */
+ struct GNUNET_TRANSPORT_PluginEnvironment *env;
+
+ /**
+ * List of open connections. head
+ */
+ struct MacEndpoint *mac_head;
+
+ /**
+ * List of open connections. tail
+ */
+ struct MacEndpoint *mac_tail;
+
+ /**
+ * Number of connections
+ */
+ unsigned int mac_count;
+
+ /**
+ * encapsulation of data from the local wlan helper program
+ */
+ struct GNUNET_SERVER_MessageStreamTokenizer *suid_tokenizer;
+
+ /**
+ * encapsulation of packets received from the wlan helper
+ */
+ struct GNUNET_SERVER_MessageStreamTokenizer *data_tokenizer;
+
+ /**
+ * stdout pipe handle for the gnunet-helper-transport-wlan process
+ */
+ struct GNUNET_DISK_PipeHandle *server_stdout;
+
+ /**
+ * stdout file handle for the gnunet-helper-transport-wlan process
+ */
+ const struct GNUNET_DISK_FileHandle *server_stdout_handle;
+
+ /**
+ * stdin pipe handle for the gnunet-helper-transport-wlan process
+ */
+ struct GNUNET_DISK_PipeHandle *server_stdin;
+
+ /**
+ * stdin file handle for the gnunet-helper-transport-wlan process
+ */
+ const struct GNUNET_DISK_FileHandle *server_stdin_handle;
+
+ /**
+ * ID of the gnunet-wlan-server std read task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier server_read_task;
+
+ /**
+ * ID of the gnunet-wlan-server std read task
+ */
+ GNUNET_SCHEDULER_TaskIdentifier server_write_task;
+
+ /**
+ * ID of the delay task for writing
+ */
+ GNUNET_SCHEDULER_TaskIdentifier server_write_delay_task;
+
+ /**
+ * The process id of the wlan process
+ */
+ struct GNUNET_OS_Process *server_proc;
+
+ /**
+ * The interface of the wlan card given to us by the user.
+ */
+ char *interface;
+
+ /**
+ * Mode of operation for the helper, 0 = normal, 1 = first loopback, 2 = second loopback
+ */
+ long long unsigned int testmode;
+
+ /**
+ * The mac_address of the wlan card given to us by the helper.
+ */
+ struct GNUNET_TRANSPORT_WLAN_MacAddress mac_address;
+
+ /**
+ * Sessions currently pending for transmission
+ * to a peer, if any.
+ */
+ struct Sessionqueue *pending_Sessions_head;
+
+ /**
+ * Sessions currently pending for transmission
+ * to a peer (tail), if any.
+ */
+ struct Sessionqueue *pending_Sessions_tail;
+
+ /**
+ * number of pending sessions
+ */
+ unsigned int pendingsessions;
+
+ /**
+ * Messages in the sending queues
+ */
+ int pending_Fragment_Messages;
+
+ /**
+ * messages ready for send, head
+ */
+ struct FragmentMessage_queue *sending_messages_head;
+ /**
+ * messages ready for send, tail
+ */
+ struct FragmentMessage_queue *sending_messages_tail;
+ /**
+ * time of the next "hello-beacon"
+ */
+ struct GNUNET_TIME_Absolute beacon_time;
+
+ /**
+ * queue to send acks for received fragments (head)
+ */
+ struct AckSendQueue *ack_send_queue_head;
+
+ /**
+ * queue to send acks for received fragments (tail)
+ */
+ struct AckSendQueue *ack_send_queue_tail;
+
+ /**
+ * Tracker for bandwidth limit
+ */
+ struct GNUNET_BANDWIDTH_Tracker tracker;
+
+ /**
+ * saves the current state of the helper process
+ */
+ int helper_is_running;
+};
+
+/**
+ * Struct to store data if file write did not accept the whole packet
+ */
+struct Finish_send
+{
+ /**
+ * pointer to the global plugin struct
+ */
+ struct Plugin *plugin;
+
+ /**
+ * head of the next part to send to the helper
+ */
+ char *head_of_next_write;
+
+ /**
+ * Start of the message to send, needed for free
+ */
+ struct GNUNET_MessageHeader *msgstart;
+
+ /**
+ * rest size to send
+ */
+ ssize_t size;
+};
+
+/**
+ * Queue of sessions, for the general session queue and the pending session queue
+ */
+//TODO DOXIGEN
+struct Sessionqueue
+{
+ struct Sessionqueue *next;
+ struct Sessionqueue *prev;
+ struct Session *content;
+#if !HAVE_UNALIGNED_64_ACCESS
+ void *dummy; /* for alignment, see #1909 */
+#endif
+};
+
+/**
+ * Queue of fragmented messages, for the sending queue of the plugin
+ */
+//TODO DOXIGEN
+struct FragmentMessage_queue
+{
+ struct FragmentMessage_queue *next;
+ struct FragmentMessage_queue *prev;
+ struct FragmentMessage *content;
+};
+
+/**
+ * Queue for the fragments received
+ */
+//TODO DOXIGEN
+struct Receive_Fragment_Queue
+{
+ struct Receive_Fragment_Queue *next;
+ struct Receive_Fragment_Queue *prev;
+ uint16_t num;
+ const char *msg;
+ uint16_t size;
+ struct Radiotap_rx rxinfo;
+};
+
+//TODO DOXIGEN
+struct MacEndpoint_id_fragment_triple
+{
+ struct MacEndpoint *endpoint;
+ uint32_t message_id;
+ struct FragmentMessage *fm;
+};
+
+//TODO DOXIGEN
+struct Plugin_Session_pair
+{
+ struct Plugin *plugin;
+ struct Session *session;
+};
+
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Header for messages which need fragmentation
+ */
+struct WlanHeader
+{
+
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * checksum/error correction
+ */
+ uint32_t crc GNUNET_PACKED;
+
+ /**
+ * To whom are we talking to (set to our identity
+ * if we are still waiting for the welcome message)
+ */
+ struct GNUNET_PeerIdentity target;
+
+ /**
+ * Where the packet came from
+ */
+ struct GNUNET_PeerIdentity source;
+
+// followed by payload
+
+};
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * Information kept for each message that is yet to
+ * be transmitted.
+ */
+struct PendingMessage
+{
+ /**
+ * dll next
+ */
+ struct PendingMessage *next;
+ /**
+ * dll prev
+ */
+ struct PendingMessage *prev;
+
+ /**
+ * The pending message
+ */
+ struct WlanHeader *msg;
+
+ /**
+ * Size of the message
+ */
+ size_t message_size;
+
+ /**
+ * Continuation function to call once the message
+ * has been sent. Can be NULL if there is no
+ * continuation to call.
+ */
+ GNUNET_TRANSPORT_TransmitContinuation transmit_cont;
+
+ /**
+ * Cls for transmit_cont
+ */
+ void *transmit_cont_cls;
+
+ /**
+ * Timeout value for the pending message.
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+};
+
+/**
+ * Queue for acks to send for fragments recived
+ */
+struct AckSendQueue
+{
+
+ /**
+ * next ack in the ack send queue
+ */
+ struct AckSendQueue *next;
+ /**
+ * previous ack in the ack send queue
+ */
+ struct AckSendQueue *prev;
+ /**
+ * pointer to the session this ack belongs to
+ */
+ struct MacEndpoint *endpoint;
+ /**
+ * ID of message, to distinguish between the messages, picked randomly.
+ */
+ uint32_t message_id;
+
+ /**
+ * msg to send
+ */
+ struct GNUNET_MessageHeader *hdr;
+ /**
+ * pointer to the ieee wlan header
+ */
+ struct ieee80211_frame *ieeewlanheader;
+ /**
+ * pointer to the radiotap header
+ */
+ struct Radiotap_Send *radioHeader;
+};
+
+/**
+ * Session infos gathered from a messages
+ */
+struct Session_light
+{
+ /**
+ * the session this message belongs to
+ */
+ struct Session *session;
+ /**
+ * peer mac address
+ */
+ struct GNUNET_TRANSPORT_WLAN_MacAddress addr;
+
+ /**
+ * mac endpoint
+ */
+ struct MacEndpoint *macendpoint;
+};
+
+/**
+ * Session handle for connections.
+ */
+struct Session
+{
+
+ /**
+ * API requirement.
+ */
+ struct SessionHeader header;
+
+ /**
+ * Message currently pending for transmission
+ * to this peer, if any. head
+ */
+ struct PendingMessage *pending_message_head;
+
+ /**
+ * Message currently pending for transmission
+ * to this peer, if any. tail
+ */
+ struct PendingMessage *pending_message_tail;
+
+ /**
+ * To whom are we talking to (set to our identity
+ * if we are still waiting for the welcome message)
+ */
+ struct GNUNET_PeerIdentity target;
+
+ /**
+ * Address of the other peer (either based on our 'connect'
+ * call or on our 'accept' call).
+ */
+ void *connect_addr;
+
+ /**
+ * Last activity on this connection. Used to select preferred
+ * connection and timeout
+ */
+ struct GNUNET_TIME_Absolute last_activity;
+
+ /**
+ * Timeout task.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * peer connection
+ */
+ struct MacEndpoint *mac;
+
+ /**
+ * count of messages in the fragment out queue for this session
+ */
+
+ int fragment_messages_out_count;
+
+};
+
+/**
+ * Struct to represent one network card connection
+ */
+struct MacEndpoint
+{
+ /**
+ * Pointer to the global plugin struct.
+ */
+ struct Plugin *plugin;
+ /**
+ * Struct to hold the session reachable over this mac; head
+ */
+ struct Sessionqueue *sessions_head;
+ /**
+ * Struct to hold the session reachable over this mac; tail
+ */
+ struct Sessionqueue *sessions_tail;
+ /**
+ * Messages currently sending
+ * to a peer, if any.
+ */
+ struct FragmentMessage *sending_messages_head;
+
+ /**
+ * Messages currently sending
+ * to a peer (tail), if any.
+ */
+ struct FragmentMessage *sending_messages_tail;
+ /**
+ * dll next
+ */
+ struct MacEndpoint *next;
+ /**
+ * dll prev
+ */
+ struct MacEndpoint *prev;
+
+ /**
+ * peer mac address
+ */
+ struct GNUNET_TRANSPORT_WLAN_MacAddress addr;
+
+ /**
+ * Defrag context for this mac endpoint
+ */
+ struct GNUNET_DEFRAGMENT_Context *defrag;
+
+ /**
+ * count of messages in the fragment out queue for this mac endpoint
+ */
+
+ int fragment_messages_out_count;
+
+ //TODO DOXIGEN
+ uint8_t rate;
+ uint16_t tx_power;
+ uint8_t antenna;
+
+ /**
+ * Duplicates received
+ */
+ int dups;
+
+ /**
+ * Fragments received
+ */
+ int fragc;
+
+ /**
+ * Acks received
+ */
+ int acks;
+
+ /**
+ * Last activity on this endpoint. Used to select preferred
+ * connection.
+ */
+ struct GNUNET_TIME_Absolute last_activity;
+
+ /**
+ * Timeout task.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+};
+
+/**
+ * Struct for Messages in the fragment queue
+ */
+struct FragmentMessage
+{
+
+ /**
+ * Session this message belongs to
+ */
+ struct Session *session;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct FragmentMessage *next;
+
+ /**
+ * This is a doubly-linked list.
+ */
+ struct FragmentMessage *prev;
+
+ /**
+ * Fragmentation context
+ */
+ struct GNUNET_FRAGMENT_Context *fragcontext;
+
+ /**
+ * Timeout value for the message.
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * Timeout task.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * Fragment to send
+ */
+ char *frag;
+
+ /**
+ * size of message
+ */
+ size_t size;
+
+ /**
+ * pointer to the ieee wlan header
+ */
+ struct ieee80211_frame *ieeewlanheader;
+ /**
+ * pointer to the radiotap header
+ */
+ struct Radiotap_Send *radioHeader;
+};
+
+static void
+do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+static void
+free_session (struct Plugin *plugin, struct Sessionqueue *queue,
+ int do_free_macendpoint);
+
+static struct MacEndpoint *
+create_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr);
+
+static void
+finish_sending (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc);
+
+/**
+ * Generates a nice hexdump of a memory area.
+ *
+ * \param mem pointer to memory to dump
+ * \param length how many bytes to dump
+ */
+static void
+hexdump (const void *mem, unsigned length)
+{
+ char line[80];
+ char *src = (char *) mem;
+
+ printf ("dumping %u bytes from %p\r\n"
+ " 0 1 2 3 4 5 6 7 8 9 A B C D E F 0123456789ABCDEF\r\n",
+ length, src);
+ unsigned i;
+ int j;
+
+ for (i = 0; i < length; i += 16, src += 16)
+ {
+ char *t = line;
+
+ t += sprintf (t, "%04x: ", i);
+ for (j = 0; j < 16; j++)
+ {
+ if (i + j < length)
+ t += sprintf (t, "%02X", src[j] & 0xff);
+ else
+ t += sprintf (t, " ");
+
+ t += sprintf (t, (j % 2) ? " " : "-");
+ }
+
+ t += sprintf (t, " ");
+ for (j = 0; j < 16; j++)
+ {
+ if (i + j < length)
+ {
+ if (isprint ((unsigned char) src[j]))
+ t += sprintf (t, "%c", src[j]);
+ else
+ t += sprintf (t, ".");
+ }
+ else
+ {
+ t += sprintf (t, " ");
+ }
+ }
+
+ t += sprintf (t, "\r\n");
+ printf ("%s", line);
+ }
+}
+
+/**
+ * Function to find a MacEndpoint with a specific mac addr
+ * @param plugin pointer to the plugin struct
+ * @param addr pointer to the mac address
+ * @param create_new GNUNET_YES if a new end point should be created
+ * @return
+ */
+static struct MacEndpoint *
+get_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr,
+ int create_new)
+{
+ struct MacEndpoint *queue = plugin->mac_head;
+
+ while (queue != NULL)
+ {
+ //GNUNET_assert (queue->sessions_head != NULL);
+ if (memcmp (addr, &queue->addr, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
+ return queue; /* session found */
+ queue = queue->next;
+ }
+
+ if (create_new == GNUNET_YES)
+ {
+ return create_macendpoint (plugin, addr);
+ }
+ else
+ {
+ return NULL;
+ }
+
+}
+
+/**
+ * search for a session with the macendpoint and peer id
+ *
+ * @param plugin pointer to the plugin struct
+ * @param endpoint pointer to the mac endpoint of the peer
+ * @param peer pointer to the peerid
+ * @return returns the session
+ */
+static struct Session *
+search_session (struct Plugin *plugin, const struct MacEndpoint *endpoint,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_assert (endpoint != NULL);
+ struct Sessionqueue *queue = endpoint->sessions_head;
+
+ while (queue != NULL)
+ {
+ GNUNET_assert (queue->content != NULL);
+ if (memcmp
+ (peer, &queue->content->target,
+ sizeof (struct GNUNET_PeerIdentity)) == 0)
+ return queue->content; /* session found */
+ queue = queue->next;
+ }
+ return NULL;
+}
+
+/**
+ * Function called for a quick conversion of the binary address to
+ * a numeric address. Note that the caller must not free the
+ * address and that the next call to this function is allowed
+ * to override the address again.
+ *
+ * @param cls closure
+ * @param addr binary address
+ * @param addrlen length of the address
+ * @return string representing the same address
+ */
+static const char *
+wlan_plugin_address_to_string (void *cls, const void *addr, size_t addrlen)
+{
+ static char ret[40];
+ const struct GNUNET_TRANSPORT_WLAN_MacAddress *mac;
+
+ if (addrlen != sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+ mac = addr;
+ GNUNET_snprintf (ret, sizeof (ret), "%s Mac-Address %X:%X:%X:%X:%X:%X",
+ PROTOCOL_PREFIX, mac->mac[0], mac->mac[1], mac->mac[2],
+ mac->mac[3], mac->mac[4], mac->mac[5]);
+
+ return ret;
+}
+
+/**
+ * Function for the scheduler if a session times out
+ * @param cls pointer to the Sessionqueue
+ * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
+ */
+static void
+session_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Sessionqueue *queue = cls;
+
+ GNUNET_assert (queue != NULL);
+ GNUNET_assert (queue->content != NULL);
+ queue->content->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+ {
+ return;
+ }
+ if (GNUNET_TIME_absolute_get_remaining
+ (GNUNET_TIME_absolute_add
+ (queue->content->last_activity, SESSION_TIMEOUT)).rel_value == 0)
+ {
+
+ GNUNET_assert (queue->content->mac != NULL);
+ GNUNET_assert (queue->content->mac->plugin != NULL);
+ GNUNET_STATISTICS_update (queue->content->mac->plugin->env->stats,
+ _("# wlan session timeouts"), 1, GNUNET_NO);
+ free_session (queue->content->mac->plugin, queue, GNUNET_YES);
+ }
+ else
+ {
+ queue->content->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (SESSION_TIMEOUT, &session_timeout, queue);
+ }
+}
+
+/**
+ * create a new session
+ *
+ * @param plugin pointer to the plugin struct
+ * @param endpoint pointer to the mac endpoint of the peer
+ * @param peer peer identity to use for this session
+ * @return returns the session
+ */
+static struct Session *
+create_session (struct Plugin *plugin, struct MacEndpoint *endpoint,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_assert (endpoint != NULL);
+ GNUNET_assert (plugin != NULL);
+ GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan session created"), 1,
+ GNUNET_NO);
+ struct Sessionqueue *queue =
+ GNUNET_malloc (sizeof (struct Sessionqueue) + sizeof (struct Session));
+
+ GNUNET_CONTAINER_DLL_insert_tail (endpoint->sessions_head,
+ endpoint->sessions_tail, queue);
+
+ queue->content = (struct Session *) &queue[1];
+ queue->content->mac = endpoint;
+ queue->content->target = *peer;
+ queue->content->last_activity = GNUNET_TIME_absolute_get ();
+ queue->content->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (SESSION_TIMEOUT, &session_timeout, queue);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "New session %p with endpoint %p: %s\n", queue->content,
+ endpoint, wlan_plugin_address_to_string (NULL,
+ endpoint->addr.mac,
+ 6));
+ return queue->content;
+}
+
+/**
+ * Get session from address, create if no session exists
+ *
+ * @param plugin pointer to the plugin struct
+ * @param addr pointer to the mac address of the peer
+ * @param peer pointer to the peerid
+ * @return returns the session
+ */
+static struct Session *
+get_session (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ struct MacEndpoint *mac;
+
+ mac = get_macendpoint (plugin, addr, GNUNET_YES);
+ struct Session *session = search_session (plugin, mac, peer);
+
+ if (session != NULL)
+ return session;
+ return create_session (plugin, mac, peer);
+}
+
+/**
+ * Queue the session to send data
+ * checks if there is a message pending
+ * checks if this session is not allready in the queue
+ * @param plugin pointer to the plugin
+ * @param session pointer to the session to add
+ */
+static void
+queue_session (struct Plugin *plugin, struct Session *session)
+{
+ struct Sessionqueue *queue = plugin->pending_Sessions_head;
+
+ if (session->pending_message_head != NULL)
+ {
+ while (queue != NULL)
+ {
+ // content is never NULL
+ GNUNET_assert (queue->content != NULL);
+ // is session already in queue?
+ if (session == queue->content)
+ {
+ return;
+ }
+ // try next
+ queue = queue->next;
+ }
+
+ // Session is not in the queue
+
+ queue = GNUNET_malloc (sizeof (struct Sessionqueue));
+ queue->content = session;
+
+ //insert at the tail
+ GNUNET_CONTAINER_DLL_insert_tail (plugin->pending_Sessions_head,
+ plugin->pending_Sessions_tail, queue);
+ plugin->pendingsessions++;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ }
+
+}
+
+/**
+ * Function to schedule the write task, executed after a delay
+ * @param cls pointer to the plugin struct
+ * @param tc GNUNET_SCHEDULER_TaskContext pointer
+ */
+static void
+delay_fragment_task (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ // GNUNET_TIME_UNIT_FOREVER_REL is needed to clean up old msg
+ if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK)
+ {
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &do_transmit, plugin);
+ }
+}
+
+/**
+ * Function to calculate the time of the next periodic "hello-beacon"
+ * @param plugin pointer to the plugin struct
+ */
+static void
+set_next_beacon_time (struct Plugin *const plugin)
+{
+ //under 10 known peers: once a second
+ if (plugin->mac_count < 10)
+ {
+ plugin->beacon_time =
+ GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ HELLO_BEACON_SCALING_FACTOR));
+ }
+ //under 30 known peers: every 10 seconds
+ else if (plugin->mac_count < 30)
+ {
+ plugin->beacon_time =
+ GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_SECONDS,
+ 10 * HELLO_BEACON_SCALING_FACTOR));
+ }
+ //over 30 known peers: once a minute
+ else
+ {
+ plugin->beacon_time =
+ GNUNET_TIME_absolute_add (GNUNET_TIME_absolute_get (),
+ GNUNET_TIME_relative_multiply
+ (GNUNET_TIME_UNIT_MINUTES,
+ HELLO_BEACON_SCALING_FACTOR));
+ }
+}
+
+/**
+ * Function to set the timer for the next timeout of the fragment queue
+ * @param plugin the handle to the plugin struct
+ */
+static void
+set_next_send (struct Plugin *const plugin)
+{
+ struct GNUNET_TIME_Relative next_send;
+
+ //abort if helper is not running
+ if (plugin->helper_is_running == GNUNET_NO)
+ {
+ return;
+ }
+
+ //cancel old task
+ if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_write_delay_task);
+ plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ //check if some acks are in the queue
+ if (plugin->ack_send_queue_head != NULL)
+ {
+ next_send = GNUNET_TIME_UNIT_ZERO;
+ }
+
+ //check if there are some fragments in the queue
+ else if (plugin->sending_messages_head != NULL)
+ {
+ next_send = GNUNET_TIME_UNIT_ZERO;
+ }
+ else
+ {
+ next_send = GNUNET_TIME_absolute_get_remaining (plugin->beacon_time);
+ }
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Next packet is send in: %u\n", next_send.rel_value);
+ if (next_send.rel_value == GNUNET_TIME_UNIT_ZERO.rel_value)
+ {
+ if (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK)
+ {
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &do_transmit, plugin);
+ }
+ }
+ else
+ {
+ if (plugin->server_write_delay_task == GNUNET_SCHEDULER_NO_TASK)
+ {
+ plugin->server_write_delay_task =
+ GNUNET_SCHEDULER_add_delayed (next_send, &delay_fragment_task,
+ plugin);
+ }
+ }
+}
+
+/**
+ * Function to get the next queued Session, removes the session from the queue
+ * @param plugin pointer to the plugin struct
+ * @return pointer to the session found, returns NULL if there is now session in the queue
+ */
+static struct Session *
+get_next_queue_session (struct Plugin *plugin)
+{
+ struct Session *session;
+ struct Sessionqueue *sessionqueue;
+ struct Sessionqueue *sessionqueue_alt;
+ struct PendingMessage *pm;
+
+ sessionqueue = plugin->pending_Sessions_head;
+
+ while (sessionqueue != NULL)
+ {
+ session = sessionqueue->content;
+
+ GNUNET_assert (session != NULL);
+ pm = session->pending_message_head;
+
+ if (pm == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "pending message is empty, should not happen. session %p\n",
+ session);
+ sessionqueue_alt = sessionqueue;
+ sessionqueue = sessionqueue->next;
+ plugin->pendingsessions--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
+ plugin->pending_Sessions_tail,
+ sessionqueue_alt);
+
+ GNUNET_free (sessionqueue_alt);
+ continue;
+
+ }
+
+ //check for message timeout
+ if (GNUNET_TIME_absolute_get_remaining (pm->timeout).rel_value > 0)
+ {
+ //check if session has no message in the fragment queue
+ if ((session->mac->fragment_messages_out_count <
+ FRAGMENT_QUEUE_MESSAGES_OUT_PER_MACENDPOINT) &&
+ (session->fragment_messages_out_count <
+ FRAGMENT_QUEUE_MESSAGES_OUT_PER_SESSION))
+ {
+ plugin->pendingsessions--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
+ plugin->pending_Sessions_tail,
+ sessionqueue);
+ GNUNET_free (sessionqueue);
+
+ return session;
+ }
+ else
+ {
+ sessionqueue = sessionqueue->next;
+ }
+ }
+ else
+ {
+ GNUNET_CONTAINER_DLL_remove (session->pending_message_head,
+ session->pending_message_tail, pm);
+
+ //call the cont func that it did not work
+ if (pm->transmit_cont != NULL)
+ pm->transmit_cont (pm->transmit_cont_cls, &(session->target),
+ GNUNET_SYSERR);
+ GNUNET_free (pm->msg);
+ GNUNET_free (pm);
+
+ if (session->pending_message_head == NULL)
+ {
+ sessionqueue_alt = sessionqueue;
+ sessionqueue = sessionqueue->next;
+ plugin->pendingsessions--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
+ plugin->pending_Sessions_tail,
+ sessionqueue_alt);
+
+ GNUNET_free (sessionqueue_alt);
+ }
+ }
+
+ }
+ return NULL;
+}
+
+/**
+ * frees the space of a message in the fragment queue (send queue)
+ * @param plugin the plugin struct
+ * @param fm message to free
+ */
+static void
+free_fragment_message (struct Plugin *plugin, struct FragmentMessage *fm)
+{
+ struct Session *session = fm->session;
+ struct MacEndpoint *endpoint = session->mac;
+ struct FragmentMessage_queue *fmq;
+ struct FragmentMessage_queue *fmq_next;
+
+ fmq = plugin->sending_messages_head;
+ while (fmq != NULL)
+ {
+ fmq_next = fmq->next;
+ if (fmq->content == fm)
+ {
+ GNUNET_CONTAINER_DLL_remove (plugin->sending_messages_head,
+ plugin->sending_messages_tail, fmq);
+ GNUNET_free (fmq);
+ }
+ fmq = fmq_next;
+ }
+
+ (session->mac->fragment_messages_out_count)--;
+ session->fragment_messages_out_count--;
+ plugin->pending_Fragment_Messages--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending fragments"),
+ plugin->pending_Fragment_Messages, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (endpoint->sending_messages_head,
+ endpoint->sending_messages_tail, fm);
+ GNUNET_FRAGMENT_context_destroy (fm->fragcontext);
+ if (fm->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (fm->timeout_task);
+ fm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ GNUNET_free (fm);
+
+ queue_session (plugin, session);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Free pending fragment messages %p, session %p\n", fm,
+ session);
+}
+
+/**
+ * function to fill the radiotap header
+ * @param plugin pointer to the plugin struct
+ * @param endpoint pointer to the endpoint
+ * @param header pointer to the radiotap header
+ * @return GNUNET_YES at success
+ */
+static int
+getRadiotapHeader (struct Plugin *plugin, struct MacEndpoint *endpoint,
+ struct Radiotap_Send *header)
+{
+
+ if (endpoint != NULL)
+ {
+ header->rate = endpoint->rate;
+ header->tx_power = endpoint->tx_power;
+ header->antenna = endpoint->antenna;
+ }
+ else
+ {
+ header->rate = 255;
+ header->tx_power = 0;
+ header->antenna = 0;
+ }
+
+ return GNUNET_YES;
+}
+
+/**
+ * function to generate the wlan hardware header for one packet
+ * @param Header address to write the header to
+ * @param to_mac_addr address of the recipient
+ * @param plugin pointer to the plugin struct
+ * @param size size of the whole packet, needed to calculate the time to send the packet
+ * @return GNUNET_YES if there was no error
+ */
+static int
+getWlanHeader (struct ieee80211_frame *Header,
+ const struct GNUNET_TRANSPORT_WLAN_MacAddress *to_mac_addr, struct Plugin *plugin,
+ unsigned int size)
+{
+ uint16_t *tmp16;
+ const int rate = 11000000;
+
+ Header->i_fc[0] = IEEE80211_FC0_TYPE_DATA;
+ Header->i_fc[1] = 0x00;
+ memcpy (&Header->i_addr3, &mac_bssid_gnunet, sizeof (mac_bssid_gnunet));
+ memcpy (&Header->i_addr2, plugin->mac_address.mac,
+ sizeof (plugin->mac_address));
+ memcpy (&Header->i_addr1, to_mac_addr, sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
+
+ tmp16 = (uint16_t *) Header->i_dur;
+ *tmp16 = (uint16_t) GNUNET_htole16 ((size * 1000000) / rate + 290);
+ Header->llc[0] = WLAN_LLC_DSAP_FIELD;
+ Header->llc[1] = WLAN_LLC_SSAP_FIELD;
+
+ return GNUNET_YES;
+}
+
+
+/**
+ * function to add a fragment of a message to send
+ * @param cls FragmentMessage this message belongs to
+ * @param hdr pointer to the start of the message
+ */
+static void
+add_message_for_send (void *cls, const struct GNUNET_MessageHeader *hdr)
+{
+
+ struct FragmentMessage *fm = cls;
+ struct FragmentMessage_queue *fmqueue;
+
+ GNUNET_assert (cls != NULL);
+ GNUNET_assert (fm->frag == NULL);
+ struct MacEndpoint *endpoint = fm->session->mac;
+ struct Plugin *plugin = endpoint->plugin;
+ struct GNUNET_MessageHeader *msgheader;
+ struct GNUNET_MessageHeader *msgheader2;
+ uint16_t size;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Adding fragment of message %p to send, session %p, endpoint %p, type %u\n",
+ fm, fm->session, endpoint, hdr->type);
+ size =
+ sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) +
+ sizeof (struct ieee80211_frame) + ntohs (hdr->size);
+ fm->frag = GNUNET_malloc (size);
+ fm->size = size;
+
+ msgheader = (struct GNUNET_MessageHeader *) fm->frag;
+ msgheader->size = htons (size);
+ msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
+
+ fm->radioHeader = (struct Radiotap_Send *) &msgheader[1];
+ fm->ieeewlanheader = (struct ieee80211_frame *) &fm->radioHeader[1];
+ msgheader2 = (struct GNUNET_MessageHeader *) &fm->ieeewlanheader[1];
+ memcpy (msgheader2, hdr, ntohs (hdr->size));
+
+ fmqueue = GNUNET_malloc (sizeof (struct FragmentMessage_queue));
+ fmqueue->content = fm;
+
+ GNUNET_CONTAINER_DLL_insert_tail (plugin->sending_messages_head,
+ plugin->sending_messages_tail, fmqueue);
+ set_next_send (plugin);
+}
+
+
+/**
+ * We have been notified that gnunet-helper-transport-wlan has written something to stdout.
+ * Handle the output, then reschedule this function to be called again once
+ * more is available.
+ *
+ * @param cls the plugin handle
+ * @param tc the scheduling context
+ */
+static void
+wlan_plugin_helper_read (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ char mybuf[WLAN_MTU + sizeof (struct GNUNET_MessageHeader)];
+ ssize_t bytes;
+
+ bytes =
+ GNUNET_DISK_file_read (plugin->server_stdout_handle, mybuf,
+ sizeof (mybuf));
+ if (bytes <= 0)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ _
+ ("Finished reading from gnunet-helper-transport-wlan stdout with code: %d\n"),
+ bytes);
+ return;
+ }
+ GNUNET_SERVER_mst_receive (plugin->suid_tokenizer, NULL, mybuf, bytes,
+ GNUNET_NO, GNUNET_NO);
+
+ GNUNET_assert (plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK);
+ plugin->server_read_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdout_handle,
+ &wlan_plugin_helper_read, plugin);
+}
+
+/**
+ * Start the gnunet-helper-transport-wlan process.
+ *
+ * @param plugin the transport plugin
+ * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
+ */
+static int
+wlan_transport_start_wlan_helper (struct Plugin *plugin)
+{
+ const char *filenamehw = "gnunet-helper-transport-wlan";
+ const char *filenameloopback = "gnunet-helper-transport-wlan-dummy";
+ char *absolute_filename = NULL;
+
+ if (plugin->helper_is_running == GNUNET_YES)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "wlan_transport_start_wlan_helper not needed, helper already running!");
+ return GNUNET_YES;
+ }
+
+ plugin->server_stdout = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_NO, GNUNET_YES);
+ if (plugin->server_stdout == NULL)
+ return GNUNET_SYSERR;
+
+ plugin->server_stdin = GNUNET_DISK_pipe (GNUNET_YES, GNUNET_YES, GNUNET_YES, GNUNET_NO);
+ if (plugin->server_stdin == NULL)
+ return GNUNET_SYSERR;
+
+ if ((plugin->testmode == 1) || (plugin->testmode == 2))
+ {
+ if (GNUNET_OS_check_helper_binary (filenameloopback) == GNUNET_YES)
+ {
+ absolute_filename = GNUNET_strdup (filenameloopback);
+ }
+ else
+ {
+ char cwd[FILENAME_MAX];
+
+ GNUNET_assert (getcwd (cwd, sizeof (cwd)) != NULL);
+
+ GNUNET_asprintf (&absolute_filename, "%s%s%s", cwd, DIR_SEPARATOR_STR,
+ filenameloopback);
+
+ if (GNUNET_DISK_file_test (filenameloopback) != GNUNET_YES)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "Helper `%s' not found! %i\n", absolute_filename);
+ GNUNET_break (0);
+ }
+ }
+ }
+
+ /* Start the server process */
+
+ if (plugin->testmode == 0)
+ {
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Starting gnunet-helper-transport-wlan process cmd: %s %s %i\n",
+ filenamehw, plugin->interface, plugin->testmode);
+ if (GNUNET_OS_check_helper_binary (filenamehw) == GNUNET_YES)
+ {
+ plugin->server_proc =
+ GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout,
+ filenamehw, filenamehw, plugin->interface,
+ NULL);
+ }
+ else if (GNUNET_OS_check_helper_binary (filenamehw) == GNUNET_NO)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "gnunet-helper-transport-wlan is not suid, please change it or look at the doku\n");
+ GNUNET_break (0);
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "gnunet-helper-transport-wlan not found, please look if it exists and is the $PATH variable!\n");
+ GNUNET_break (0);
+ }
+
+ }
+ else if (plugin->testmode == 1)
+ {
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME,
+ "Starting gnunet-helper-transport-wlan-dummy loopback 1 process cmd: %s %s %i\n",
+ absolute_filename, plugin->interface, plugin->testmode);
+ plugin->server_proc =
+ GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout,
+ absolute_filename, absolute_filename, "1",
+ NULL);
+ if (plugin->server_proc == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "`%s' not found, please look if it exists and is in the $PATH variable!\n",
+ absolute_filename);
+ GNUNET_break (0);
+ }
+ }
+ else if (plugin->testmode == 2)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME,
+ "Starting gnunet-helper-transport-wlan-dummy loopback 2 process cmd: %s %s %i\n",
+ absolute_filename, plugin->interface, plugin->testmode);
+ plugin->server_proc =
+ GNUNET_OS_start_process (GNUNET_NO, plugin->server_stdin, plugin->server_stdout,
+ absolute_filename, absolute_filename, "2",
+ NULL);
+ if (plugin->server_proc == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ "`%s' not found, please look if it exists and is in the $PATH variable!\n",
+ absolute_filename);
+ GNUNET_break (0);
+ }
+ }
+ if (absolute_filename != NULL)
+ GNUNET_free (absolute_filename);
+ if (plugin->server_proc == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Failed to start gnunet-helper-transport-wlan process\n");
+ return GNUNET_SYSERR;
+ }
+
+
+
+ /* Close the write end of the read pipe */
+ GNUNET_DISK_pipe_close_end (plugin->server_stdout,
+ GNUNET_DISK_PIPE_END_WRITE);
+
+ /* Close the read end of the write pipe */
+ GNUNET_DISK_pipe_close_end (plugin->server_stdin, GNUNET_DISK_PIPE_END_READ);
+
+ plugin->server_stdout_handle =
+ GNUNET_DISK_pipe_handle (plugin->server_stdout,
+ GNUNET_DISK_PIPE_END_READ);
+ plugin->server_stdin_handle =
+ GNUNET_DISK_pipe_handle (plugin->server_stdin,
+ GNUNET_DISK_PIPE_END_WRITE);
+
+ GNUNET_assert (plugin->server_read_task == GNUNET_SCHEDULER_NO_TASK);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Adding server_read_task for the gnunet-helper-transport-wlan\n");
+ plugin->server_read_task =
+ GNUNET_SCHEDULER_add_read_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdout_handle,
+ &wlan_plugin_helper_read, plugin);
+
+ plugin->helper_is_running = GNUNET_YES;
+ return GNUNET_YES;
+}
+
+/**
+ * Stops the gnunet-helper-transport-wlan process.
+ *
+ * @param plugin the transport plugin
+ * @return GNUNET_YES if process was started, GNUNET_SYSERR on error
+ */
+static int
+wlan_transport_stop_wlan_helper (struct Plugin *plugin)
+{
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Stoping WLAN helper process\n");
+
+ if (plugin->helper_is_running == GNUNET_NO)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "wlan_transport_stop_wlan_helper not needed, helper already stopped!");
+ return GNUNET_YES;
+ }
+
+ if (plugin->server_write_delay_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_write_delay_task);
+ plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (plugin->server_write_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_write_task);
+ plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (plugin->server_read_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (plugin->server_read_task);
+ plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ GNUNET_DISK_pipe_close (plugin->server_stdout);
+ GNUNET_DISK_pipe_close (plugin->server_stdin);
+ GNUNET_OS_process_kill (plugin->server_proc, SIGKILL);
+ GNUNET_OS_process_wait (plugin->server_proc);
+ GNUNET_OS_process_close (plugin->server_proc);
+
+ plugin->helper_is_running = GNUNET_NO;
+
+ return GNUNET_YES;
+}
+
+/**
+ * function for delayed restart of the helper process
+ * @param cls Finish_send struct if message should be finished
+ * @param tc TaskContext
+ */
+static void
+delay_restart_helper (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Finish_send *finish = cls;
+ struct Plugin *plugin;
+
+ plugin = finish->plugin;
+
+ plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ {
+ GNUNET_free_non_null (finish->msgstart);
+ GNUNET_free (finish);
+ return;
+ }
+
+ wlan_transport_start_wlan_helper (plugin);
+
+ if (finish->size != 0)
+ {
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &finish_sending, finish);
+ }
+ else
+ {
+ set_next_send (plugin);
+ GNUNET_free_non_null (finish->msgstart);
+ GNUNET_free (finish);
+ }
+
+}
+
+/**
+ * Function to restart the helper
+ * @param plugin pointer to the global plugin struct
+ * @param finish pointer to the Finish_send struct to finish
+ */
+static void
+restart_helper (struct Plugin *plugin, struct Finish_send *finish)
+{
+ static struct GNUNET_TIME_Relative next_try = { 1000 };
+ GNUNET_assert (finish != NULL);
+
+ wlan_transport_stop_wlan_helper (plugin);
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_delayed (next_try, &delay_restart_helper, finish);
+ GNUNET_TIME_relative_multiply (next_try, HELPER_RESTART_SCALING_FACTOR);
+
+}
+
+/**
+ * function to finish a sending if not all could have been writen befor
+ * @param cls pointer to the Finish_send struct
+ * @param tc TaskContext
+ */
+static void
+finish_sending (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Finish_send *finish = cls;
+ struct Plugin *plugin;
+ ssize_t bytes;
+
+ plugin = finish->plugin;
+ plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (0 != (GNUNET_SCHEDULER_REASON_SHUTDOWN & tc->reason))
+ {
+ GNUNET_free (finish->msgstart);
+ GNUNET_free (finish);
+ return;
+ }
+ bytes =
+ GNUNET_DISK_file_write (plugin->server_stdin_handle,
+ finish->head_of_next_write, finish->size);
+
+ if (bytes != finish->size)
+ {
+ if (bytes != GNUNET_SYSERR)
+ {
+ finish->head_of_next_write += bytes;
+ finish->size -= bytes;
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &finish_sending, finish);
+ }
+ else
+ {
+ restart_helper (plugin, finish);
+ }
+ }
+ else
+ {
+ GNUNET_free (finish->msgstart);
+ GNUNET_free (finish);
+ set_next_send (plugin);
+ }
+}
+
+/**
+ * function to send a hello beacon
+ * @param plugin pointer to the plugin struct
+ */
+static void
+send_hello_beacon (struct Plugin *plugin)
+{
+ uint16_t size;
+ ssize_t bytes;
+ uint16_t hello_size;
+ struct GNUNET_MessageHeader *msgheader;
+ struct ieee80211_frame *ieeewlanheader;
+ struct Radiotap_Send *radioHeader;
+ struct GNUNET_MessageHeader *msgheader2;
+ const struct GNUNET_MessageHeader *hello;
+ struct Finish_send *finish;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Sending hello beacon\n");
+
+ GNUNET_assert (plugin != NULL);
+
+ GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan hello beacons send"),
+ 1, GNUNET_NO);
+
+ hello = plugin->env->get_our_hello ();
+ hello_size = GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello);
+ GNUNET_assert (sizeof (struct WlanHeader) + hello_size <= WLAN_MTU);
+ size =
+ sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) +
+ sizeof (struct ieee80211_frame) + hello_size;
+
+ msgheader = GNUNET_malloc (size);
+ msgheader->size = htons (size);
+ msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
+
+ radioHeader = (struct Radiotap_Send *) &msgheader[1];
+ getRadiotapHeader (plugin, NULL, radioHeader);
+ ieeewlanheader = (struct ieee80211_frame *) &radioHeader[1];
+ getWlanHeader (ieeewlanheader, &bc_all_mac, plugin, size);
+
+ msgheader2 = (struct GNUNET_MessageHeader *) &ieeewlanheader[1];
+ /*msgheader2->size =
+ * htons (GNUNET_HELLO_size ((struct GNUNET_HELLO_Message *) hello) +
+ * sizeof (struct GNUNET_MessageHeader));
+ *
+ * msgheader2->type = htons (GNUNET_MESSAGE_TYPE_WLAN_ADVERTISEMENT); */
+ memcpy (msgheader2, hello, hello_size);
+
+ bytes = GNUNET_DISK_file_write (plugin->server_stdin_handle, msgheader, size);
+
+ if (bytes == GNUNET_SYSERR)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ _
+ ("Error writing to wlan helper. errno == %d, ERROR: %s\n"),
+ errno, strerror (errno));
+ finish = GNUNET_malloc (sizeof (struct Finish_send));
+ finish->plugin = plugin;
+ finish->head_of_next_write = NULL;
+ finish->size = 0;
+ finish->msgstart = NULL;
+ restart_helper (plugin, finish);
+
+ set_next_beacon_time (plugin);
+
+ }
+ else
+ {
+ GNUNET_assert (bytes == size);
+ set_next_beacon_time (plugin);
+ set_next_send (plugin);
+ }
+ GNUNET_free (msgheader);
+
+
+}
+
+/**
+ * function to add an ack to send it for a received fragment
+ * @param cls MacEndpoint this ack belongs to
+ * @param msg_id id of the message
+ * @param hdr pointer to the hdr where the ack is stored
+ *
+ */
+static void
+add_ack_for_send (void *cls, uint32_t msg_id,
+ const struct GNUNET_MessageHeader *hdr)
+{
+
+ struct AckSendQueue *ack;
+
+ GNUNET_assert (cls != NULL);
+ struct MacEndpoint *endpoint = cls;
+ struct Plugin *plugin = endpoint->plugin;
+ struct GNUNET_MessageHeader *msgheader;
+ struct GNUNET_MessageHeader *msgheader2;
+ uint16_t size;
+
+ size =
+ sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) +
+ sizeof (struct ieee80211_frame) + ntohs (hdr->size) +
+ sizeof (struct AckSendQueue);
+
+ ack = GNUNET_malloc (size);
+ ack->message_id = msg_id;
+ ack->endpoint = endpoint;
+
+ size =
+ sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_Send) +
+ sizeof (struct ieee80211_frame) + ntohs (hdr->size);
+
+ msgheader = (struct GNUNET_MessageHeader *) &ack[1];
+ ack->hdr = (struct GNUNET_MessageHeader *) &ack[1];
+ msgheader->size = htons (size);
+ msgheader->type = htons (GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA);
+
+ ack->radioHeader = (struct Radiotap_Send *) &msgheader[1];
+ ack->ieeewlanheader = (struct ieee80211_frame *) &(ack->radioHeader)[1];
+ msgheader2 = (struct GNUNET_MessageHeader *) &(ack->ieeewlanheader)[1];
+ memcpy (msgheader2, hdr, ntohs (hdr->size));
+
+ GNUNET_CONTAINER_DLL_insert_tail (plugin->ack_send_queue_head,
+ plugin->ack_send_queue_tail, ack);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Adding ack with message id %u to send, AckSendQueue %p, endpoint %p\n",
+ msg_id, ack, endpoint);
+ set_next_send (plugin);
+}
+
+/**
+ * Function for the scheduler if a FragmentMessage times out
+ * @param cls pointer to the FragmentMessage
+ * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
+ */
+static void
+fragmentmessage_timeout (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct FragmentMessage *fm = cls;
+
+ GNUNET_assert (fm != NULL);
+ fm->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+ {
+ return;
+ }
+ free_fragment_message (fm->session->mac->plugin, fm);
+}
+
+/**
+ * Function to check if there is some space in the fragment queue
+ * inserts a message if space is available
+ * @param plugin the plugin struct
+ */
+
+static void
+check_fragment_queue (struct Plugin *plugin)
+{
+ struct Session *session;
+ struct FragmentMessage *fm;
+ struct GNUNET_PeerIdentity pid;
+
+ struct PendingMessage *pm;
+
+ if (plugin->pending_Fragment_Messages < FRAGMENT_QUEUE_SIZE)
+ {
+ session = get_next_queue_session (plugin);
+ if (session != NULL)
+ {
+ pm = session->pending_message_head;
+ GNUNET_assert (pm != NULL);
+ GNUNET_CONTAINER_DLL_remove (session->pending_message_head,
+ session->pending_message_tail, pm);
+ session->mac->fragment_messages_out_count++;
+ session->fragment_messages_out_count++;
+ plugin->pending_Fragment_Messages++;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending fragments"),
+ plugin->pending_Fragment_Messages, GNUNET_NO);
+
+ fm = GNUNET_malloc (sizeof (struct FragmentMessage));
+ fm->session = session;
+ fm->timeout.abs_value = pm->timeout.abs_value;
+ fm->frag = NULL;
+ fm->fragcontext =
+ GNUNET_FRAGMENT_context_create (plugin->env->stats, WLAN_MTU,
+ &plugin->tracker,
+ GNUNET_TIME_UNIT_SECONDS,
+ &(pm->msg->header),
+ &add_message_for_send, fm);
+ fm->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
+ (fm->timeout), fragmentmessage_timeout,
+ fm);
+ GNUNET_CONTAINER_DLL_insert_tail (session->mac->sending_messages_head,
+ session->mac->sending_messages_tail,
+ fm);
+
+ if (pm->transmit_cont != NULL)
+ {
+ pid = session->target;
+ pm->transmit_cont (pm->transmit_cont_cls, &pid, GNUNET_OK);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "called pm->transmit_cont for %p\n", session);
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "no pm->transmit_cont for %p\n", session);
+ }
+ GNUNET_free (pm);
+
+ if (session->pending_message_head != NULL)
+ {
+ //requeue session
+ queue_session (plugin, session);
+ }
+
+ }
+ }
+
+ //check if timeout changed
+ set_next_send (plugin);
+}
+
+/**
+ * Function to send an ack, does not free the ack
+ * @param plugin pointer to the plugin
+ */
+static void
+send_ack (struct Plugin *plugin)
+{
+
+ ssize_t bytes;
+ struct AckSendQueue *ack;
+ struct Finish_send *finish;
+
+ ack = plugin->ack_send_queue_head;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Sending ack for message_id %u for mac endpoint %p, size %u\n",
+ ack->message_id, ack->endpoint,
+ ntohs (ack->hdr->size) - sizeof (struct Radiotap_Send));
+ GNUNET_assert (plugin != NULL);
+ GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan acks send"), 1,
+ GNUNET_NO);
+
+ getRadiotapHeader (plugin, ack->endpoint, ack->radioHeader);
+ getWlanHeader (ack->ieeewlanheader, &ack->endpoint->addr, plugin,
+ ntohs (ack->hdr->size));
+
+ bytes =
+ GNUNET_DISK_file_write (plugin->server_stdin_handle, ack->hdr,
+ ntohs (ack->hdr->size));
+ if (bytes == GNUNET_SYSERR)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ _
+ ("Error writing to wlan helper. errno == %d, ERROR: %s\n"),
+ errno, strerror (errno));
+ finish = GNUNET_malloc (sizeof (struct Finish_send));
+ finish->plugin = plugin;
+ finish->head_of_next_write = NULL;
+ finish->size = 0;
+ finish->msgstart = NULL;
+ restart_helper (plugin, finish);
+ }
+ else
+ {
+ GNUNET_assert (bytes == ntohs (ack->hdr->size));
+ GNUNET_CONTAINER_DLL_remove (plugin->ack_send_queue_head,
+ plugin->ack_send_queue_tail, ack);
+ GNUNET_free (ack);
+ set_next_send (plugin);
+ }
+}
+
+/**
+ * Function called when wlan helper is ready to get some data
+ *
+ * @param cls closure
+ * @param tc GNUNET_SCHEDULER_TaskContext
+ */
+static void
+do_transmit (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct Plugin *plugin = cls;
+
+ GNUNET_assert (plugin != NULL);
+
+ plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
+ if (0 != (tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN))
+ return;
+
+ struct Session *session;
+ struct FragmentMessage *fm;
+ struct Finish_send *finish;
+ struct FragmentMessage_queue *fmq;
+ ssize_t bytes;
+
+ if (plugin->ack_send_queue_head != NULL)
+ {
+ send_ack (plugin);
+ return;
+ }
+
+ //test if a "hello-beacon" has to be send
+ if (GNUNET_TIME_absolute_get_remaining (plugin->beacon_time).rel_value == 0)
+ {
+ send_hello_beacon (plugin);
+ return;
+ }
+
+ if (plugin->sending_messages_head != NULL)
+ {
+ GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan fragments send"), 1,
+ GNUNET_NO);
+
+ fmq = plugin->sending_messages_head;
+ fm = fmq->content;
+ GNUNET_CONTAINER_DLL_remove (plugin->sending_messages_head,
+ plugin->sending_messages_tail, fmq);
+ GNUNET_free (fmq);
+
+ session = fm->session;
+ GNUNET_assert (session != NULL);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Sending GNUNET_MESSAGE_TYPE_WLAN_FRAGMENT for fragment message %p, size: %u\n",
+ fm, fm->size);
+ getRadiotapHeader (plugin, session->mac, fm->radioHeader);
+ getWlanHeader (fm->ieeewlanheader, &(fm->session->mac->addr), plugin,
+ fm->size);
+
+ bytes =
+ GNUNET_DISK_file_write (plugin->server_stdin_handle, fm->frag,
+ fm->size);
+
+
+ if (bytes != fm->size)
+ {
+ finish = GNUNET_malloc (sizeof (struct Finish_send));
+ finish->plugin = plugin;
+ finish->msgstart = (struct GNUNET_MessageHeader *) fm->frag;
+ GNUNET_assert (plugin->server_write_task == GNUNET_SCHEDULER_NO_TASK);
+
+ if (bytes == GNUNET_SYSERR)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ _
+ ("Error writing to wlan helper. errno == %d, ERROR: %s\n"),
+ errno, strerror (errno));
+
+ finish->head_of_next_write = fm->frag;
+ finish->size = fm->size;
+ restart_helper (plugin, finish);
+ }
+ else
+ {
+ finish->head_of_next_write = fm->frag + bytes;
+ finish->size = fm->size - bytes;
+ plugin->server_write_task =
+ GNUNET_SCHEDULER_add_write_file (GNUNET_TIME_UNIT_FOREVER_REL,
+ plugin->server_stdin_handle,
+ &finish_sending, finish);
+ }
+
+ fm->frag = NULL;
+ }
+ else
+ {
+ GNUNET_free (fm->frag);
+ fm->frag = NULL;
+ set_next_send (plugin);
+ }
+ GNUNET_FRAGMENT_context_transmission_done (fm->fragcontext);
+ return;
+ }
+
+#if 1
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "do_transmit did nothing, should not happen!\n");
+#endif
+ set_next_send (plugin);
+}
+
+/**
+ * Another peer has suggested an address for this
+ * peer and transport plugin. Check that this could be a valid
+ * address. If so, consider adding it to the list
+ * of addresses.
+ *
+ * @param cls closure
+ * @param addr pointer to the address
+ * @param addrlen length of addr
+ * @return GNUNET_OK if this is a plausible address for this peer
+ * and transport
+ */
+static int
+wlan_plugin_address_suggested (void *cls, const void *addr, size_t addrlen)
+{
+ //struct Plugin *plugin = cls;
+
+ /* check if the address is plausible; if so,
+ * add it to our list! */
+
+ GNUNET_assert (cls != NULL);
+ //FIXME mitm is not checked
+ //Mac Address has 6 bytes
+ if (addrlen == 6)
+ {
+ /* TODO check for bad addresses like multicast, broadcast, etc */
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "wlan_plugin_address_suggested got good address, size %u!\n",
+ addrlen);
+ return GNUNET_OK;
+ }
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "wlan_plugin_address_suggested got bad address, size %u!\n",
+ addrlen);
+ return GNUNET_SYSERR;
+}
+
+
+/**
+ * Creates a new outbound session the transport service will use to send data to the
+ * peer
+ *
+ * @param cls the plugin
+ * @param address the address
+ * @return the session or NULL of max connections exceeded
+ */
+
+static struct Session *
+wlan_plugin_get_session (void *cls,
+ const struct GNUNET_HELLO_Address *address)
+{
+ struct Plugin *plugin = cls;
+ struct Session * s = NULL;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (address != NULL);
+
+ if (GNUNET_OK == wlan_plugin_address_suggested (plugin,
+ address->address,
+ address->address_length))
+ {
+ s = get_session (plugin, address->address, &address->peer);
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, PLUGIN_LOG_NAME,
+ _("Wlan Address len %d is wrong\n"), address->address_length);
+ return s;
+ }
+
+ return s;
+}
+
+/**
+ * Function that can be used by the transport service to transmit
+ * a message using the plugin. Note that in the case of a
+ * peer disconnecting, the continuation MUST be called
+ * prior to the disconnect notification itself. This function
+ * will be called with this peer's HELLO message to initiate
+ * a fresh connection to another peer.
+ *
+ * @param cls closure
+ * @param session which session must be used
+ * @param msgbuf the message to transmit
+ * @param msgbuf_size number of bytes in 'msgbuf'
+ * @param priority how important is the message (most plugins will
+ * ignore message priority and just FIFO)
+ * @param to how long to wait at most for the transmission (does not
+ * require plugins to discard the message after the timeout,
+ * just advisory for the desired delay; most plugins will ignore
+ * this as well)
+ * @param cont continuation to call once the message has
+ * been transmitted (or if the transport is ready
+ * for the next transmission call; or if the
+ * peer disconnected...); can be NULL
+ * @param cont_cls closure for cont
+ * @return number of bytes used (on the physical network, with overheads);
+ * -1 on hard errors (i.e. address invalid); 0 is a legal value
+ * and does NOT mean that the message was not transmitted (DV)
+ */
+static ssize_t
+wlan_plugin_send (void *cls,
+ struct Session *session,
+ const char *msgbuf, size_t msgbuf_size,
+ unsigned int priority,
+ struct GNUNET_TIME_Relative to,
+ GNUNET_TRANSPORT_TransmitContinuation cont, void *cont_cls)
+{
+ struct Plugin *plugin = cls;
+ struct PendingMessage *newmsg;
+ struct WlanHeader *wlanheader;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (session != NULL);
+ GNUNET_assert (msgbuf_size > 0);
+
+ //queue message:
+
+ //queue message in session
+ //test if there is no other message in the "queue"
+ //FIXME: to many send requests
+ if (session->pending_message_head != NULL)
+ {
+ newmsg = session->pending_message_head;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "wlan_plugin_send: a pending message is already in the queue for this client\n remaining time to send this message is %u, queued fragment messages for this mac connection %u\n",
+ GNUNET_TIME_absolute_get_remaining (newmsg->
+ timeout).rel_value,
+ session->mac->fragment_messages_out_count);
+ }
+
+ newmsg = GNUNET_malloc (sizeof (struct PendingMessage));
+ newmsg->msg = GNUNET_malloc (msgbuf_size + sizeof (struct WlanHeader));
+ wlanheader = newmsg->msg;
+ //copy msg to buffer, not fragmented / segmented yet, but with message header
+ wlanheader->header.size = htons (msgbuf_size + sizeof (struct WlanHeader));
+ wlanheader->header.type = htons (GNUNET_MESSAGE_TYPE_WLAN_DATA);
+ memcpy (&(wlanheader->target), &session->target, sizeof (struct GNUNET_PeerIdentity));
+ memcpy (&(wlanheader->source), plugin->env->my_identity,
+ sizeof (struct GNUNET_PeerIdentity));
+ wlanheader->crc = 0;
+ memcpy (&wlanheader[1], msgbuf, msgbuf_size);
+ wlanheader->crc =
+ htonl (GNUNET_CRYPTO_crc32_n
+ ((char *) wlanheader, msgbuf_size + sizeof (struct WlanHeader)));
+
+ newmsg->transmit_cont = cont;
+ newmsg->transmit_cont_cls = cont_cls;
+ newmsg->timeout = GNUNET_TIME_relative_to_absolute (to);
+
+ newmsg->timeout.abs_value = newmsg->timeout.abs_value - 500;
+
+ newmsg->message_size = msgbuf_size + sizeof (struct WlanHeader);
+
+ GNUNET_CONTAINER_DLL_insert_tail (session->pending_message_head,
+ session->pending_message_tail, newmsg);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "New message for %p with size (incl wlan header) %u added\n",
+ session, newmsg->message_size);
+#if DEBUG_WLAN > 1
+ hexdump (msgbuf, GNUNET_MIN (msgbuf_size, 256));
+#endif
+ //queue session
+ queue_session (plugin, session);
+
+ check_fragment_queue (plugin);
+ //FIXME not the correct size
+ return msgbuf_size;
+}
+
+
+/**
+ * function to free a mac endpoint
+ * @param plugin pointer to the plugin struct
+ * @param endpoint pointer to the MacEndpoint to free
+ */
+static void
+free_macendpoint (struct Plugin *plugin, struct MacEndpoint *endpoint)
+{
+ struct Sessionqueue *sessions;
+ struct Sessionqueue *sessions_next;
+
+ GNUNET_assert (endpoint != NULL);
+
+ sessions = endpoint->sessions_head;
+ while (sessions != NULL)
+ {
+ sessions_next = sessions->next;
+ free_session (plugin, sessions, GNUNET_NO);
+ sessions = sessions_next;
+ }
+
+ GNUNET_CONTAINER_DLL_remove (plugin->mac_head, plugin->mac_tail, endpoint);
+ if (endpoint->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (endpoint->timeout_task);
+ endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ plugin->mac_count--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"),
+ plugin->mac_count, GNUNET_NO);
+ GNUNET_free (endpoint);
+
+}
+
+/**
+ * function to free a session
+ * @param plugin pointer to the plugin
+ * @param queue pointer to the sessionqueue element to free
+ * @param do_free_macendpoint if GNUNET_YES and mac endpoint would be empty, free mac endpoint
+ */
+static void
+free_session (struct Plugin *plugin, struct Sessionqueue *queue,
+ int do_free_macendpoint)
+{
+ struct Sessionqueue *pendingsession;
+ struct Sessionqueue *pendingsession_tmp;
+ struct PendingMessage *pm;
+ struct MacEndpoint *endpoint;
+ struct FragmentMessage *fm;
+ struct FragmentMessage *fmnext;
+ int check = 0;
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_assert (queue != NULL);
+ GNUNET_assert (queue->content != NULL);
+
+ //session found
+ //is this session pending for send
+ pendingsession = plugin->pending_Sessions_head;
+ while (pendingsession != NULL)
+ {
+ pendingsession_tmp = pendingsession;
+ pendingsession = pendingsession->next;
+ GNUNET_assert (pendingsession_tmp->content != NULL);
+ if (pendingsession_tmp->content == queue->content)
+ {
+ plugin->pendingsessions--;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_remove (plugin->pending_Sessions_head,
+ plugin->pending_Sessions_tail,
+ pendingsession_tmp);
+ GNUNET_free (pendingsession_tmp);
+
+ GNUNET_assert (check == 0);
+ check = 1;
+ }
+ }
+
+ endpoint = queue->content->mac;
+ fm = endpoint->sending_messages_head;
+ while (fm != NULL)
+ {
+ fmnext = fm->next;
+ if (fm->session == queue->content)
+ {
+ free_fragment_message (plugin, fm);
+ }
+ fm = fmnext;
+ }
+
+ // remove PendingMessage
+ pm = queue->content->pending_message_head;
+ while (pm != NULL)
+ {
+ GNUNET_CONTAINER_DLL_remove (queue->content->pending_message_head,
+ queue->content->pending_message_tail, pm);
+ GNUNET_free (pm->msg);
+ GNUNET_free (pm);
+ pm = queue->content->pending_message_head;
+ }
+
+ GNUNET_CONTAINER_DLL_remove (endpoint->sessions_head, endpoint->sessions_tail,
+ queue);
+ //Check that no ohter session on this endpoint for this session exits
+ GNUNET_assert (search_session (plugin, endpoint, &queue->content->target) ==
+ NULL);
+ if (endpoint->sessions_head == NULL && do_free_macendpoint == GNUNET_YES)
+ {
+ free_macendpoint (plugin, endpoint);
+ //check if no endpoint with the same address exists
+ GNUNET_assert (get_macendpoint (plugin, &endpoint->addr, GNUNET_NO) ==
+ NULL);
+ }
+
+ if (queue->content->timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (queue->content->timeout_task);
+ queue->content->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_free (queue);
+
+ check_fragment_queue (plugin);
+}
+
+/**
+ * Function that can be used to force the plugin to disconnect
+ * from the given peer and cancel all previous transmissions
+ * (and their continuation).
+ *
+ * @param cls closure
+ * @param target peer from which to disconnect
+ */
+static void
+wlan_plugin_disconnect (void *cls, const struct GNUNET_PeerIdentity *target)
+{
+ struct Plugin *plugin = cls;
+ struct Sessionqueue *queue;
+ struct Sessionqueue *queue_next;
+ struct MacEndpoint *endpoint = plugin->mac_head;
+ struct MacEndpoint *endpoint_next;
+
+ // just look at all the session for the needed one
+ while (endpoint != NULL)
+ {
+ queue = endpoint->sessions_head;
+ endpoint_next = endpoint->next;
+ while (queue != NULL)
+ {
+ // content is never NULL
+ GNUNET_assert (queue->content != NULL);
+ queue_next = queue->next;
+ if (memcmp
+ (target, &(queue->content->target),
+ sizeof (struct GNUNET_PeerIdentity)) == 0)
+ {
+ free_session (plugin, queue, GNUNET_YES);
+ }
+ // try next
+ queue = queue_next;
+ }
+ endpoint = endpoint_next;
+ }
+}
+
+/**
+ * Convert the transports address to a nice, human-readable
+ * format.
+ *
+ * @param cls closure
+ * @param type name of the transport that generated the address
+ * @param addr one of the addresses of the host, NULL for the last address
+ * the specific address format depends on the transport
+ * @param addrlen length of the address
+ * @param numeric should (IP) addresses be displayed in numeric form?
+ * @param timeout after how long should we give up?
+ * @param asc function to call on each string
+ * @param asc_cls closure for asc
+ */
+static void
+wlan_plugin_address_pretty_printer (void *cls, const char *type,
+ const void *addr, size_t addrlen,
+ int numeric,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_AddressStringCallback asc,
+ void *asc_cls)
+{
+ char *ret;
+ const unsigned char *input;
+
+ //GNUNET_assert(cls !=NULL);
+ if (addrlen != sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress))
+ {
+ /* invalid address (MAC addresses have 6 bytes) */
+ //GNUNET_break (0);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_plugin_address_pretty_printer got size: %u, worng size!\n",
+ addrlen);
+ asc (asc_cls, NULL);
+ return;
+ }
+ input = (const unsigned char *) addr;
+ GNUNET_asprintf (&ret,
+ "Transport %s: %s Mac-Address %.2X:%.2X:%.2X:%.2X:%.2X:%.2X",
+ type, PROTOCOL_PREFIX, input[0], input[1], input[2],
+ input[3], input[4], input[5]);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_plugin_address_pretty_printer got size: %u, nummeric %u, type %s; made string: %s\n",
+ addrlen, numeric, type, ret);
+ asc (asc_cls, ret);
+ //only one mac address per plugin
+ asc (asc_cls, NULL);
+}
+
+
+
+/**
+ * handels the data after all fragments are put together
+ * @param cls macendpoint this messages belongs to
+ * @param hdr pointer to the data
+ */
+static void
+wlan_data_message_handler (void *cls, const struct GNUNET_MessageHeader *hdr)
+{
+ struct MacEndpoint *endpoint = (struct MacEndpoint *) cls;
+ struct Plugin *plugin = endpoint->plugin;
+ struct WlanHeader *wlanheader;
+ struct Session *session;
+
+ const struct GNUNET_MessageHeader *temp_hdr;
+ struct GNUNET_PeerIdentity tmpsource;
+ int crc;
+
+ GNUNET_assert (plugin != NULL);
+
+ if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_WLAN_DATA)
+ {
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_data_message_handler got GNUNET_MESSAGE_TYPE_WLAN_DATA size: %u\n",
+ ntohs (hdr->size));
+
+ if (ntohs (hdr->size) <
+ sizeof (struct WlanHeader) + sizeof (struct GNUNET_MessageHeader))
+ {
+ //packet not big enought
+ return;
+ }
+
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ _("# wlan whole messages received"), 1,
+ GNUNET_NO);
+ wlanheader = (struct WlanHeader *) hdr;
+
+ session = search_session (plugin, endpoint, &wlanheader->source);
+
+ temp_hdr = (const struct GNUNET_MessageHeader *) &wlanheader[1];
+ crc = ntohl (wlanheader->crc);
+ wlanheader->crc = 0;
+ if (GNUNET_CRYPTO_crc32_n
+ ((char *) wlanheader, ntohs (wlanheader->header.size)) != crc)
+ {
+ //wrong crc, dispose message
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME,
+ "Wlan message header crc was wrong: %u != %u\n",
+ GNUNET_CRYPTO_crc32_n ((char *) wlanheader,
+ ntohs (wlanheader->header.size)),
+ crc);
+ hexdump ((void *) hdr, ntohs (hdr->size));
+ return;
+ }
+
+ //if not in session list
+ if (session == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "WLAN client not in session list: packet size = %u, inner size = %u, header size = %u\n",
+ ntohs (wlanheader->header.size), ntohs (temp_hdr->size),
+ sizeof (struct WlanHeader));
+ //try if it is a hello message
+ if (ntohs (wlanheader->header.size) >=
+ ntohs (temp_hdr->size) + sizeof (struct WlanHeader))
+ {
+ if (ntohs (temp_hdr->type) == GNUNET_MESSAGE_TYPE_HELLO)
+ {
+ if (GNUNET_HELLO_get_id
+ ((const struct GNUNET_HELLO_Message *) temp_hdr,
+ &tmpsource) == GNUNET_OK)
+ {
+ session = create_session (plugin, endpoint, &tmpsource);
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
+ "WLAN client not in session list and hello message is not okay\n");
+ return;
+ }
+
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
+ "WLAN client not in session list and not a hello message\n");
+ return;
+ }
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
+ "WLAN client not in session list and message size in does not fit\npacket size = %u, inner size = %u, header size = %u\n",
+ ntohs (wlanheader->header.size),
+ ntohs (temp_hdr->size), sizeof (struct WlanHeader));
+ return;
+ }
+ }
+
+ //"receive" the message
+
+ if (memcmp
+ (&wlanheader->source, &session->target,
+ sizeof (struct GNUNET_PeerIdentity)) != 0)
+ {
+ //wrong peer id
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "WLAN peer source id doesn't match packet peer source id: session %p\n",
+ session);
+ return;
+ }
+
+ if (memcmp
+ (&wlanheader->target, plugin->env->my_identity,
+ sizeof (struct GNUNET_PeerIdentity)) != 0)
+ {
+ //wrong peer id
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "WLAN peer target id doesn't match our peer id: session %p\n",
+ session);
+ return;
+ }
+
+ GNUNET_SERVER_mst_receive (plugin->data_tokenizer, session,
+ (const char *) temp_hdr,
+ ntohs (hdr->size) - sizeof (struct WlanHeader),
+ GNUNET_YES, GNUNET_NO);
+
+ return;
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
+ "wlan_data_message_handler got wrong message type: %u\n",
+ ntohs (hdr->size));
+ return;
+ }
+}
+
+/**
+ * function to process the a message, give it to the higher layer
+ * @param cls pointer to the plugin
+ * @param client pointer to the session this message belongs to
+ * @param hdr start of the message
+ */
+//TODO ATS informations
+static void
+process_data (void *cls, void *client, const struct GNUNET_MessageHeader *hdr)
+{
+
+ GNUNET_assert (client != NULL);
+ GNUNET_assert (cls != NULL);
+ struct Session *session = (struct Session *) client;
+ struct Plugin *plugin = (struct Plugin *) cls;
+ struct GNUNET_ATS_Information ats[2];
+
+ ats[0].type = htonl (GNUNET_ATS_QUALITY_NET_DISTANCE);
+ ats[0].value = htonl (1);
+ ats[1].type = htonl (GNUNET_ATS_NETWORK_TYPE);
+ ats[1].value = htonl (GNUNET_ATS_NET_WLAN);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Calling plugin->env->receive for session %p; %s; size: %u\n",
+ session, wlan_plugin_address_to_string (NULL,
+ session->mac->
+ addr.mac, 6),
+ htons (hdr->size));
+ plugin->env->receive (plugin->env->cls, &(session->target), hdr,
+ (const struct GNUNET_ATS_Information *) &ats, 2,
+ session, (const char *) &session->mac->addr,
+ sizeof (session->mac->addr));
+}
+
+/**
+ * Function used for to process the data received from the wlan interface
+ *
+ * @param cls the plugin handle
+ * @param session_light pointer to the struct holding known informations
+ * @param hdr hdr of the GNUNET_MessageHeader
+ * @param rxinfo pointer to the radiotap informations got with this packet FIXME: give ATS for info
+ */
+static void
+wlan_data_helper (void *cls, struct Session_light *session_light,
+ const struct GNUNET_MessageHeader *hdr,
+ const struct Radiotap_rx *rxinfo)
+{
+ struct Plugin *plugin = cls;
+ struct FragmentMessage *fm;
+ struct FragmentMessage *fm2;
+ struct GNUNET_PeerIdentity tmpsource;
+
+ GNUNET_assert (plugin != NULL);
+
+ //ADVERTISEMENT
+ if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_HELLO)
+ {
+
+ //TODO better DOS protection, error handling
+ //TODO test first than create session
+ GNUNET_assert (session_light != NULL);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_HELLO size: %u; %s\n",
+ ntohs (hdr->size), wlan_plugin_address_to_string (NULL,
+ session_light->addr.
+ mac, 6));
+ if (session_light->macendpoint == NULL)
+ {
+ session_light->macendpoint =
+ get_macendpoint (plugin, &session_light->addr, GNUNET_YES);
+ }
+
+
+ if (GNUNET_HELLO_get_id
+ ((const struct GNUNET_HELLO_Message *) hdr, &tmpsource) == GNUNET_OK)
+ {
+ session_light->session =
+ search_session (plugin, session_light->macendpoint, &tmpsource);
+ if (session_light->session == NULL)
+ {
+ session_light->session =
+ create_session (plugin, session_light->macendpoint, &tmpsource);
+ }
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ _("# wlan hello messages received"), 1,
+ GNUNET_NO);
+ plugin->env->receive (plugin->env->cls, &session_light->session->target,
+ hdr, NULL, 0, session_light->session,
+ (const char *) &session_light->session->mac->addr,
+ sizeof (session_light->session->mac->addr));
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_WARNING, PLUGIN_LOG_NAME,
+ "WLAN client not in session list and hello message is not okay\n");
+ return;
+ }
+ }
+
+ //FRAGMENT
+
+ else if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_FRAGMENT)
+ {
+
+ GNUNET_assert (session_light != NULL);
+ if (session_light->macendpoint == NULL)
+ {
+ session_light->macendpoint =
+ get_macendpoint (plugin, &session_light->addr, GNUNET_YES);
+ }
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_FRAGMENT with size: %u; mac endpoint %p: %s\n",
+ ntohs (hdr->size), session_light->macendpoint,
+ wlan_plugin_address_to_string (NULL,
+ session_light->addr.mac,
+ 6));
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ _("# wlan fragments received"), 1, GNUNET_NO);
+ int ret =
+ GNUNET_DEFRAGMENT_process_fragment (session_light->macendpoint->defrag,
+ hdr);
+
+ if (ret == GNUNET_NO)
+ {
+ session_light->macendpoint->dups++;
+ }
+ else if (ret == GNUNET_OK)
+ {
+ session_light->macendpoint->fragc++;
+ }
+ set_next_send (plugin);
+
+ }
+
+ //ACK
+
+ else if (ntohs (hdr->type) == GNUNET_MESSAGE_TYPE_FRAGMENT_ACK)
+ {
+ GNUNET_assert (session_light != NULL);
+ if (session_light->macendpoint == NULL)
+ {
+ session_light->macendpoint =
+ get_macendpoint (plugin, &session_light->addr, GNUNET_NO);
+ }
+
+ if (session_light->macendpoint == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Macendpoint does not exist for this GNUNET_MESSAGE_TYPE_FRAGMENT_ACK size: %u; %s\n",
+ ntohs (hdr->size), wlan_plugin_address_to_string (NULL,
+ session_light->addr.mac,
+ 6));
+ return;
+ }
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_data_helper got GNUNET_MESSAGE_TYPE_FRAGMENT_ACK size: %u; mac endpoint: %p; %s\n",
+ ntohs (hdr->size), session_light->macendpoint,
+ wlan_plugin_address_to_string (NULL,
+ session_light->addr.mac,
+ 6));
+ fm = session_light->macendpoint->sending_messages_head;
+ while (fm != NULL)
+ {
+ fm2 = fm->next;
+ GNUNET_STATISTICS_update (plugin->env->stats, _("# wlan acks received"),
+ 1, GNUNET_NO);
+ int ret = GNUNET_FRAGMENT_process_ack (fm->fragcontext, hdr);
+
+ if (ret == GNUNET_OK)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Got last ack, finished fragment message %p\n", fm);
+ session_light->macendpoint->acks++;
+ fm->session->last_activity = GNUNET_TIME_absolute_get ();
+ session_light->macendpoint->last_activity = fm->session->last_activity;
+ free_fragment_message (plugin, fm);
+ check_fragment_queue (plugin);
+ return;
+ }
+ if (ret == GNUNET_NO)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Got ack for: %p\n", fm);
+ session_light->macendpoint->acks++;
+ return;
+ }
+ if (ret == GNUNET_SYSERR)
+ {
+
+ }
+
+ fm = fm2;
+ }
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "WLAN fragment not in fragment list\n");
+ return;
+
+ }
+ else
+ {
+ // TODO Wrong data?
+ GNUNET_log_from (GNUNET_ERROR_TYPE_INFO, PLUGIN_LOG_NAME,
+ "WLAN packet inside the WLAN helper packet has not the right type: %u size: %u\n",
+ ntohs (hdr->type), ntohs (hdr->size));
+ GNUNET_break (0);
+ return;
+ }
+
+#if 0
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Helper finished\n");
+#endif
+
+}
+
+/**
+ * Function to print mac addresses nice *
+ * @param pointer to 6 byte with the mac address
+ * @return pointer to the chars which hold the print out
+ */
+static const char *
+macprinter (const u_int8_t * mac)
+{
+ static char macstr[20];
+
+ GNUNET_snprintf (macstr, sizeof (macstr), "%X:%X:%X:%X:%X:%X", mac[0], mac[1],
+ mac[2], mac[3], mac[4], mac[5]);
+ return macstr;
+}
+
+/**
+ * Function for the scheduler if a mac endpoint times out
+ * @param cls pointer to the MacEndpoint
+ * @param tc pointer to the GNUNET_SCHEDULER_TaskContext
+ */
+static void
+macendpoint_timeout (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct MacEndpoint *endpoint = cls;
+
+ GNUNET_assert (endpoint != NULL);
+ endpoint->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ if (tc->reason == GNUNET_SCHEDULER_REASON_SHUTDOWN)
+ {
+ return;
+ }
+ if (GNUNET_TIME_absolute_get_remaining
+ (GNUNET_TIME_absolute_add
+ (endpoint->last_activity, MACENDPOINT_TIMEOUT)).rel_value == 0)
+ {
+ GNUNET_assert (endpoint->plugin != NULL);
+ GNUNET_STATISTICS_update (endpoint->plugin->env->stats,
+ _("# wlan mac endpoints timeouts"), 1, GNUNET_NO);
+ free_macendpoint (endpoint->plugin, endpoint);
+ }
+ else
+ {
+ endpoint->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout,
+ endpoint);
+ }
+}
+
+/**
+ * function to create an macendpoint
+ * @param plugin pointer to the plugin struct
+ * @param addr pointer to the macaddress
+ * @return returns a macendpoint
+ */
+static struct MacEndpoint *
+create_macendpoint (struct Plugin *plugin, const struct GNUNET_TRANSPORT_WLAN_MacAddress *addr)
+{
+ struct MacEndpoint *newend = GNUNET_malloc (sizeof (struct MacEndpoint));
+
+ GNUNET_assert (plugin != NULL);
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ _("# wlan mac endpoints created"), 1, GNUNET_NO);
+ newend->addr = *addr;
+ newend->plugin = plugin;
+ newend->addr = *addr;
+ newend->fragment_messages_out_count = 0;
+ newend->defrag =
+ GNUNET_DEFRAGMENT_context_create (plugin->env->stats, WLAN_MTU,
+ MESSAGES_IN_DEFRAG_QUEUE_PER_MAC,
+ newend, &wlan_data_message_handler,
+ &add_ack_for_send);
+ newend->last_activity = GNUNET_TIME_absolute_get ();
+ newend->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (MACENDPOINT_TIMEOUT, &macendpoint_timeout,
+ newend);
+
+ plugin->mac_count++;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"),
+ plugin->mac_count, GNUNET_NO);
+ GNUNET_CONTAINER_DLL_insert_tail (plugin->mac_head, plugin->mac_tail, newend);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "New Mac Endpoint %p: %s\n", newend,
+ wlan_plugin_address_to_string (NULL, newend->addr.mac, 6));
+ return newend;
+}
+
+/**
+ * Function used for to process the data from the suid process
+ *
+ * @param cls the plugin handle
+ * @param client client that send the data (not used)
+ * @param hdr header of the GNUNET_MessageHeader
+ */
+static void
+wlan_process_helper (void *cls, void *client,
+ const struct GNUNET_MessageHeader *hdr)
+{
+ struct Plugin *plugin = cls;
+ struct ieee80211_frame *wlanIeeeHeader = NULL;
+ struct Session_light *session_light = NULL;
+ struct Radiotap_rx *rxinfo;
+ const struct GNUNET_MessageHeader *temp_hdr = NULL;
+
+ int datasize = 0;
+ int pos;
+
+ GNUNET_assert (plugin != NULL);
+ switch (ntohs (hdr->type))
+ {
+ case GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA:
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_process_helper got GNUNET_MESSAGE_TYPE_WLAN_HELPER_DATA size: %u\n",
+ ntohs (hdr->size));
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ _("# wlan WLAN_HELPER_DATA received"), 1,
+ GNUNET_NO);
+ //call wlan_process_helper with the message inside, later with wlan: analyze signal
+ if (ntohs (hdr->size) <
+ sizeof (struct ieee80211_frame) +
+ 2 * sizeof (struct GNUNET_MessageHeader) + sizeof (struct Radiotap_rx))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Size of packet is too small; size: %u min size: %u\n",
+ ntohs (hdr->size),
+ sizeof (struct ieee80211_frame) +
+ sizeof (struct GNUNET_MessageHeader));
+ //GNUNET_break (0);
+ /* FIXME: restart SUID process */
+ return;
+ }
+
+ rxinfo = (struct Radiotap_rx *) &hdr[1];
+ wlanIeeeHeader = (struct ieee80211_frame *) &rxinfo[1];
+
+ //process only if it is an broadcast or for this computer both with the gnunet bssid
+
+ //check for bssid
+ if (memcmp
+ (&(wlanIeeeHeader->i_addr3), &mac_bssid_gnunet,
+ sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0)
+ {
+ //check for broadcast or mac
+ if ((memcmp
+ (&(wlanIeeeHeader->i_addr1), &bc_all_mac,
+ sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0) ||
+ (memcmp
+ (&(wlanIeeeHeader->i_addr1), &(plugin->mac_address),
+ sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0))
+ {
+ //if packet is from us return
+ if ((memcmp
+ (&(wlanIeeeHeader->i_addr2), &(plugin->mac_address),
+ sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)) == 0))
+ {
+ return;
+ }
+ // process the inner data
+
+
+ datasize =
+ ntohs (hdr->size) - sizeof (struct ieee80211_frame) -
+ sizeof (struct GNUNET_MessageHeader) - sizeof (struct Radiotap_rx);
+
+ session_light = GNUNET_malloc (sizeof (struct Session_light));
+ memcpy (&session_light->addr, &(wlanIeeeHeader->i_addr2),
+ sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
+ //session_light->session = search_session(plugin,session_light->addr);
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ _("# wlan messages for this client received"),
+ 1, GNUNET_NO);
+
+ pos = 0;
+ while (pos < datasize)
+ {
+ temp_hdr = (struct GNUNET_MessageHeader *) &wlanIeeeHeader[1] + pos;
+ if (ntohs (temp_hdr->size) <= datasize + pos)
+ {
+ GNUNET_STATISTICS_update (plugin->env->stats,
+ _
+ ("# wlan messages inside WLAN_HELPER_DATA received"),
+ 1, GNUNET_NO);
+ wlan_data_helper (plugin, session_light, temp_hdr, rxinfo);
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Size of packet is too small; size: %u > size of packet: %u\n",
+ ntohs (temp_hdr->size), datasize + pos);
+ }
+ pos += ntohs (temp_hdr->size);
+
+ }
+
+ //clean up
+ GNUNET_free (session_light);
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_process_helper got wrong MAC: %s\n",
+ macprinter (wlanIeeeHeader->i_addr1));
+ }
+ }
+ else
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_process_helper got wrong BSSID: %s\n",
+ macprinter (wlanIeeeHeader->i_addr2));
+ }
+ break;
+ case GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL:
+ //TODO more control messages
+ if (ntohs (hdr->size) != sizeof (struct GNUNET_TRANSPORT_WLAN_HelperControlMessage))
+ {
+ GNUNET_break (0);
+ /* FIXME: restart SUID process */
+ return;
+ }
+ memcpy (&plugin->mac_address, &hdr[1], sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Received WLAN_HELPER_CONTROL message with transport of address %s\n",
+ wlan_plugin_address_to_string (cls, &plugin->mac_address,
+ sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress)));
+ plugin->env->notify_address (plugin->env->cls, GNUNET_YES,
+ &plugin->mac_address,
+ sizeof (struct GNUNET_TRANSPORT_WLAN_MacAddress));
+ break;
+ default:
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "Func wlan_process_helper got unknown message with number %u, size %u\n",
+ ntohs (hdr->type), ntohs (hdr->size));
+
+#if DEBUG_WLAN > 1
+ hexdump (hdr, GNUNET_MIN (ntohs (hdr->size), 256));
+#endif
+ GNUNET_break (0);
+ return;
+ }
+}
+
+/**
+ * Exit point from the plugin.
+ * @param cls pointer to the api struct
+ */
+
+//FIXME cleanup
+void *
+libgnunet_plugin_transport_wlan_done (void *cls)
+{
+ struct GNUNET_TRANSPORT_PluginFunctions *api = cls;
+ struct Plugin *plugin = api->cls;
+ struct MacEndpoint *endpoint = plugin->mac_head;
+ struct MacEndpoint *endpoint_next;
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "libgnunet_plugin_transport_wlan_done started\n");
+ wlan_transport_stop_wlan_helper (plugin);
+
+ GNUNET_assert (cls != NULL);
+ //free sessions
+ while (endpoint != NULL)
+ {
+ endpoint_next = endpoint->next;
+ free_macendpoint (plugin, endpoint);
+ endpoint = endpoint_next;
+
+ }
+
+
+ if (plugin->suid_tokenizer != NULL)
+ GNUNET_SERVER_mst_destroy (plugin->suid_tokenizer);
+
+ if (plugin->data_tokenizer != NULL)
+ GNUNET_SERVER_mst_destroy (plugin->data_tokenizer);
+
+ GNUNET_free_non_null (plugin->interface);
+ GNUNET_free (plugin);
+ GNUNET_free (api);
+ return NULL;
+}
+
+/**
+ * Entry point for the plugin.
+ *
+ * @param cls closure, the 'struct GNUNET_TRANSPORT_PluginEnvironment*'
+ * @return the 'struct GNUNET_TRANSPORT_PluginFunctions*' or NULL on error
+ */
+void *
+libgnunet_plugin_transport_wlan_init (void *cls)
+{
+ //struct GNUNET_SERVICE_Context *service;
+ struct GNUNET_TRANSPORT_PluginEnvironment *env = cls;
+ struct GNUNET_TRANSPORT_PluginFunctions *api;
+ struct Plugin *plugin;
+
+ GNUNET_assert (cls != NULL);
+
+ plugin = GNUNET_malloc (sizeof (struct Plugin));
+ plugin->env = env;
+ plugin->pendingsessions = 0;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan pending sessions"),
+ plugin->pendingsessions, GNUNET_NO);
+ plugin->mac_count = 0;
+ GNUNET_STATISTICS_set (plugin->env->stats, _("# wlan mac endpoints"),
+ plugin->mac_count, GNUNET_NO);
+ plugin->server_write_task = GNUNET_SCHEDULER_NO_TASK;
+ plugin->server_read_task = GNUNET_SCHEDULER_NO_TASK;
+ plugin->server_write_delay_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_BANDWIDTH_tracker_init (&plugin->tracker,
+ GNUNET_BANDWIDTH_value_init (100 * 1024 *
+ 1024 / 8), 100);
+
+ plugin->suid_tokenizer =
+ GNUNET_SERVER_mst_create (&wlan_process_helper, plugin);
+
+ plugin->data_tokenizer = GNUNET_SERVER_mst_create (&process_data, plugin);
+
+ //plugin->sessions = GNUNET_malloc (sizeof (struct Sessionqueue));
+ //plugin->pending_Sessions_head = GNUNET_malloc (sizeof (struct Sessionqueue));
+
+ api = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PluginFunctions));
+ api->cls = plugin;
+ api->send = &wlan_plugin_send;
+ api->get_session = &wlan_plugin_get_session;
+ api->disconnect = &wlan_plugin_disconnect;
+ api->address_pretty_printer = &wlan_plugin_address_pretty_printer;
+ api->check_address = &wlan_plugin_address_suggested;
+ api->address_to_string = &wlan_plugin_address_to_string;
+
+ //read config
+
+ if (GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "TESTMODE"))
+ {
+ if (GNUNET_SYSERR ==
+ GNUNET_CONFIGURATION_get_value_number (env->cfg, "transport-wlan",
+ "TESTMODE", &(plugin->testmode)))
+ plugin->testmode = 0; //default value
+ }
+
+ if (GNUNET_CONFIGURATION_have_value (env->cfg, "transport-wlan", "INTERFACE"))
+ {
+ if (GNUNET_CONFIGURATION_get_value_string
+ (env->cfg, "transport-wlan", "INTERFACE",
+ &(plugin->interface)) != GNUNET_YES)
+ {
+ libgnunet_plugin_transport_wlan_done (api);
+ return NULL;
+ }
+ }
+
+ //start the plugin
+ wlan_transport_start_wlan_helper (plugin);
+ set_next_beacon_time (plugin);
+ set_next_send (plugin);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, PLUGIN_LOG_NAME,
+ "wlan init finished\n");
+ return api;
+}
+
+/* end of plugin_transport_wlan.c */
diff --git a/src/transport/plugin_transport_wlan.h b/src/transport/plugin_transport_wlan.h
new file mode 100644
index 0000000..9e1bc4f
--- /dev/null
+++ b/src/transport/plugin_transport_wlan.h
@@ -0,0 +1,152 @@
+/*
+ This file is part of GNUnet
+ (C) 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+ */
+
+/**
+ * @file transport/plugin_transport_wlan.h
+ * @brief header for transport plugin and the helper for wlan
+ * @author David Brodski
+ */
+#ifndef PLUGIN_TRANSPORT_WLAN
+#define PLUGIN_TRANSPORT_WLAN
+
+#include <stdint.h>
+#include "gnunet_common.h"
+
+/**
+ * Number fo bytes in a mac address.
+ */
+#define MAC_ADDR_SIZE 6
+
+GNUNET_NETWORK_STRUCT_BEGIN
+/**
+ * A MAC Address.
+ */
+struct GNUNET_TRANSPORT_WLAN_MacAddress
+{
+ uint8_t mac[MAC_ADDR_SIZE];
+};
+
+/**
+ * Format of a WLAN Control Message.
+ */
+struct GNUNET_TRANSPORT_WLAN_HelperControlMessage
+{
+ /**
+ * Message header. Type is
+ * GNUNET_MESSAGE_TYPE_WLAN_HELPER_CONTROL
+ */
+ struct GNUNET_MessageHeader hdr;
+
+ /**
+ * MAC Address of the local WLAN interface.
+ */
+ struct GNUNET_TRANSPORT_WLAN_MacAddress mac;
+};
+GNUNET_NETWORK_STRUCT_END
+
+/**
+ * GNUnet bssid
+ */
+static const struct GNUNET_TRANSPORT_WLAN_MacAddress mac_bssid_gnunet = {
+ {0x13, 0x22, 0x33, 0x44, 0x55, 0x66}
+};
+
+
+/**
+ * Broadcast MAC
+ */
+static const struct GNUNET_TRANSPORT_WLAN_MacAddress bc_all_mac = {
+ {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}
+};
+
+
+struct Radiotap_Send
+{
+ /**
+ * wlan send rate
+ */
+ uint8_t rate;
+
+ /**
+ * Antenna; the first antenna is 0.
+ */
+ uint8_t antenna;
+
+ /**
+ * Transmit power expressed as unitless distance from max power set at factory calibration.
+ * 0 is max power. Monotonically nondecreasing with lower power levels.
+ */
+ uint16_t tx_power;
+};
+
+
+/**
+ * struct to represent infos gathered form the radiotap fields, see RadiotapHeader for more Infos
+ */
+struct Radiotap_rx
+{
+ /**
+ * FIXME: not initialized properly so far. (supposed to contain
+ * information about which of the fields below are actually valid).
+ */
+ uint32_t ri_present;
+
+ /**
+ * IEEE80211_RADIOTAP_TSFT
+ */
+ uint64_t ri_mactime;
+
+ /**
+ * from radiotap
+ * either IEEE80211_RADIOTAP_DBM_ANTSIGNAL
+ * or IEEE80211_RADIOTAP_DB_ANTSIGNAL
+ */
+ int32_t ri_power;
+
+ /**
+ * either IEEE80211_RADIOTAP_DBM_ANTNOISE
+ * or IEEE80211_RADIOTAP_DB_ANTNOISE
+ */
+ int32_t ri_noise;
+
+ /**
+ * IEEE80211_RADIOTAP_CHANNEL
+ */
+ uint32_t ri_channel;
+
+ /**
+ * Frequency we use. FIXME: not properly initialized so far!
+ */
+ uint32_t ri_freq;
+
+ /**
+ * IEEE80211_RADIOTAP_RATE * 50000
+ */
+ uint32_t ri_rate;
+
+ /**
+ * IEEE80211_RADIOTAP_ANTENNA
+ */
+ uint32_t ri_antenna;
+};
+
+
+
+#endif
diff --git a/src/transport/template_cfg_peer1.conf b/src/transport/template_cfg_peer1.conf
new file mode 100644
index 0000000..ba05e93
--- /dev/null
+++ b/src/transport/template_cfg_peer1.conf
@@ -0,0 +1,50 @@
+@INLINE@ test_transport_defaults.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p1/
+DEFAULTCONFIG = template_cfg_peer1.conf
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+DISABLEV6 = NO
+
+[transport-tcp]
+PORT = 12000
+TIMEOUT = 5 s
+
+[transport-udp]
+BROADCAST = NO
+
+[arm]
+PORT = 12005
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12004
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12003
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12002
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+#PREFIX = valgrind --leak-check=full
+PORT = 12001
+#DEBUG = YES
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+[ats]
+#DEBUG = YES
+WAN_QUOTA_IN = 1 GB
+WAN_QUOTA_OUT = 1 GB
+PORT = 12006
+UNIXPATH = /tmp/gnunet-p1-service-ats.sock
+
+
diff --git a/src/transport/template_cfg_peer2.conf b/src/transport/template_cfg_peer2.conf
new file mode 100644
index 0000000..0a0e74a
--- /dev/null
+++ b/src/transport/template_cfg_peer2.conf
@@ -0,0 +1,50 @@
+@INLINE@ test_transport_defaults.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p2/
+DEFAULTCONFIG = template_cfg_peer2.conf
+
+[gnunetd]
+HOSTKEY = $SERVICEHOME/.hostkey
+
+[nat]
+RETURN_LOCAL_ADDRESSES = YES
+DISABLEV6 = NO
+
+[transport-tcp]
+PORT = 12100
+TIMEOUT = 5 s
+
+[transport-udp]
+BROADCAST = NO
+
+[arm]
+PORT = 12014
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12013
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12012
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12011
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+TRUST = $SERVICEHOME/data/credit/
+
+[transport]
+#PREFIX = valgrind --leak-check=full
+PORT = 12010
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+[ats]
+#DEBUG = YES
+WAN_QUOTA_IN = 1 GB
+WAN_QUOTA_OUT = 1 GB
+PORT = 12016
+UNIXPATH = /tmp/gnunet-p2-service-ats.sock
+
+
diff --git a/src/transport/test_plugin_transport_data.conf b/src/transport/test_plugin_transport_data.conf
new file mode 100644
index 0000000..adc7a59
--- /dev/null
+++ b/src/transport/test_plugin_transport_data.conf
@@ -0,0 +1,25 @@
+@INLINE@ test_transport_defaults.conf
+[PATHS]
+SERVICEHOME = /tmp/test-gnunetd-plugin-transport/
+DEFAULTCONFIG = test_plugin_transport_data.conf
+
+[transport-tcp]
+PORT = 2368
+TIMEOUT = 5 s
+
+[arm]
+PORT = 2366
+
+[statistics]
+PORT = 2367
+
+[resolver]
+PORT = 2364
+
+[peerinfo]
+PORT = 2369
+
+[transport]
+PORT = 2365
+
+
diff --git a/src/transport/test_plugin_transport_data_udp.conf b/src/transport/test_plugin_transport_data_udp.conf
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/src/transport/test_plugin_transport_data_udp.conf
@@ -0,0 +1 @@
+
diff --git a/src/transport/test_quota_compliance.c b/src/transport/test_quota_compliance.c
new file mode 100644
index 0000000..8f4db53
--- /dev/null
+++ b/src/transport/test_quota_compliance.c
@@ -0,0 +1,632 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_quota_compliance.c
+ * @brief base test case for transport implementations
+ *
+ * This test case tests quota compliance both on transport level
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_transport_service.h"
+#include "gauger.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * Testcase timeout
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 20)
+
+#define DURATION GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 5)
+
+static char *test_source;
+
+static char *test_plugin;
+
+static char *test_name;
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier measure_task;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+struct PeerContext *sender;
+
+struct PeerContext *receiver;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+char *cfg_file_p1;
+char *gen_cfg_p2;
+unsigned long long quota_in_p1;
+unsigned long long quota_out_p1;
+
+char *cfg_file_p2;
+char *gen_cfg_p1;
+unsigned long long quota_in_p2;
+unsigned long long quota_out_p2;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+
+/*
+ * Testcase specific declarations
+ */
+
+/**
+ * Note that this value must not significantly exceed
+ * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
+ * messages may be dropped even for a reliable transport.
+ */
+#define TOTAL_MSGS (1024 * 2)
+
+#define MTYPE 12345
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+struct TestMessage
+{
+ struct GNUNET_MessageHeader header;
+ uint32_t num;
+};
+GNUNET_NETWORK_STRUCT_END
+
+static int msg_scheduled;
+static int msg_sent;
+static int msg_recv_expected;
+static int msg_recv;
+
+static int test_failed;
+static int test_connected;
+
+static unsigned long long total_bytes_sent;
+
+static struct GNUNET_TIME_Absolute start_time;
+
+/*
+ * END Testcase specific declarations
+ */
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+
+static void
+end ()
+{
+ unsigned long long delta;
+ unsigned long long datarate;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value;
+ datarate = (total_bytes_sent * 1000) / delta;
+
+ FPRINTF (stderr, "Throughput was %llu b/s\n", datarate);
+
+ test_failed = GNUNET_NO;
+ if (datarate > quota_in_p2)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Datarate of %llu b/s higher than allowed inbound quota of %llu b/s\n",
+ datarate, quota_in_p2);
+ test_failed = GNUNET_YES;
+ }
+ if (datarate > quota_out_p1)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Datarate of %llu b/s higher than allowed outbound quota of %llu b/s\n",
+ datarate, quota_out_p1);
+ test_failed = GNUNET_YES;
+ }
+ if (test_failed == GNUNET_NO)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Datarate of %llu b/s complied to allowed outbound quota of %llu b/s and inbound quota of %llu b/s\n",
+ datarate, quota_out_p1, quota_in_p2);
+ }
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (cc != NULL)
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+}
+
+static void
+end_badly ()
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ if (measure_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (measure_task);
+
+ if (test_connected == GNUNET_YES)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n");
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n");
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (cc != NULL)
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ ok = GNUNET_SYSERR;
+}
+
+
+static unsigned int
+get_size (unsigned int iter)
+{
+ unsigned int ret;
+
+ ret = (iter * iter * iter);
+ return sizeof (struct TestMessage) + (ret % 60000);
+}
+
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ static int n;
+ unsigned int s;
+ char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ const struct TestMessage *hdr;
+
+ hdr = (const struct TestMessage *) message;
+ s = get_size (n);
+ if (MTYPE != ntohs (message->type))
+ return;
+ msg_recv_expected = n;
+ msg_recv = ntohl (hdr->num);
+ if (ntohs (message->size) != (s))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u of size %u, got %u bytes of message %u\n",
+ n, s, ntohs (message->size), ntohl (hdr->num));
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_failed = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+ if (ntohl (hdr->num) != n)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u of size %u, got %u bytes of message %u\n",
+ n, s, ntohs (message->size), ntohl (hdr->num));
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_failed = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+ memset (cbuf, n, s - sizeof (struct TestMessage));
+ if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u with bits %u, but body did not match\n", n,
+ (unsigned char) n);
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_failed = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+#if VERBOSE
+ if (ntohl (hdr->num) % 5000 == 0)
+ {
+ struct PeerContext *p = cls;
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
+ p->no, ps, ntohl (hdr->num), ntohs (message->size),
+ GNUNET_i2s (peer));
+ GNUNET_free (ps);
+ }
+#endif
+ n++;
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ static int n;
+ char *cbuf = buf;
+ struct TestMessage hdr;
+ unsigned int s;
+ unsigned int ret;
+
+ th = NULL;
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout occurred while waiting for transmit_ready for message %u of %u\n",
+ msg_scheduled, TOTAL_MSGS);
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ ok = 42;
+ return 0;
+ }
+
+ ret = 0;
+ s = get_size (n);
+ GNUNET_assert (size >= s);
+ GNUNET_assert (buf != NULL);
+ cbuf = buf;
+ do
+ {
+ hdr.header.size = htons (s);
+ hdr.header.type = htons (MTYPE);
+ hdr.num = htonl (n);
+ msg_sent = n;
+ memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage));
+ ret += sizeof (struct TestMessage);
+ memset (&cbuf[ret], n, s - sizeof (struct TestMessage));
+ ret += s - sizeof (struct TestMessage);
+#if VERBOSE
+ if (n % 5000 == 0)
+ {
+
+ char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message of size %u from peer %u (`%4s') -> peer %u (`%s') !\n",
+ n, sender->no, GNUNET_i2s (&sender->id), receiver->no,
+ receiver_s);
+ GNUNET_free (receiver_s);
+ }
+#endif
+ n++;
+ s = get_size (n);
+ if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
+ break; /* sometimes pack buffer full, sometimes not */
+ }
+ while (size - ret >= s);
+ if (n < TOTAL_MSGS)
+ {
+ if (th == NULL)
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0,
+ TIMEOUT_TRANSMIT,
+ &notify_ready, NULL);
+ msg_scheduled = n;
+ }
+ if (n % 5000 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Returning total message block of size %u\n", ret);
+ }
+ total_bytes_sent += ret;
+ if (n == TOTAL_MSGS)
+ {
+ FPRINTF (stderr, "%s", "\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All messages sent\n");
+ }
+ return ret;
+}
+
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+
+ struct PeerContext *p = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') connected to us!\n",
+ p->no, GNUNET_i2s (peer));
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerContext *p = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') disconnected!\n", p->no,
+ GNUNET_i2s (peer));
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+}
+
+static void
+sendtask ()
+{
+ start_time = GNUNET_TIME_absolute_get ();
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0,
+ TIMEOUT_TRANSMIT, &notify_ready,
+ NULL);
+}
+
+
+static void
+measure (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ static int counter;
+
+ measure_task = GNUNET_SCHEDULER_NO_TASK;
+
+ counter++;
+ if ((DURATION.rel_value / 1000) < counter)
+ {
+ FPRINTF (stderr, "%s", ".\n");
+ GNUNET_SCHEDULER_add_now (&end, NULL);
+ }
+ else
+ {
+ FPRINTF (stderr, "%s", ".");
+ measure_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &measure, NULL);
+ }
+}
+
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
+ p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ cc = NULL;
+ test_connected = GNUNET_YES;
+
+ measure_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &measure, NULL);
+ GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+
+}
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ test_connected = GNUNET_NO;
+
+ sender = p2;
+ receiver = p1;
+
+ char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test tries to send from %u (%s) -> peer %u (%s)\n", sender->no,
+ sender_c, receiver->no, GNUNET_i2s (&receiver->id));
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+static char *
+generate_config (char *cfg_file, unsigned long long quota_in,
+ unsigned long long quota_out)
+{
+ char *fname = NULL;
+ struct GNUNET_CONFIGURATION_Handle *cfg = GNUNET_CONFIGURATION_create ();
+
+ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (cfg, cfg_file));
+ GNUNET_asprintf (&fname, "q_in_%llu_q_out_%llu_%s", quota_in, quota_out,
+ cfg_file);
+ GNUNET_CONFIGURATION_set_value_string (cfg, "PATHS", "DEFAULTCONFIG", fname);
+ GNUNET_CONFIGURATION_set_value_number (cfg, "ats", "WAN_QUOTA_IN", quota_in);
+ GNUNET_CONFIGURATION_set_value_number (cfg, "ats", "WAN_QUOTA_OUT",
+ quota_out);
+ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_write (cfg, fname));
+ GNUNET_CONFIGURATION_destroy (cfg);
+ return fname;
+}
+
+static void
+run_measurement (unsigned long long p1_quota_in,
+ unsigned long long p1_quota_out,
+ unsigned long long p2_quota_in,
+ unsigned long long p2_quota_out)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+
+ /* setting ATS quota */
+ quota_out_p1 = p1_quota_out;
+ gen_cfg_p1 = generate_config (cfg_file_p1, p1_quota_in, p1_quota_out);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Generated config file `%s'\n",
+ gen_cfg_p1);
+
+ quota_in_p2 = p2_quota_in;
+ gen_cfg_p2 = generate_config (cfg_file_p2, p2_quota_in, p2_quota_out);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Generated config file `%s'\n",
+ gen_cfg_p2);
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, gen_cfg_p1, 1, &notify_receive,
+ &notify_connect, &notify_disconnect,
+ &start_cb, NULL);
+
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, gen_cfg_p2, 2, &notify_receive,
+ &notify_connect, &notify_disconnect,
+ &start_cb, NULL);
+
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ unsigned long long p1_quota_in = 10000;
+ unsigned long long p1_quota_out = 10000;
+ unsigned long long p2_quota_in = 10000;
+ unsigned long long p2_quota_out = 10000;
+
+ if (NULL != strstr (test_name, "asymmetric"))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Running asymmetric test with sending peer unlimited, receiving peer (in/out): %llu/%llu b/s \n",
+ p2_quota_in, p2_quota_out);
+ p1_quota_out = 1024 * 1024 * 1024;
+ p1_quota_in = 1024 * 1024 * 1024;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Running symmetric test with (in/out) %llu/%llu b/s \n",
+ p2_quota_in, p2_quota_out);
+ }
+ run_measurement (p1_quota_in, p1_quota_out, p2_quota_in, p2_quota_out);
+}
+
+static int
+check ()
+{
+ static char *argv[] = { "test_transport-quota-compliance",
+ "-c",
+ "test_quota_compliance_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
+ GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
+ &test_plugin);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
+
+ check ();
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ if (GNUNET_YES == GNUNET_DISK_file_test (gen_cfg_p1))
+ {
+ GNUNET_DISK_directory_remove (gen_cfg_p1);
+ GNUNET_free (gen_cfg_p1);
+ }
+
+ if (GNUNET_YES == GNUNET_DISK_file_test (gen_cfg_p2))
+ {
+ GNUNET_DISK_directory_remove (gen_cfg_p2);
+ GNUNET_free (gen_cfg_p2);
+ }
+
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ return test_failed;
+}
+
+
+/* end of test_quota_compliance.c */
diff --git a/src/transport/test_quota_compliance_data.conf b/src/transport/test_quota_compliance_data.conf
new file mode 100644
index 0000000..93f75dd
--- /dev/null
+++ b/src/transport/test_quota_compliance_data.conf
@@ -0,0 +1,25 @@
+@INLINE@ test_transport_defaults.conf
+[PATHS]
+SERVICEHOME = /tmp/test-gnunetd-plugin-transport/
+DEFAULTCONFIG = test_quota_compliance_data.conf
+
+[transport-tcp]
+PORT = 2368
+TIMEOUT = 5 s
+
+[arm]
+PORT = 2366
+
+[statistics]
+PORT = 2367
+
+[resolver]
+PORT = 2364
+
+[peerinfo]
+PORT = 2369
+
+[transport]
+PORT = 2365
+
+
diff --git a/src/transport/test_quota_compliance_http_asymmetric_peer1.conf b/src/transport/test_quota_compliance_http_asymmetric_peer1.conf
new file mode 100644
index 0000000..f56b157
--- /dev/null
+++ b/src/transport/test_quota_compliance_http_asymmetric_peer1.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer1
+DEFAULTCONFIG = test_quota_compliance_http_peer1.conf
+
+[transport-http]
+PORT = 4010
+
+[arm]
+PORT = 4015
+UNIXPATH = /tmp/test_quota_compliance_http_arm_peer1.sock
+
+[statistics]
+PORT = 4014
+UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer1.sock
+
+[resolver]
+PORT = 4013
+UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer1.sock
+
+[peerinfo]
+PORT = 4012
+UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer1.sock
+
+[transport]
+PORT = 4011
+PLUGINS = http
+UNIXPATH = /tmp/test_quota_compliance_http_transport_peer1.sock
+
+
diff --git a/src/transport/test_quota_compliance_http_asymmetric_peer2.conf b/src/transport/test_quota_compliance_http_asymmetric_peer2.conf
new file mode 100644
index 0000000..20ef582
--- /dev/null
+++ b/src/transport/test_quota_compliance_http_asymmetric_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer2
+DEFAULTCONFIG = test_quota_compliance_http_peer2.conf
+
+[transport-http]
+PORT = 3010
+
+[arm]
+PORT = 3015
+UNIXPATH = /tmp/test_quota_compliance_http_arm_peer2.sock
+
+[statistics]
+PORT = 3014
+UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer2.sock
+
+[resolver]
+PORT = 3013
+UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer2.sock
+
+[peerinfo]
+PORT = 3012
+UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer2.sock
+
+[transport]
+PORT = 3011
+PLUGINS = http
+UNIXPATH = /tmp/test_quota_compliance_http_transport_peer2.sock
+
+
diff --git a/src/transport/test_quota_compliance_http_peer1.conf b/src/transport/test_quota_compliance_http_peer1.conf
new file mode 100644
index 0000000..f56b157
--- /dev/null
+++ b/src/transport/test_quota_compliance_http_peer1.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer1
+DEFAULTCONFIG = test_quota_compliance_http_peer1.conf
+
+[transport-http]
+PORT = 4010
+
+[arm]
+PORT = 4015
+UNIXPATH = /tmp/test_quota_compliance_http_arm_peer1.sock
+
+[statistics]
+PORT = 4014
+UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer1.sock
+
+[resolver]
+PORT = 4013
+UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer1.sock
+
+[peerinfo]
+PORT = 4012
+UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer1.sock
+
+[transport]
+PORT = 4011
+PLUGINS = http
+UNIXPATH = /tmp/test_quota_compliance_http_transport_peer1.sock
+
+
diff --git a/src/transport/test_quota_compliance_http_peer2.conf b/src/transport/test_quota_compliance_http_peer2.conf
new file mode 100644
index 0000000..20ef582
--- /dev/null
+++ b/src/transport/test_quota_compliance_http_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer2
+DEFAULTCONFIG = test_quota_compliance_http_peer2.conf
+
+[transport-http]
+PORT = 3010
+
+[arm]
+PORT = 3015
+UNIXPATH = /tmp/test_quota_compliance_http_arm_peer2.sock
+
+[statistics]
+PORT = 3014
+UNIXPATH = /tmp/test_quota_compliance_http_statistics_peer2.sock
+
+[resolver]
+PORT = 3013
+UNIXPATH = /tmp/test_quota_compliance_http_resolver_peer2.sock
+
+[peerinfo]
+PORT = 3012
+UNIXPATH = /tmp/test_quota_compliance_http_peerinfo_peer2.sock
+
+[transport]
+PORT = 3011
+PLUGINS = http
+UNIXPATH = /tmp/test_quota_compliance_http_transport_peer2.sock
+
+
diff --git a/src/transport/test_quota_compliance_https_asymmetric_peer1.conf b/src/transport/test_quota_compliance_https_asymmetric_peer1.conf
new file mode 100644
index 0000000..ad4aab0
--- /dev/null
+++ b/src/transport/test_quota_compliance_https_asymmetric_peer1.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer1/
+DEFAULTCONFIG = test_quota_compliance_https_peer1.conf
+
+[transport-https]
+PORT = 4001
+KEY_FILE = https_key_quota_p1.key
+CERT_FILE = https_cert_quota_p1.crt
+
+[arm]
+PORT = 4006
+UNIXPATH = /tmp/test_quota_compliance_https_arm_peer1.sock
+
+[statistics]
+PORT = 4005
+UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer1.sock
+
+[resolver]
+PORT = 4004
+UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer1.sock
+
+[peerinfo]
+PORT = 4003
+UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer1.sock
+
+[transport]
+PORT = 4002
+PLUGINS = https
+UNIXPATH = /tmp/test_quota_compliance_https_transport_peer1.sock
+
+
diff --git a/src/transport/test_quota_compliance_https_asymmetric_peer2.conf b/src/transport/test_quota_compliance_https_asymmetric_peer2.conf
new file mode 100644
index 0000000..94d7412
--- /dev/null
+++ b/src/transport/test_quota_compliance_https_asymmetric_peer2.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer2
+DEFAULTCONFIG = test_quota_compliance_https_peer2.conf
+
+[transport-https]
+PORT = 3001
+KEY_FILE = https_key_quota_p2.key
+CERT_FILE = https_cert_qutoa_p2.crt
+
+[arm]
+PORT = 3006
+UNIXPATH = /tmp/test_quota_compliance_https_arm_peer2.sock
+
+[statistics]
+PORT = 3005
+UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer2.sock
+
+[resolver]
+PORT = 3004
+UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer2.sock
+
+[peerinfo]
+PORT = 3003
+UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer2.sock
+
+[transport]
+PORT = 3002
+PLUGINS = https
+UNIXPATH = /tmp/https_transport_peer2.sock
+
+
diff --git a/src/transport/test_quota_compliance_https_peer1.conf b/src/transport/test_quota_compliance_https_peer1.conf
new file mode 100644
index 0000000..ad4aab0
--- /dev/null
+++ b/src/transport/test_quota_compliance_https_peer1.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer1/
+DEFAULTCONFIG = test_quota_compliance_https_peer1.conf
+
+[transport-https]
+PORT = 4001
+KEY_FILE = https_key_quota_p1.key
+CERT_FILE = https_cert_quota_p1.crt
+
+[arm]
+PORT = 4006
+UNIXPATH = /tmp/test_quota_compliance_https_arm_peer1.sock
+
+[statistics]
+PORT = 4005
+UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer1.sock
+
+[resolver]
+PORT = 4004
+UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer1.sock
+
+[peerinfo]
+PORT = 4003
+UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer1.sock
+
+[transport]
+PORT = 4002
+PLUGINS = https
+UNIXPATH = /tmp/test_quota_compliance_https_transport_peer1.sock
+
+
diff --git a/src/transport/test_quota_compliance_https_peer2.conf b/src/transport/test_quota_compliance_https_peer2.conf
new file mode 100644
index 0000000..94d7412
--- /dev/null
+++ b/src/transport/test_quota_compliance_https_peer2.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer2
+DEFAULTCONFIG = test_quota_compliance_https_peer2.conf
+
+[transport-https]
+PORT = 3001
+KEY_FILE = https_key_quota_p2.key
+CERT_FILE = https_cert_qutoa_p2.crt
+
+[arm]
+PORT = 3006
+UNIXPATH = /tmp/test_quota_compliance_https_arm_peer2.sock
+
+[statistics]
+PORT = 3005
+UNIXPATH = /tmp/test_quota_compliance_https_statistics_peer2.sock
+
+[resolver]
+PORT = 3004
+UNIXPATH = /tmp/test_quota_compliance_https_resolver_peer2.sock
+
+[peerinfo]
+PORT = 3003
+UNIXPATH = /tmp/test_quota_compliance_https_peerinfo_peer2.sock
+
+[transport]
+PORT = 3002
+PLUGINS = https
+UNIXPATH = /tmp/https_transport_peer2.sock
+
+
diff --git a/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf b/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf
new file mode 100644
index 0000000..a7bac62
--- /dev/null
+++ b/src/transport/test_quota_compliance_tcp_asymmetric_peer1.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/quota-tcp-p1/
+DEFAULTCONFIG = test_quota_compliance_tcp_asymmetric_peer1.conf
+
+[transport-tcp]
+PORT = 4094
+
+[transport-udp]
+PORT = 4094
+
+[arm]
+PORT = 4087
+UNIXPATH = /tmp/test_quota_compliance_tcp_arm_peer1.sock
+
+[statistics]
+PORT = 4088
+UNIXPATH = /tmp/test_quota_compliance_tcp_statistics_peer1.sock
+
+[resolver]
+PORT = 4089
+UNIXPATH = /tmp/test_quota_compliance_tcp_resolver_peer1.sock
+
+[peerinfo]
+PORT = 4090
+UNIXPATH = /tmp/test_quota_compliance_tcp_peerinfo_peer1.sock
+
+[transport]
+PORT = 4091
+UNIXPATH = /tmp/test_quota_compliance_tcp_transport_peer1.sock
+
+
diff --git a/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf b/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf
new file mode 100644
index 0000000..75a4fe9
--- /dev/null
+++ b/src/transport/test_quota_compliance_tcp_asymmetric_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/quota-tcp-p2/
+DEFAULTCONFIG = test_quota_compliance_tcp_asymmetric_peer2.conf
+
+[transport-tcp]
+PORT = 12015
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12014
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12013
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12012
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12011
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12010
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
diff --git a/src/transport/test_quota_compliance_tcp_peer1.conf b/src/transport/test_quota_compliance_tcp_peer1.conf
new file mode 100644
index 0000000..ff63514
--- /dev/null
+++ b/src/transport/test_quota_compliance_tcp_peer1.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/quota-tcp-p1/
+DEFAULTCONFIG = test_quota_compliance_tcp_peer1.conf
+
+[transport-tcp]
+PORT = 4094
+
+[transport-udp]
+PORT = 4094
+
+[arm]
+PORT = 4087
+UNIXPATH = /tmp/test_quota_compliance_tcp_arm_peer1.sock
+
+[statistics]
+PORT = 4088
+UNIXPATH = /tmp/test_quota_compliance_tcp_statistics_peer1.sock
+
+[resolver]
+PORT = 4089
+UNIXPATH = /tmp/test_quota_compliance_tcp_resolver_peer1.sock
+
+[peerinfo]
+PORT = 4090
+UNIXPATH = /tmp/test_quota_compliance_tcp_peerinfo_peer1.sock
+
+[transport]
+PORT = 4091
+UNIXPATH = /tmp/test_quota_compliance_tcp_transport_peer1.sock
+
+
diff --git a/src/transport/test_quota_compliance_tcp_peer2.conf b/src/transport/test_quota_compliance_tcp_peer2.conf
new file mode 100644
index 0000000..18b199c
--- /dev/null
+++ b/src/transport/test_quota_compliance_tcp_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p2/
+DEFAULTCONFIG = test_quota_compliance_tcp_peer2.conf
+
+[transport-tcp]
+PORT = 12015
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12014
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12013
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12012
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12011
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12010
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
diff --git a/src/transport/test_quota_compliance_udp_peer1.conf b/src/transport/test_quota_compliance_udp_peer1.conf
new file mode 100644
index 0000000..fceee7b
--- /dev/null
+++ b/src/transport/test_quota_compliance_udp_peer1.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer1/
+DEFAULTCONFIG = test_quota_compliance_udp_peer1.conf
+
+[transport-udp]
+PORT = 4368
+MAX_BPS = 50000000
+
+[arm]
+PORT = 4087
+UNIXPATH = /tmp/test_quota_compliance_udp_arm_peer1.sock
+
+[statistics]
+PORT = 4088
+UNIXPATH = /tmp/test_quota_compliance_udp_statistics_peer1.sock
+
+[resolver]
+PORT = 4089
+UNIXPATH = /tmp/test_quota_compliance_udp_resolver_peer1.sock
+
+[peerinfo]
+PORT = 4090
+UNIXPATH = /tmp/test_quota_compliance_udp_peerinfo_peer1.sock
+
+[transport]
+PORT = 4091
+PLUGINS = udp
+UNIXPATH = /tmp/test_quota_compliance_udp_transport_peer1.sock
+
diff --git a/src/transport/test_quota_compliance_udp_peer2.conf b/src/transport/test_quota_compliance_udp_peer2.conf
new file mode 100644
index 0000000..4b58c93
--- /dev/null
+++ b/src/transport/test_quota_compliance_udp_peer2.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer2
+DEFAULTCONFIG = test_quota_compliance_udp_peer2.conf
+
+[transport-udp]
+PORT = 3368
+MAX_BPS = 50000000
+
+[arm]
+PORT = 3087
+UNIXPATH = /tmp/test_quota_compliance_udp_arm_peer2.sock
+
+[statistics]
+PORT = 3088
+UNIXPATH = /tmp/test_quota_compliance_udp_statistics_peer2.sock
+
+[resolver]
+PORT = 3089
+UNIXPATH = /tmp/test_quota_compliance_udp_resolver_peer2.sock
+
+[peerinfo]
+PORT = 3090
+UNIXPATH = /tmp/test_quota_compliance_udp_peerinfo_peer2.sock
+
+[transport]
+PORT = 3091
+PLUGINS = udp
+UNIXPATH = /tmp/test_quota_compliance_udp_transport_peer2.sock
+
+
diff --git a/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf b/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf
new file mode 100644
index 0000000..649cf1c
--- /dev/null
+++ b/src/transport/test_quota_compliance_unix_asymmetric_peer1.conf
@@ -0,0 +1,29 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer1/
+DEFAULTCONFIG = test_quota_compliance_unix_asymmetric_peer1.conf
+
+[arm]
+PORT = 4087
+UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer1.sock
+
+[statistics]
+PORT = 4088
+UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer1.sock
+
+[resolver]
+PORT = 4089
+UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer1.sock
+
+[peerinfo]
+PORT = 4090
+UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer1.sock
+
+[transport]
+PORT = 4091
+PLUGINS = unix
+UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer1.sock
+
+[transport-unix]
+PORT = 4092
+
diff --git a/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf b/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf
new file mode 100644
index 0000000..a2d1bdd
--- /dev/null
+++ b/src/transport/test_quota_compliance_unix_asymmetric_peer2.conf
@@ -0,0 +1,29 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer2
+DEFAULTCONFIG = test_quota_compliance_unix_asymmetric_peer2.conf
+
+[arm]
+PORT = 3087
+UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer2.sock
+
+[statistics]
+PORT = 3088
+UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer2.sock
+
+[resolver]
+PORT = 3089
+UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer2.sock
+
+[peerinfo]
+PORT = 3090
+UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer2.sock
+
+[transport]
+PORT = 3091
+PLUGINS = unix
+UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer2.sock
+
+[transport-unix]
+PORT = 3368
+
diff --git a/src/transport/test_quota_compliance_unix_peer1.conf b/src/transport/test_quota_compliance_unix_peer1.conf
new file mode 100644
index 0000000..60e656b
--- /dev/null
+++ b/src/transport/test_quota_compliance_unix_peer1.conf
@@ -0,0 +1,28 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer1/
+DEFAULTCONFIG = test_quota_compliance_unix_peer1.conf
+
+[transport-unix]
+PORT = 12120
+
+[arm]
+PORT = 4087
+UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer1.sock
+
+[statistics]
+PORT = 4088
+UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer1.sock
+
+[resolver]
+PORT = 4089
+UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer1.sock
+
+[peerinfo]
+PORT = 4090
+UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer1.sock
+
+[transport]
+PORT = 4091
+PLUGINS = unix
+UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer1.sock
diff --git a/src/transport/test_quota_compliance_unix_peer2.conf b/src/transport/test_quota_compliance_unix_peer2.conf
new file mode 100644
index 0000000..b4f0b64
--- /dev/null
+++ b/src/transport/test_quota_compliance_unix_peer2.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test_quota_compliance_peer2
+DEFAULTCONFIG = test_quota_compliance_unix_peer2.conf
+
+[transport-unix]
+PORT = 12136
+
+[arm]
+PORT = 3087
+UNIXPATH = /tmp/test_quota_compliance_unix_arm_peer2.sock
+
+[statistics]
+PORT = 3088
+UNIXPATH = /tmp/test_quota_compliance_unix_statistics_peer2.sock
+
+[resolver]
+PORT = 3089
+UNIXPATH = /tmp/test_quota_compliance_unix_resolver_peer2.sock
+
+[peerinfo]
+PORT = 3090
+UNIXPATH = /tmp/test_quota_compliance_unix_peerinfo_peer2.sock
+
+[transport]
+PORT = 3091
+PLUGINS = unix
+UNIXPATH = /tmp/test_quota_compliance_unix_transport_peer2.sock
+
+[transport-unix]
+PORT = 3368
+
diff --git a/src/transport/test_transport_api.c b/src/transport/test_transport_api.c
new file mode 100644
index 0000000..5fb81e1
--- /dev/null
+++ b/src/transport/test_transport_api.c
@@ -0,0 +1,442 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api.c
+ * @brief base test case for transport implementations
+ *
+ * This test case serves as a base for tcp, udp, and udp-nat
+ * transport test cases. Based on the executable being run
+ * the correct test case will be performed. Conservation of
+ * C code apparently.
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
+
+#define MSIZE 2600
+
+#define MTYPE 12345
+
+static char *test_source;
+
+static char *test_plugin;
+
+static char *test_name;
+
+static int ok;
+
+static int s_started;
+static int s_connected;
+static int s_sending;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier send_task;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+static void
+end ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+}
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+
+ if (cc != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n"));
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ cc = NULL;
+ }
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not ready to send data\n"));
+
+ if (s_started == GNUNET_NO)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were not started n"));
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peers were started n"));
+
+ if (s_connected == GNUNET_NO)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not connected\n"));
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were connected\n"));
+
+ if (s_sending == GNUNET_NO)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were not ready to send data\n"));
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer were ready to send data\n"));
+
+ th = NULL;
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer 1 was not started\n"));
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Peer 2 was not started\n"));
+
+ ok = GNUNET_SYSERR;
+}
+
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n",
+ p->no, ps, ntohs (message->type), ntohs (message->size), t->no,
+ GNUNET_i2s (&t->id));
+ GNUNET_free (ps);
+
+ if ((MTYPE == ntohs (message->type)) &&
+ (MSIZE == ntohs (message->size)))
+ {
+ ok = 0;
+ end ();
+ }
+ else
+ {
+ GNUNET_break (0);
+ ok = 1;
+ end ();
+ }
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ struct PeerContext *p = cls;
+ struct GNUNET_MessageHeader *hdr;
+
+ th = NULL;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout occurred while waiting for transmit_ready\n");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ ok = 42;
+ return 0;
+ }
+
+ GNUNET_assert (size >= MSIZE);
+
+ if (buf != NULL)
+ {
+ hdr = buf;
+ hdr->size = htons (MSIZE);
+ hdr->type = htons (MTYPE);
+ }
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id));
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n",
+ p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no,
+ GNUNET_i2s (&p->id));
+ GNUNET_free (ps);
+
+ return MSIZE;
+}
+
+
+static void
+sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+ char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n",
+ p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s);
+ GNUNET_free (receiver_s);
+ s_sending = GNUNET_YES;
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, MSIZE, 0,
+ TIMEOUT_TRANSMIT, &notify_ready,
+ p1);
+}
+
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ static int c;
+
+ c++;
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps,
+ t->no, GNUNET_i2s (peer));
+ GNUNET_free (ps);
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerContext *p = cls;
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps,
+ GNUNET_i2s (peer));
+
+ GNUNET_free (ps);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ cc = NULL;
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
+ p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ s_connected = GNUNET_YES;
+ send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+}
+
+
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+ else
+ s_started = GNUNET_YES;
+ char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
+ p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (sender_c);
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+
+ s_started = GNUNET_NO;
+ s_connected = GNUNET_NO;
+ s_sending = GNUNET_NO;
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+}
+
+
+static int
+check ()
+{
+ static char *const argv[] = { "test-transport-api",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+ GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
+ GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
+ &test_plugin);
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
+
+ ret = check ();
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ return ret;
+}
+
+/* end of test_transport_api.c */
diff --git a/src/transport/test_transport_api_bidirectional_connect.c b/src/transport/test_transport_api_bidirectional_connect.c
new file mode 100644
index 0000000..604554c
--- /dev/null
+++ b/src/transport/test_transport_api_bidirectional_connect.c
@@ -0,0 +1,415 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api_bidirectional_connect.c
+ * @brief base test case for transport implementations
+ *
+ * Perform a 3-way handshake connection set up in both directions at
+ * (almost) the same time
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+#define MTYPE 12345
+
+static char *test_source;
+
+static char *test_plugin;
+
+static char *test_name;
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier send_task;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc1;
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc2;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+
+static void
+end ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+}
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+
+ if (cc2 != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n"));
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc2);
+ cc2 = NULL;
+ }
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ ok = GNUNET_SYSERR;
+}
+
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n",
+ p->no, ps, ntohs (message->type), ntohs (message->size), t->no,
+ GNUNET_i2s (&t->id));
+
+ if ((MTYPE == ntohs (message->type)) &&
+ (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)))
+ {
+ ok = 0;
+ end ();
+ }
+ else
+ {
+ GNUNET_break (0);
+ ok = 1;
+ end ();
+ }
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ struct PeerContext *p = cls;
+ struct GNUNET_MessageHeader *hdr;
+
+ th = NULL;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout occurred while waiting for transmit_ready\n");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ ok = 42;
+ return 0;
+ }
+
+ GNUNET_assert (size >= 256);
+
+ if (buf != NULL)
+ {
+ hdr = buf;
+ hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
+ hdr->type = htons (MTYPE);
+ }
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n",
+ p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no,
+ GNUNET_i2s (&p->id));
+ GNUNET_free (ps);
+ return sizeof (struct GNUNET_MessageHeader);
+}
+
+
+static void
+sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+ char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n",
+ p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s);
+ GNUNET_free (receiver_s);
+
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0,
+ TIMEOUT_TRANSMIT, &notify_ready,
+ p1);
+}
+
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ static int c;
+
+ c++;
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps,
+ t->no, GNUNET_i2s (peer));
+ GNUNET_free (ps);
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerContext *p = cls;
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps,
+ GNUNET_i2s (peer));
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ if (cls == cc1)
+ {
+ cc1 = NULL;
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc2);
+ }
+ if (cls == cc2)
+ {
+ cc2 = NULL;
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc1);
+ }
+
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
+ p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+}
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test tries to connect peer %u (`%s') <-> peer %u (`%s')\n",
+ p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
+
+ cc1 =
+ GNUNET_TRANSPORT_TESTING_connect_peers (tth, p2, p1, &testing_connect_cb,
+ NULL);
+ cc2 =
+ GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+}
+
+
+static int
+check ()
+{
+ static char *const argv[] = { "test-transport-api",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
+ GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
+ &test_plugin);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
+
+ ret = check ();
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ return ret;
+}
+
+/* end of test_transport_api_bidirectional_connect.c */
diff --git a/src/transport/test_transport_api_bidirectional_connect_peer1.conf b/src/transport/test_transport_api_bidirectional_connect_peer1.conf
new file mode 100644
index 0000000..21591b5
--- /dev/null
+++ b/src/transport/test_transport_api_bidirectional_connect_peer1.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p1/
+DEFAULTCONFIG = test_transport_api_bidirectional_connect_peer1.conf
+
+[transport-tcp]
+PORT = 12000
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12005
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12004
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12003
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12002
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12001
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+#DEBUG = YES
+
diff --git a/src/transport/test_transport_api_bidirectional_connect_peer2.conf b/src/transport/test_transport_api_bidirectional_connect_peer2.conf
new file mode 100644
index 0000000..db3ba8c
--- /dev/null
+++ b/src/transport/test_transport_api_bidirectional_connect_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p2/
+DEFAULTCONFIG = test_transport_api_bidirectional_connect_peer2.conf
+
+[transport-tcp]
+PORT = 12015
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12014
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12013
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12012
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12011
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12010
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
diff --git a/src/transport/test_transport_api_blacklisting.c b/src/transport/test_transport_api_blacklisting.c
new file mode 100644
index 0000000..f8f6040
--- /dev/null
+++ b/src/transport/test_transport_api_blacklisting.c
@@ -0,0 +1,480 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/transport_api_blacklisting.c
+ * @brief test for the blacklisting API
+ * @author Matthias Wachs
+ *
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+#define MSIZE 2600
+
+#define MTYPE 12345
+
+
+static int ok;
+static int connected;
+static int blacklist_request_p1;
+static int blacklist_request_p2;
+
+struct GNUNET_TRANSPORT_Blacklist * blacklist_p1;
+
+struct GNUNET_TRANSPORT_Blacklist * blacklist_p2;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier send_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier shutdown_task;
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+
+static void
+end (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping\n");
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (cc != NULL)
+ {
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel(tth, cc);
+ cc = NULL;
+ }
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (blacklist_p1 != NULL)
+ {
+ GNUNET_TRANSPORT_blacklist_cancel (blacklist_p1);
+ blacklist_p1 = NULL;
+ }
+
+ if (blacklist_p2 != NULL)
+ {
+ GNUNET_TRANSPORT_blacklist_cancel (blacklist_p2);
+ blacklist_p2 = NULL;
+ }
+
+ if (p1 != NULL)
+ {
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ p1 = NULL;
+ }
+ if (p2 != NULL)
+ {
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+ p2 = NULL;
+ }
+
+ if ((blacklist_request_p1 == GNUNET_YES) &&
+ (blacklist_request_p2 == GNUNET_YES) &&
+ (connected == GNUNET_NO))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Peers were not connected, success\n"));
+ ok = 0;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, _("Peers were not connected, fail\n"));
+ ok = 1;
+ }
+}
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (send_task);
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (shutdown_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (shutdown_task);
+ shutdown_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (cc != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n"));
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ cc = NULL;
+ }
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (blacklist_p1 != NULL)
+ GNUNET_TRANSPORT_blacklist_cancel (blacklist_p1);
+
+ if (blacklist_p2 != NULL)
+ GNUNET_TRANSPORT_blacklist_cancel (blacklist_p2);
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ ok = GNUNET_SYSERR;
+}
+
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n",
+ p->no, ps, ntohs (message->type), ntohs (message->size), t->no,
+ GNUNET_i2s (&t->id));
+ GNUNET_free (ps);
+
+ if ((MTYPE == ntohs (message->type)) &&
+ (MSIZE == ntohs (message->size)))
+ {
+ ok = 0;
+ shutdown_task = GNUNET_SCHEDULER_add_now(&end, NULL);
+ }
+ else
+ {
+ GNUNET_break (0);
+ ok = 1;
+ shutdown_task = GNUNET_SCHEDULER_add_now(&end, NULL);
+ }
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ struct PeerContext *p = cls;
+ struct GNUNET_MessageHeader *hdr;
+
+ th = NULL;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout occurred while waiting for transmit_ready\n");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ {
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ ok = 42;
+ return 0;
+ }
+
+ GNUNET_assert (size >= MSIZE);
+
+ if (buf != NULL)
+ {
+ hdr = buf;
+ hdr->size = htons (MSIZE);
+ hdr->type = htons (MTYPE);
+ }
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id));
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n",
+ p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no,
+ GNUNET_i2s (&p->id));
+ GNUNET_free (ps);
+
+ return MSIZE;
+}
+
+static void
+sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+ char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n",
+ p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s);
+ GNUNET_free (receiver_s);
+
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, MSIZE, 0,
+ TIMEOUT_TRANSMIT, &notify_ready,
+ p1);
+}
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ static int c;
+
+ c++;
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps,
+ t->no, GNUNET_i2s (peer));
+ GNUNET_free (ps);
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerContext *p = cls;
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps,
+ GNUNET_i2s (peer));
+
+ GNUNET_free (ps);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ cc = NULL;
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
+ p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+
+
+ send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+}
+
+
+int blacklist_cb (void *cls,
+ const struct
+ GNUNET_PeerIdentity * pid)
+{
+ struct PeerContext * p = cls;
+ int res = GNUNET_SYSERR;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u : Blacklist request for peer `%s'\n", p->no, GNUNET_i2s (pid));
+
+ if (p == p1)
+ {
+ blacklist_request_p1 = GNUNET_YES;
+ res = GNUNET_OK;
+ }
+ else if (p == p2)
+ {
+ blacklist_request_p2 = GNUNET_YES;
+ res = GNUNET_SYSERR;
+ }
+
+ if (((blacklist_request_p2 == GNUNET_YES) && (blacklist_request_p1 == GNUNET_YES)) && (shutdown_task == GNUNET_SCHEDULER_NO_TASK))
+ {
+ shutdown_task = GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply(GNUNET_TIME_UNIT_SECONDS, 3), &end, NULL);
+ }
+
+ return res;
+}
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
+ p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (sender_c);
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+ connected = GNUNET_NO;
+ blacklist_request_p1 = GNUNET_NO;
+ blacklist_request_p2 = GNUNET_NO;
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, "test_transport_api_tcp_peer1.conf", 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, "test_transport_api_tcp_peer2.conf", 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ blacklist_p1 = GNUNET_TRANSPORT_blacklist (p1->cfg,
+ &blacklist_cb,
+ p1);
+
+ blacklist_p2 = GNUNET_TRANSPORT_blacklist (p2->cfg,
+ &blacklist_cb,
+ p2);
+
+ GNUNET_assert (blacklist_p1 != NULL);
+ GNUNET_assert (blacklist_p2 != NULL);
+}
+
+
+static int
+check ()
+{
+ static char *const argv[] = { "test-transport-api-blacklisting",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, "test-transport-api-blacklisting",
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_log_setup ("test-transport-api-blacklisting",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ ret = check ();
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ return ret;
+}
+
+/* end of transport_api_blacklisting.c */
diff --git a/src/transport/test_transport_api_data.conf b/src/transport/test_transport_api_data.conf
new file mode 100644
index 0000000..3955246
--- /dev/null
+++ b/src/transport/test_transport_api_data.conf
@@ -0,0 +1,12 @@
+@INLINE@ test_transport_defaults.conf
+[PATHS]
+DEFAULTCONFIG = test_transport_api_data.conf
+
+[transport-tcp]
+PORT = 2094
+
+[transport-udp]
+PORT = 2094
+
+
+
diff --git a/src/transport/test_transport_api_disconnect.c b/src/transport/test_transport_api_disconnect.c
new file mode 100644
index 0000000..973c4cf
--- /dev/null
+++ b/src/transport/test_transport_api_disconnect.c
@@ -0,0 +1,436 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api_disconnect.c
+ * @brief base test case for transport implementations
+ *
+ * This test case tests disconnect notifications in peer shutdown
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 120)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+#define MTYPE 12345
+
+static char *test_source;
+
+static char *test_plugin;
+
+static char *test_name;
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier send_task;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+int shutdown_;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+
+static void
+end ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (send_task);
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ p1 = NULL;
+
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+ p2 = NULL;
+
+ /* success */
+ ok = 0;
+}
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ if (cc != NULL)
+ {
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ cc = NULL;
+ }
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (send_task);
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ ok = GNUNET_SYSERR;
+}
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerContext *p = cls;
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps,
+ GNUNET_i2s (peer));
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (shutdown_ == GNUNET_YES)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Complete, shutting down...\n");
+ GNUNET_SCHEDULER_add_now (&end, NULL);
+ }
+}
+
+
+static void
+stop_peer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+
+ struct PeerContext *p = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Shutting down peer %u (`%s')\n", p->no,
+ GNUNET_i2s (&p->id));
+ shutdown_ = GNUNET_YES;
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+ p2 = NULL;
+ GNUNET_assert (p2 == NULL);
+}
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n",
+ p->no, ps, ntohs (message->type), ntohs (message->size), t->no,
+ GNUNET_i2s (&t->id));
+
+ if ((MTYPE == ntohs (message->type)) &&
+ (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)))
+ {
+ ok = 1;
+ GNUNET_SCHEDULER_add_now (stop_peer, p2);
+ return;
+ }
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ struct PeerContext *p = cls;
+ struct GNUNET_MessageHeader *hdr;
+
+ th = NULL;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout occurred while waiting for transmit_ready\n");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ ok = 42;
+ return 0;
+ }
+
+ GNUNET_assert (size >= 256);
+
+ if (buf != NULL)
+ {
+ hdr = buf;
+ hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
+ hdr->type = htons (MTYPE);
+ }
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n",
+ p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no,
+ GNUNET_i2s (&p->id));
+ GNUNET_free (ps);
+ return sizeof (struct GNUNET_MessageHeader);
+}
+
+
+static void
+sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+ char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n",
+ p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s);
+ GNUNET_free (receiver_s);
+
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0,
+ TIMEOUT_TRANSMIT, &notify_ready,
+ p1);
+}
+
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ static int c;
+
+ c++;
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps,
+ t->no, GNUNET_i2s (peer));
+ GNUNET_free (ps);
+}
+
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ cc = NULL;
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
+ p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+}
+
+
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
+ p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+}
+
+
+static int
+check ()
+{
+ static char *const argv[] = { "test-transport-api",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
+ GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
+ &test_plugin);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
+
+ ret = check ();
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ return ret;
+}
+
+/* end of test_transport_api.c */
diff --git a/src/transport/test_transport_api_disconnect_tcp_peer1.conf b/src/transport/test_transport_api_disconnect_tcp_peer1.conf
new file mode 100644
index 0000000..8bfa374
--- /dev/null
+++ b/src/transport/test_transport_api_disconnect_tcp_peer1.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p1/
+DEFAULTCONFIG = test_transport_api_tcp_peer1.conf
+
+[transport-tcp]
+PORT = 12000
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12005
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12004
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12003
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12002
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12001
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+#DEBUG = YES
+
diff --git a/src/transport/test_transport_api_disconnect_tcp_peer2.conf b/src/transport/test_transport_api_disconnect_tcp_peer2.conf
new file mode 100644
index 0000000..6bb7fad
--- /dev/null
+++ b/src/transport/test_transport_api_disconnect_tcp_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p2/
+DEFAULTCONFIG = test_transport_api_tcp_peer2.conf
+
+[transport-tcp]
+PORT = 12015
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12014
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12013
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12012
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12011
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12010
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
diff --git a/src/transport/test_transport_api_http_nat_peer1.conf b/src/transport/test_transport_api_http_nat_peer1.conf
new file mode 100644
index 0000000..447508c
--- /dev/null
+++ b/src/transport/test_transport_api_http_nat_peer1.conf
@@ -0,0 +1,38 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-http-p1/
+DEFAULTCONFIG = test_transport_api_http_nat_peer1.conf
+
+[nat]
+BEHIND_NAT = YES
+ENABLE_NAT_SERVER = YES
+
+[transport-http]
+PORT = 0
+
+[arm]
+PORT = 12085
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12084
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12083
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12082
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+#DEBUG = YES
+PORT = 12081
+PLUGINS = http
+#BINARY = .libs/gnunet-service-transport
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+#PREFIX = valgrind --leak-check=full
+#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
+
diff --git a/src/transport/test_transport_api_http_nat_peer2.conf b/src/transport/test_transport_api_http_nat_peer2.conf
new file mode 100644
index 0000000..2f56eab
--- /dev/null
+++ b/src/transport/test_transport_api_http_nat_peer2.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-http-p2/
+DEFAULTCONFIG = test_transport_api_http_nat_peer2.conf
+
+[transport-http]
+PORT = 12090
+
+[arm]
+PORT = 12095
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12094
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12093
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12092
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+#DEBUG = YES
+PORT = 12091
+PLUGINS = http
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+#PREFIX = valgrind --leak-check=full
diff --git a/src/transport/test_transport_api_http_peer1.conf b/src/transport/test_transport_api_http_peer1.conf
new file mode 100644
index 0000000..26c2969
--- /dev/null
+++ b/src/transport/test_transport_api_http_peer1.conf
@@ -0,0 +1,34 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-http-p1/
+DEFAULTCONFIG = test_transport_api_http_peer1.conf
+
+[transport-http]
+PORT = 12080
+
+[arm]
+PORT = 12085
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12084
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12083
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12082
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+#DEBUG = YES
+PORT = 12081
+PLUGINS = http
+#BINARY = .libs/gnunet-service-transport
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+#PREFIX = valgrind --leak-check=full
+#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
+
diff --git a/src/transport/test_transport_api_http_peer2.conf b/src/transport/test_transport_api_http_peer2.conf
new file mode 100644
index 0000000..fa7aa3b
--- /dev/null
+++ b/src/transport/test_transport_api_http_peer2.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-http-p2/
+DEFAULTCONFIG = test_transport_api_http_peer2.conf
+
+[transport-http]
+PORT = 12090
+
+[arm]
+PORT = 12095
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12094
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12093
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12092
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+#DEBUG = YES
+PORT = 12091
+PLUGINS = http
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+#PREFIX = valgrind --leak-check=full
diff --git a/src/transport/test_transport_api_https_nat_peer1.conf b/src/transport/test_transport_api_https_nat_peer1.conf
new file mode 100644
index 0000000..e97b473
--- /dev/null
+++ b/src/transport/test_transport_api_https_nat_peer1.conf
@@ -0,0 +1,36 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-https-p1/
+DEFAULTCONFIG = test_transport_api_https_nat_peer1.conf
+
+[nat]
+BEHIND_NAT = YES
+ENABLE_NAT_SERVER = YES
+
+[transport-https]
+PORT = 0
+KEY_FILE = $SERVICEHOME/https_key_p1.key
+CERT_FILE = $SERVICEHOME/https_cert_p1.crt
+
+[arm]
+PORT = 12105
+
+[statistics]
+PORT = 12104
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12103
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12102
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12101
+PLUGINS = https
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+DEBUG = NO
+
+
diff --git a/src/transport/test_transport_api_https_nat_peer2.conf b/src/transport/test_transport_api_https_nat_peer2.conf
new file mode 100644
index 0000000..a23f3a5
--- /dev/null
+++ b/src/transport/test_transport_api_https_nat_peer2.conf
@@ -0,0 +1,33 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-https-p2/
+DEFAULTCONFIG = test_transport_api_https_nat_peer2.conf
+
+[transport-https]
+PORT = 12110
+KEY_FILE = $SERVICEHOME/https_key_p2.key
+CERT_FILE = $SERVICEHOME/https_cert_p2.crt
+
+[arm]
+PORT = 12115
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12114
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12113
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12112
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12111
+PLUGINS = https
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+DEBUG = NO
+
+
diff --git a/src/transport/test_transport_api_https_peer1.conf b/src/transport/test_transport_api_https_peer1.conf
new file mode 100644
index 0000000..8a93ca1
--- /dev/null
+++ b/src/transport/test_transport_api_https_peer1.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-https-p1/
+DEFAULTCONFIG = test_transport_api_https_peer1.conf
+
+[transport-https]
+PORT = 12100
+KEY_FILE = $SERVICEHOME/https_key_p1.key
+CERT_FILE = $SERVICEHOME/https_cert_p1.crt
+
+[arm]
+PORT = 12105
+
+[statistics]
+PORT = 12104
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12103
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12102
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12101
+PLUGINS = https
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+DEBUG = NO
+
+
diff --git a/src/transport/test_transport_api_https_peer2.conf b/src/transport/test_transport_api_https_peer2.conf
new file mode 100644
index 0000000..0710f41
--- /dev/null
+++ b/src/transport/test_transport_api_https_peer2.conf
@@ -0,0 +1,33 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-https-p2/
+DEFAULTCONFIG = test_transport_api_https_peer2.conf
+
+[transport-https]
+PORT = 12110
+KEY_FILE = $SERVICEHOME/https_key_p2.key
+CERT_FILE = $SERVICEHOME/https_cert_p2.crt
+
+[arm]
+PORT = 12115
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12114
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12113
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12112
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12111
+PLUGINS = https
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+DEBUG = NO
+
+
diff --git a/src/transport/test_transport_api_limited_sockets.c b/src/transport/test_transport_api_limited_sockets.c
new file mode 100644
index 0000000..8b8cdc0
--- /dev/null
+++ b/src/transport/test_transport_api_limited_sockets.c
@@ -0,0 +1,383 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api.c
+ * @brief base test case for transport implementations
+ *
+ * This test case serves as a base for tcp, udp, and udp-nat
+ * transport test cases. Based on the executable being run
+ * the correct test case will be performed. Conservation of
+ * C code apparently.
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 300)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+#define MTYPE 12345
+
+#define MAX_FILES 50
+
+static char *test_source;
+
+static char *test_plugin;
+
+static char *test_name;
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier send_task;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+
+static void
+end ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+}
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+
+ if (cc != NULL)
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ ok = GNUNET_SYSERR;
+}
+
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received message of type %d from peer %s!\n",
+ ntohs (message->type), GNUNET_i2s (peer));
+
+ if ((MTYPE == ntohs (message->type)) &&
+ (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)))
+ {
+ ok = 0;
+ end ();
+ }
+ else
+ {
+ GNUNET_break (0);
+ ok = 1;
+ end ();
+ }
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ struct PeerContext *p = cls;
+ struct GNUNET_MessageHeader *hdr;
+
+ th = NULL;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting message with %u bytes to peer %s\n",
+ sizeof (struct GNUNET_MessageHeader), GNUNET_i2s (&p->id));
+ GNUNET_assert (size >= 256);
+
+ if (buf != NULL)
+ {
+ hdr = buf;
+ hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
+ hdr->type = htons (MTYPE);
+ }
+ return sizeof (struct GNUNET_MessageHeader);
+}
+
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n",
+ GNUNET_i2s (peer), cls);
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n",
+ GNUNET_i2s (peer), cls);
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+}
+
+static void
+sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p1->th, &p2->id, 256, 0, TIMEOUT,
+ &notify_ready, &p1);
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ cc = NULL;
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c,
+ GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ // FIXME: THIS IS REQUIRED! SEEMS TO BE A BUG!
+ send_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &sendtask, NULL);
+}
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+}
+
+
+static int
+check ()
+{
+ static char *const argv[] = { "test-transport-api",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret = 0;
+
+ test_plugin = NULL;
+
+ GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
+ GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
+ &test_plugin);
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+#if !HAVE_SETRLIMIT
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Cannot run test on this system\n");
+
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+
+ return 0;
+#else
+ struct rlimit r_file_old;
+ struct rlimit r_file_new;
+ int res;
+
+ res = getrlimit (RLIMIT_NOFILE, &r_file_old);
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Maximum number of open files was: %u/%u\n", r_file_old.rlim_cur,
+ r_file_old.rlim_max);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Setting maximum number of open files to: %u\n", MAX_FILES);
+ r_file_new.rlim_cur = MAX_FILES;
+ r_file_new.rlim_max = r_file_old.rlim_max;
+ res = setrlimit (RLIMIT_NOFILE, &r_file_new);
+
+ if (res != 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Setting limit failed!\n");
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+ return 0;
+ }
+
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
+ ret = check ();
+#endif
+
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+
+#if HAVE_SETRLIMIT
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Restoring previous value maximum number of open files\n");
+ res = setrlimit (RLIMIT_NOFILE, &r_file_old);
+ if (res != 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Restoring limit failed!\n");
+ return 0;
+ }
+#endif
+
+ return ret;
+}
+
+/* end of test_transport_api.c */
diff --git a/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf b/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf
new file mode 100644
index 0000000..dee44f6
--- /dev/null
+++ b/src/transport/test_transport_api_limited_sockets_tcp_peer1.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p1/
+DEFAULTCONFIG = test_transport_api_tcp_peer1.conf
+
+[transport-tcp]
+PORT = 12000
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12005
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12004
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12003
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12002
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12001
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf b/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf
new file mode 100644
index 0000000..04324f4
--- /dev/null
+++ b/src/transport/test_transport_api_limited_sockets_tcp_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p2/
+DEFAULTCONFIG = test_transport_api_tcp_peer2.conf
+
+[transport-tcp]
+PORT = 0
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12014
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12013
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12012
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12011
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12010
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
diff --git a/src/transport/test_transport_api_multi_peer1.conf b/src/transport/test_transport_api_multi_peer1.conf
new file mode 100644
index 0000000..a7c57fc
--- /dev/null
+++ b/src/transport/test_transport_api_multi_peer1.conf
@@ -0,0 +1,43 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-multi-p1/
+DEFAULTCONFIG = test_transport_api_multi_peer1.conf
+
+[transport-tcp]
+PORT = 12140
+TIMEOUT = 5 s
+
+[transport-udp]
+PORT = 12141
+
+[transport-http]
+PORT = 12142
+
+[transport-https]
+PORT = 12143
+
+[arm]
+PORT = 12149
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12148
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12147
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12146
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12145
+PLUGINS = tcp udp unix
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+[transport-unix]
+PORT = 12144
+
diff --git a/src/transport/test_transport_api_multi_peer2.conf b/src/transport/test_transport_api_multi_peer2.conf
new file mode 100644
index 0000000..8008e7f
--- /dev/null
+++ b/src/transport/test_transport_api_multi_peer2.conf
@@ -0,0 +1,46 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-multi-p2/
+DEFAULTCONFIG = test_transport_api_multi_peer2.conf
+
+[nat]
+ALLOW_NAT = NO
+
+[transport-tcp]
+PORT = 12150
+TIMEOUT = 5 s
+
+[transport-udp]
+PORT = 12151
+
+[transport-http]
+PORT = 12152
+
+[transport-https]
+PORT = 12153
+
+[arm]
+PORT = 12159
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12158
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12157
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12156
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12155
+PLUGINS = tcp udp unix
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+[transport-unix]
+PORT = 12154
+
diff --git a/src/transport/test_transport_api_reliability.c b/src/transport/test_transport_api_reliability.c
new file mode 100644
index 0000000..f719a42
--- /dev/null
+++ b/src/transport/test_transport_api_reliability.c
@@ -0,0 +1,538 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api_reliability.c
+ * @brief base test case for transport implementations
+ *
+ * This test case serves as a base for tcp and http
+ * transport test cases to check that the transports
+ * achieve reliable message delivery.
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_transport_service.h"
+#include "gauger.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * Testcase timeout
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 10)
+
+
+static char *test_source;
+
+static char *test_plugin;
+
+static char *test_name;
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+struct PeerContext *sender;
+
+struct PeerContext *receiver;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+
+/*
+ * Testcase specific declarations
+ */
+
+/**
+ * Note that this value must not significantly exceed
+ * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
+ * messages may be dropped even for a reliable transport.
+ */
+#define TOTAL_MSGS (1024 * 2)
+
+#define MTYPE 12345
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+struct TestMessage
+{
+ struct GNUNET_MessageHeader header;
+ uint32_t num;
+};
+GNUNET_NETWORK_STRUCT_END
+
+static int msg_scheduled;
+static int msg_sent;
+static int msg_recv_expected;
+static int msg_recv;
+
+static int test_failed;
+static int test_connected;
+
+static unsigned long long total_bytes;
+
+static struct GNUNET_TIME_Absolute start_time;
+
+/*
+ * END Testcase specific declarations
+ */
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+
+static void
+end ()
+{
+ unsigned long long delta;
+
+ char *value_name;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value;
+ FPRINTF (stderr, "\nThroughput was %llu kb/s\n",
+ total_bytes * 1000 / 1024 / delta);
+ GNUNET_asprintf (&value_name, "reliable_%s", test_plugin);
+ GAUGER ("TRANSPORT", value_name, (int) (total_bytes * 1000 / 1024 / delta),
+ "kb/s");
+ GNUNET_free (value_name);
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (cc != NULL)
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+}
+
+static void
+end_badly ()
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ if (test_connected == GNUNET_YES)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n");
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n");
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (cc != NULL)
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ ok = GNUNET_SYSERR;
+}
+
+
+static unsigned int
+get_size (unsigned int iter)
+{
+ unsigned int ret;
+
+ ret = (iter * iter * iter);
+ return sizeof (struct TestMessage) + (ret % 60000);
+}
+
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ static int n;
+ unsigned int s;
+ char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ const struct TestMessage *hdr;
+
+ hdr = (const struct TestMessage *) message;
+ s = get_size (n);
+ if (MTYPE != ntohs (message->type))
+ return;
+ msg_recv_expected = n;
+ msg_recv = ntohl (hdr->num);
+ if (ntohs (message->size) != (s))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u of size %u, got %u bytes of message %u\n",
+ n, s, ntohs (message->size), ntohl (hdr->num));
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_failed = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+ if (ntohl (hdr->num) != n)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u of size %u, got %u bytes of message %u\n",
+ n, s, ntohs (message->size), ntohl (hdr->num));
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_failed = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+ memset (cbuf, n, s - sizeof (struct TestMessage));
+ if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u with bits %u, but body did not match\n", n,
+ (unsigned char) n);
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_failed = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+#if VERBOSE
+ if (ntohl (hdr->num) % 5000 == 0)
+ {
+ struct PeerContext *p = cls;
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%s') got message %u of size %u from peer (`%s')\n",
+ p->no, ps, ntohl (hdr->num), ntohs (message->size),
+ GNUNET_i2s (peer));
+ GNUNET_free (ps);
+ }
+#endif
+ n++;
+ if (0 == (n % (TOTAL_MSGS / 100)))
+ {
+ FPRINTF (stderr, "%s", ".");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+ }
+ if (n == TOTAL_MSGS)
+ {
+ ok = 0;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "\nAll messages received\n");
+ end ();
+ }
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ static int n;
+ char *cbuf = buf;
+ struct TestMessage hdr;
+ unsigned int s;
+ unsigned int ret;
+
+ th = NULL;
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout occurred while waiting for transmit_ready for message %u of %u\n",
+ msg_scheduled, TOTAL_MSGS);
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ ok = 42;
+ return 0;
+ }
+
+ ret = 0;
+ s = get_size (n);
+ GNUNET_assert (size >= s);
+ GNUNET_assert (buf != NULL);
+ cbuf = buf;
+ do
+ {
+ hdr.header.size = htons (s);
+ hdr.header.type = htons (MTYPE);
+ hdr.num = htonl (n);
+ msg_sent = n;
+ memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage));
+ ret += sizeof (struct TestMessage);
+ memset (&cbuf[ret], n, s - sizeof (struct TestMessage));
+ ret += s - sizeof (struct TestMessage);
+#if VERBOSE
+ if (n % 5000 == 0)
+ {
+
+ char *receiver_s = GNUNET_strdup (GNUNET_i2s (&receiver->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message of size %u from peer %u (`%4s') -> peer %u (`%s') !\n",
+ n, sender->no, GNUNET_i2s (&sender->id), receiver->no,
+ receiver_s);
+ GNUNET_free (receiver_s);
+ }
+#endif
+ n++;
+ s = get_size (n);
+ if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
+ break; /* sometimes pack buffer full, sometimes not */
+ }
+ while (size - ret >= s);
+ if (n < TOTAL_MSGS)
+ {
+ if (th == NULL)
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0,
+ TIMEOUT_TRANSMIT,
+ &notify_ready, NULL);
+ msg_scheduled = n;
+ }
+ if (n % 5000 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Returning total message block of size %u\n", ret);
+ }
+ total_bytes += ret;
+ if (n == TOTAL_MSGS)
+ {
+ FPRINTF (stderr, "%s", "\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All messages sent\n");
+ }
+ return ret;
+}
+
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+
+ struct PeerContext *p = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') connected to us!\n",
+ p->no, GNUNET_i2s (peer));
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerContext *p = cls;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%4s') disconnected!\n", p->no,
+ GNUNET_i2s (peer));
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+}
+
+static void
+sendtask ()
+{
+ start_time = GNUNET_TIME_absolute_get ();
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0,
+ TIMEOUT_TRANSMIT, &notify_ready,
+ NULL);
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
+ p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ test_connected = GNUNET_YES;
+ cc = NULL;
+
+ GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+
+}
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ test_connected = GNUNET_NO;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u: `%s' using configuration file `%s'\n", p1->no,
+ GNUNET_i2s (&p1->id), cfg_file_p1);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u: `%s' using configuration file `%s'\n", p2->no,
+ GNUNET_i2s (&p2->id), cfg_file_p2);
+
+ sender = p2;
+ receiver = p1;
+
+ char *sender_c = GNUNET_strdup (GNUNET_i2s (&sender->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test triest to send from %u (%s) -> peer %u (%s)\n", sender->no,
+ sender_c, receiver->no, GNUNET_i2s (&receiver->id));
+ GNUNET_free (sender_c);
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+}
+
+static int
+check ()
+{
+ static char *argv[] = { "test_transport",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
+ GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
+ &test_plugin);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
+
+ ret = check ();
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+
+ return ret;
+}
+
+
+/* end of test_transport_api_reliability.c */
diff --git a/src/transport/test_transport_api_reliability_http_nat_peer1.conf b/src/transport/test_transport_api_reliability_http_nat_peer1.conf
new file mode 100644
index 0000000..cd841a3
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_http_nat_peer1.conf
@@ -0,0 +1,38 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-http-p1/
+DEFAULTCONFIG = test_transport_api_reliability_http_nat_peer1.conf
+
+[nat]
+BEHIND_NAT = YES
+ENABLE_NAT_SERVER = YES
+
+[transport-http]
+PORT = 0
+
+[arm]
+PORT = 12085
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12084
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12083
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12082
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+#DEBUG = YES
+PORT = 12081
+PLUGINS = http
+#BINARY = .libs/gnunet-service-transport
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+#PREFIX = valgrind --leak-check=full
+#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
+
diff --git a/src/transport/test_transport_api_reliability_http_nat_peer2.conf b/src/transport/test_transport_api_reliability_http_nat_peer2.conf
new file mode 100644
index 0000000..c87a256
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_http_nat_peer2.conf
@@ -0,0 +1,35 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-http-p2/
+DEFAULTCONFIG = test_transport_api_reliability_http_nat_peer2.conf
+
+[ats]
+WAN_QUOTA_OUT = 1073741824
+WAN_QUOTA_IN = 1073741824
+
+[transport-http]
+PORT = 12090
+
+[arm]
+PORT = 12095
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12094
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12093
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12092
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+#DEBUG = YES
+PORT = 12091
+PLUGINS = http
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+#PREFIX = valgrind --leak-check=full
diff --git a/src/transport/test_transport_api_reliability_http_peer1.conf b/src/transport/test_transport_api_reliability_http_peer1.conf
new file mode 100644
index 0000000..ebb6e43
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_http_peer1.conf
@@ -0,0 +1,33 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-http-p1/
+DEFAULTCONFIG = test_transport_api_reliability_http_peer1.conf
+
+[transport-tcp]
+TIMEOUT = 5 s
+
+[transport-http]
+PORT = 12180
+
+[arm]
+PORT = 12185
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12184
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12183
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12182
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12181
+PLUGINS = http
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+#DEBUG = YES
+
diff --git a/src/transport/test_transport_api_reliability_http_peer2.conf b/src/transport/test_transport_api_reliability_http_peer2.conf
new file mode 100644
index 0000000..c21fa1d
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_http_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-http-p2/
+DEFAULTCONFIG = test_transport_api_reliability_http_peer2.conf
+
+[transport-http]
+PORT = 12190
+
+[arm]
+PORT = 12195
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12194
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12193
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12192
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12191
+PLUGINS = http
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+#DEBUG = YES
+
diff --git a/src/transport/test_transport_api_reliability_https_nat_peer1.conf b/src/transport/test_transport_api_reliability_https_nat_peer1.conf
new file mode 100644
index 0000000..ca14c72
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_https_nat_peer1.conf
@@ -0,0 +1,36 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-https-p1/
+DEFAULTCONFIG = test_transport_api_reliability_https_nat_peer1.conf
+
+[nat]
+BEHIND_NAT = YES
+ENABLE_NAT_SERVER = YES
+
+[transport-https]
+PORT = 0
+KEY_FILE = $SERVICEHOME/https_key_p1.key
+CERT_FILE = $SERVICEHOME/https_cert_p1.crt
+
+[arm]
+PORT = 12105
+
+[statistics]
+PORT = 12104
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12103
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12102
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12101
+PLUGINS = https
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+DEBUG = NO
+
+
diff --git a/src/transport/test_transport_api_reliability_https_nat_peer2.conf b/src/transport/test_transport_api_reliability_https_nat_peer2.conf
new file mode 100644
index 0000000..b7c2e97
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_https_nat_peer2.conf
@@ -0,0 +1,33 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-https-p2/
+DEFAULTCONFIG = test_transport_api_reliability_https_nat_peer2.conf
+
+[transport-https]
+PORT = 12110
+KEY_FILE = $SERVICEHOME/https_key_p2.key
+CERT_FILE = $SERVICEHOME/https_cert_p2.crt
+
+[arm]
+PORT = 12115
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12114
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12113
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12112
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12111
+PLUGINS = https
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+DEBUG = NO
+
+
diff --git a/src/transport/test_transport_api_reliability_https_peer1.conf b/src/transport/test_transport_api_reliability_https_peer1.conf
new file mode 100644
index 0000000..0699f69
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_https_peer1.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-https-p1/
+DEFAULTCONFIG = test_transport_api_reliability_https_peer1.conf
+
+[transport-https]
+PORT = 12300
+KEY_FILE = $SERVICEHOME/https_key_p1.key
+CERT_FILE = $SERVICEHOME/https_cert_p1.crt
+
+[arm]
+PORT = 12305
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12304
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12303
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12302
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12301
+PLUGINS = https
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
diff --git a/src/transport/test_transport_api_reliability_https_peer2.conf b/src/transport/test_transport_api_reliability_https_peer2.conf
new file mode 100644
index 0000000..bd344ab
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_https_peer2.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-https-p2/
+DEFAULTCONFIG = test_transport_api_reliability_https_peer2.conf
+
+[transport-https]
+PORT = 12310
+KEY_FILE = $SERVICEHOME/https_key_p2.key
+CERT_FILE = $SERVICEHOME/https_cert_p2.crt
+
+[arm]
+PORT = 12315
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12314
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12313
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12312
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12311
+PLUGINS = https
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf b/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf
new file mode 100644
index 0000000..2f0b3ba
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_tcp_nat_peer1.conf
@@ -0,0 +1,36 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-reliability-tcp-nat-p1/
+DEFAULTCONFIG = test_transport_api_reliability_tcp_nat_peer1.conf
+
+[nat]
+BEHIND_NAT = YES
+ENABLE_NAT_SERVER = YES
+DISABLEV6 = YES
+
+[transport-tcp]
+PORT = 0
+TIMEOUT = 5 s
+
+[arm]
+PORT = 1204
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12023
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12022
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12021
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 29542
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf b/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf
new file mode 100644
index 0000000..20ca7a0
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_tcp_nat_peer2.conf
@@ -0,0 +1,35 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-reliability-tcp-nat-p2/
+DEFAULTCONFIG = test_transport_api_reliability_tcp_nat_peer2.conf
+
+[nat]
+DISABLEV6 = YES
+ENABLE_NAT_CLIENT = YES
+
+[transport-tcp]
+PORT = 12030
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12034
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12033
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12032
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12031
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 45923
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_reliability_tcp_peer1.conf b/src/transport/test_transport_api_reliability_tcp_peer1.conf
new file mode 100644
index 0000000..a05165a
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_tcp_peer1.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p1/
+DEFAULTCONFIG = test_transport_api_reliability_tcp_peer1.conf
+
+[transport-tcp]
+PORT = 12000
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12005
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12004
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12003
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12002
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12001
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
diff --git a/src/transport/test_transport_api_reliability_tcp_peer2.conf b/src/transport/test_transport_api_reliability_tcp_peer2.conf
new file mode 100644
index 0000000..2ceff2c
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_tcp_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p2/
+DEFAULTCONFIG = test_transport_api_reliability_tcp_peer2.conf
+
+[transport-tcp]
+PORT = 12015
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12014
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12013
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12012
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12011
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12010
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+#DEBUG = YES
diff --git a/src/transport/test_transport_api_reliability_wlan_peer1.conf b/src/transport/test_transport_api_reliability_wlan_peer1.conf
new file mode 100644
index 0000000..9dd9d1b
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_wlan_peer1.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-wlan-p1/
+DEFAULTCONFIG = test_transport_api_wlan_peer1.conf
+
+[transport-wlan]
+TESTMODE = 1
+
+[arm]
+PORT = 12164
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12163
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12162
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12161
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12160
+PLUGINS = wlan
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_reliability_wlan_peer2.conf b/src/transport/test_transport_api_reliability_wlan_peer2.conf
new file mode 100644
index 0000000..bc868d7
--- /dev/null
+++ b/src/transport/test_transport_api_reliability_wlan_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-wlan-p2/
+DEFAULTCONFIG = test_transport_api_wlan_peer2.conf
+
+[transport-wlan]
+INTERFACE = mon1
+TESTMODE = 2
+
+[arm]
+PORT = 12174
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12173
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12172
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12171
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12170
+PLUGINS = wlan
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
diff --git a/src/transport/test_transport_api_restart_1peer.c b/src/transport/test_transport_api_restart_1peer.c
new file mode 100644
index 0000000..b414805
--- /dev/null
+++ b/src/transport/test_transport_api_restart_1peer.c
@@ -0,0 +1,491 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api_restart_1peer.c
+ * @brief base test case for transport implementations
+ *
+ * This test case starts 2 peers, connects and exchanges a message
+ * 1 peer is restarted and tested if peers reconnect
+ * C code apparently.
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+#define MTYPE 12345
+
+static char *test_name;
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier send_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+
+struct PeerContext *p1;
+
+int p1_connected;
+
+struct PeerContext *p2;
+
+int p2_connected;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
+
+static int restarted;
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+
+static void
+end ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (reconnect_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (reconnect_task);
+ reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+}
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ if (restarted == GNUNET_YES)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was restarted\n");
+
+ if (restarted == GNUNET_NO)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was NOT restarted\n");
+
+ if (reconnect_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (reconnect_task);
+ reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (cc != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n"));
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ cc = NULL;
+ }
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ ok = GNUNET_SYSERR;
+}
+
+static void
+reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct PeerContext *p = cls;
+
+ reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_TRANSPORT_try_connect (p->th, &p2->id);
+ reconnect_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, p);
+}
+
+static void
+restart_cb (struct PeerContext *p, void *cls)
+{
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Restarted peer %u (`%4s'), issuing reconnect\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, p);
+}
+
+static void
+restart (struct PeerContext *p, char *cfg_file)
+{
+ GNUNET_assert (p != NULL);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting peer %u (`%4s')\n", p->no,
+ GNUNET_i2s (&p->id));
+ GNUNET_TRANSPORT_TESTING_restart_peer (tth, p, cfg_file, &restart_cb, p);
+ return;
+}
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n",
+ p->no, ps, ntohs (message->type), ntohs (message->size), t->no,
+ GNUNET_i2s (&t->id));
+ GNUNET_free (ps);
+
+ if ((MTYPE == ntohs (message->type)) &&
+ (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)))
+ {
+ if (restarted == GNUNET_NO)
+ {
+ restarted = GNUNET_YES;
+ restart (p1, cfg_file_p1);
+ return;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Restarted peers connected and message was sent, stopping test...\n");
+ ok = 0;
+ end ();
+ }
+ }
+ else
+ {
+ GNUNET_break (0);
+ ok = 1;
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ }
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ struct PeerContext *p = cls;
+ struct GNUNET_MessageHeader *hdr;
+
+ th = NULL;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout occurred while waiting for transmit_ready\n");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ ok = 42;
+ return 0;
+ }
+
+ GNUNET_assert (size >= 256);
+
+ if (buf != NULL)
+ {
+ hdr = buf;
+ hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
+ hdr->type = htons (MTYPE);
+ }
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n",
+ p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no,
+ GNUNET_i2s (&p->id));
+ GNUNET_free (ps);
+ return sizeof (struct GNUNET_MessageHeader);
+}
+
+
+static void
+sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+ char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n",
+ p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s);
+ GNUNET_free (receiver_s);
+
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0,
+ TIMEOUT_TRANSMIT, &notify_ready,
+ p1);
+}
+
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ static int c;
+
+ c++;
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ p1_connected = GNUNET_YES;
+ t = p1;
+ }
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ p2_connected = GNUNET_YES;
+ t = p2;
+ }
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps,
+ t->no, GNUNET_i2s (peer));
+ GNUNET_free (ps);
+
+ if ((restarted == GNUNET_YES) && ((p1_connected == GNUNET_YES) && (p2_connected == GNUNET_YES)))
+ {
+ /* Peer was restarted and we received 3 connect messages (2 from first connect, 1 from reconnect) */
+ send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+ }
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerContext *p = cls;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ p1_connected = GNUNET_NO;
+ }
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ {
+ p2_connected = GNUNET_NO;
+ }
+
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps,
+ GNUNET_i2s (peer));
+ GNUNET_free (ps);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ cc = NULL;
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
+ p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+}
+
+
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
+ p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (sender_c);
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+ p1_connected = GNUNET_NO;
+ p2_connected = GNUNET_NO;
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+}
+
+
+static int
+check ()
+{
+ static char *const argv[] = { "test-transport-api",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ GNUNET_asprintf (&cfg_file_p1, "test_transport_api_tcp_peer1.conf");
+ GNUNET_asprintf (&cfg_file_p2, "test_transport_api_tcp_peer2.conf");
+
+ ret = check ();
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ GNUNET_free (test_name);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ return ret;
+}
+
+/* end of test_transport_api_restart_1peer.c */
diff --git a/src/transport/test_transport_api_restart_2peers.c b/src/transport/test_transport_api_restart_2peers.c
new file mode 100644
index 0000000..86758df
--- /dev/null
+++ b/src/transport/test_transport_api_restart_2peers.c
@@ -0,0 +1,477 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api_restart_2peers.c
+ * @brief base test case for transport implementations
+ *
+ * This test case starts 2 peers, connects and exchanges a message
+ * boths peer are restarted and tested if peers reconnect
+ * C code apparently.
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+#define MTYPE 12345
+
+static char *test_name;
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier send_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
+
+static int restarted;
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+
+static void
+end ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (reconnect_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (reconnect_task);
+ reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+}
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ if (restarted == GNUNET_YES)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was restarted\n");
+
+ if (restarted == GNUNET_NO)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peer was NOT restarted\n");
+
+ if (reconnect_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (reconnect_task);
+ reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (send_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (send_task);
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if (cc != NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Fail! Could not connect peers\n"));
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ cc = NULL;
+ }
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ ok = GNUNET_SYSERR;
+}
+
+static void
+reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct PeerContext *p = cls;
+
+ reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_TRANSPORT_try_connect (p1->th, &p2->id);
+ reconnect_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &reconnect, p);
+}
+
+static void
+restart_cb (struct PeerContext *p, void *cls)
+{
+ static int c;
+
+ c++;
+
+ if (c != 2)
+ return;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Restarted peer %u (`%4s'), issuing reconnect\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, p);
+}
+
+static void
+restart (struct PeerContext *p, char *cfg_file)
+{
+ GNUNET_assert (p != NULL);
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Restarting peer %u (`%4s')\n", p->no,
+ GNUNET_i2s (&p->id));
+ GNUNET_TRANSPORT_TESTING_restart_peer (tth, p, cfg_file, &restart_cb, p);
+ return;
+}
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') received message of type %d and size %u size from peer %u (`%4s')!\n",
+ p->no, ps, ntohs (message->type), ntohs (message->size), t->no,
+ GNUNET_i2s (&t->id));
+ GNUNET_free (ps);
+
+ if ((MTYPE == ntohs (message->type)) &&
+ (sizeof (struct GNUNET_MessageHeader) == ntohs (message->size)))
+ {
+ if (restarted == GNUNET_NO)
+ {
+ restarted = GNUNET_YES;
+ restart (p1, cfg_file_p1);
+ restart (p2, cfg_file_p2);
+ return;
+ }
+ else
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Restarted peers connected, stopping test...\n");
+ ok = 0;
+ end ();
+ }
+ }
+ else
+ {
+ GNUNET_break (0);
+ ok = 1;
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ }
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ struct PeerContext *p = cls;
+ struct GNUNET_MessageHeader *hdr;
+
+ th = NULL;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout occurred while waiting for transmit_ready\n");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ ok = 42;
+ return 0;
+ }
+
+ GNUNET_assert (size >= 256);
+
+ if (buf != NULL)
+ {
+ hdr = buf;
+ hdr->size = htons (sizeof (struct GNUNET_MessageHeader));
+ hdr->type = htons (MTYPE);
+ }
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p2->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') sending message with type %u and size %u bytes to peer %u (`%4s')\n",
+ p2->no, ps, ntohs (hdr->type), ntohs (hdr->size), p->no,
+ GNUNET_i2s (&p->id));
+ GNUNET_free (ps);
+ return sizeof (struct GNUNET_MessageHeader);
+}
+
+
+static void
+sendtask (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+ char *receiver_s = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Sending message from peer %u (`%4s') -> peer %u (`%s') !\n",
+ p2->no, GNUNET_i2s (&p2->id), p1->no, receiver_s);
+ GNUNET_free (receiver_s);
+
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, 256, 0,
+ TIMEOUT_TRANSMIT, &notify_ready,
+ p1);
+}
+
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ static int c;
+
+ c++;
+ struct PeerContext *p = cls;
+ struct PeerContext *t = NULL;
+
+ if (0 == memcmp (peer, &p1->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p1;
+ if (0 == memcmp (peer, &p2->id, sizeof (struct GNUNET_PeerIdentity)))
+ t = p2;
+ GNUNET_assert (t != NULL);
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer %u (`%s') connected to me!\n", p->no, ps,
+ t->no, GNUNET_i2s (peer));
+ GNUNET_free (ps);
+
+ if ((restarted == GNUNET_YES) && (c == 4))
+ {
+ send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+ }
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerContext *p = cls;
+
+
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s'): peer (`%s') disconnected from me!\n", p->no, ps,
+ GNUNET_i2s (peer));
+ GNUNET_free (ps);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ cc = NULL;
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %u (%s) <-> %u (%s)\n",
+ p1->no, p1_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ send_task = GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+}
+
+
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
+ p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (sender_c);
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+}
+
+
+static int
+check ()
+{
+ static char *const argv[] = { "test-transport-api",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+ send_task = GNUNET_SCHEDULER_NO_TASK;
+
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ GNUNET_asprintf (&cfg_file_p1, "test_transport_api_tcp_peer1.conf");
+ GNUNET_asprintf (&cfg_file_p2, "test_transport_api_tcp_peer2.conf");
+
+ ret = check ();
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ GNUNET_free (test_name);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ return ret;
+}
+
+/* end of test_transport_api_restart_2peers.c */
diff --git a/src/transport/test_transport_api_tcp_nat_peer1.conf b/src/transport/test_transport_api_tcp_nat_peer1.conf
new file mode 100644
index 0000000..78afb3d
--- /dev/null
+++ b/src/transport/test_transport_api_tcp_nat_peer1.conf
@@ -0,0 +1,36 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-nat-p1/
+DEFAULTCONFIG = test_transport_api_tcp_nat_peer1.conf
+
+[nat]
+BEHIND_NAT = YES
+ENABLE_NAT_SERVER = YES
+DISABLEV6 = YES
+
+[transport-tcp]
+PORT = 0
+TIMEOUT = 5 s
+
+[arm]
+PORT = 1204
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12023
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12022
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12021
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 29542
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+#DEBUG = YES
+
diff --git a/src/transport/test_transport_api_tcp_nat_peer2.conf b/src/transport/test_transport_api_tcp_nat_peer2.conf
new file mode 100644
index 0000000..d94ebb1
--- /dev/null
+++ b/src/transport/test_transport_api_tcp_nat_peer2.conf
@@ -0,0 +1,34 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-nat-p2/
+DEFAULTCONFIG = test_transport_api_tcp_nat_peer2.conf
+
+[nat]
+DISABLEV6 = YES
+ENABLE_NAT_CLIENT = YES
+
+[transport-tcp]
+PORT = 12030
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12034
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12033
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12032
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12031
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 45923
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+#DEBUG = YES
diff --git a/src/transport/test_transport_api_tcp_peer1.conf b/src/transport/test_transport_api_tcp_peer1.conf
new file mode 100644
index 0000000..8bfa374
--- /dev/null
+++ b/src/transport/test_transport_api_tcp_peer1.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p1/
+DEFAULTCONFIG = test_transport_api_tcp_peer1.conf
+
+[transport-tcp]
+PORT = 12000
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12005
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12004
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12003
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12002
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12001
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+#DEBUG = YES
+
diff --git a/src/transport/test_transport_api_tcp_peer2.conf b/src/transport/test_transport_api_tcp_peer2.conf
new file mode 100644
index 0000000..6bb7fad
--- /dev/null
+++ b/src/transport/test_transport_api_tcp_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p2/
+DEFAULTCONFIG = test_transport_api_tcp_peer2.conf
+
+[transport-tcp]
+PORT = 12015
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12014
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12013
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12012
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12011
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12010
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
diff --git a/src/transport/test_transport_api_timeout.c b/src/transport/test_transport_api_timeout.c
new file mode 100644
index 0000000..9ce701a
--- /dev/null
+++ b/src/transport/test_transport_api_timeout.c
@@ -0,0 +1,361 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api_timeout.c
+ * @brief test case for transport plugin implementations complying timeout
+ * settings
+ *
+ *
+ * This test case serves ensures that no peer disconnect events occurs
+ * while plugins are idle
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define WAIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
+
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90)
+
+#define MTYPE 12345
+
+static char *test_source;
+
+static char *test_plugin;
+
+static char *test_name;
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+static GNUNET_SCHEDULER_TaskIdentifier timer_task;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
+
+static struct GNUNET_TIME_Relative time_running;
+
+static int shutdown_flag;
+
+static int disconnects;
+
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+
+static void
+end ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ if (timer_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (timer_task);
+ timer_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ if (disconnects == 0)
+ ok = 0;
+ else
+ {
+ ok = disconnects;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Fail! Had %u disconnects while waiting %llu seconds \n",
+ disconnects, WAIT.rel_value);
+ }
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+}
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ if (timer_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (timer_task);
+ timer_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (cc != NULL)
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+ ok = GNUNET_SYSERR;
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+}
+
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Received message of type %d from peer %s!\n",
+ ntohs (message->type), GNUNET_i2s (peer));
+}
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n",
+ GNUNET_i2s (peer), cls);
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ if (shutdown_flag != GNUNET_YES)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "FAIL! Peer `%4s' disconnected during waiting period!\n",
+ GNUNET_i2s (peer));
+ disconnects++;
+ }
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+}
+
+static void
+timer (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ static int percentage;
+
+ timer_task = GNUNET_SCHEDULER_NO_TASK;
+
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+
+ percentage += 10;
+ time_running =
+ GNUNET_TIME_relative_add (time_running,
+ GNUNET_TIME_relative_divide (WAIT, 10));
+
+ if (time_running.rel_value ==
+ GNUNET_TIME_relative_max (time_running, WAIT).rel_value)
+ {
+ FPRINTF (stderr, "%s", "100%%\n");
+ shutdown_flag = GNUNET_YES;
+ GNUNET_SCHEDULER_add_now (&end, NULL);
+ }
+ else
+ {
+ FPRINTF (stderr, "%u%%..", percentage);
+ timer_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_divide (WAIT, 10),
+ &timer, NULL);
+ }
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ cc = NULL;
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c,
+ GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ shutdown_flag = GNUNET_NO;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Waiting for %llu seconds\n", (WAIT.rel_value) / 1000);
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_delayed (WAIT, &end_badly, NULL);
+
+ timer_task = GNUNET_SCHEDULER_add_now (&timer, NULL);
+}
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
+ p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+}
+
+static int
+check ()
+{
+ static char *const argv[] = { "test-transport-api-timeout",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+ timer_task = GNUNET_SCHEDULER_NO_TASK;
+
+ ok = 1;
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv,
+ "test-transport-api-timeout", "nohelp", options, &run,
+ &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
+ GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
+ &test_plugin);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
+
+ ret = check ();
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+
+
+ return ret;
+}
+
+/* end of test_transport_api_timeout.c*/
diff --git a/src/transport/test_transport_api_timeout_http_peer1.conf b/src/transport/test_transport_api_timeout_http_peer1.conf
new file mode 100644
index 0000000..a28750a
--- /dev/null
+++ b/src/transport/test_transport_api_timeout_http_peer1.conf
@@ -0,0 +1,36 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-http-p1/
+DEFAULTCONFIG = test_transport_api_http_peer1.conf
+
+[nat]
+
+[transport-http]
+PORT = 12080
+
+[arm]
+PORT = 12085
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12084
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12083
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12082
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+#DEBUG = YES
+PORT = 12081
+PLUGINS = http
+#BINARY = .libs/gnunet-service-transport
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+#PREFIX = valgrind --leak-check=full
+#PREFIX = xterm -geometry 100x85 -T peer1 -e gdb --args
+
diff --git a/src/transport/test_transport_api_timeout_http_peer2.conf b/src/transport/test_transport_api_timeout_http_peer2.conf
new file mode 100644
index 0000000..1269358
--- /dev/null
+++ b/src/transport/test_transport_api_timeout_http_peer2.conf
@@ -0,0 +1,33 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-http-p2/
+DEFAULTCONFIG = test_transport_api_http_peer2.conf
+
+[nat]
+
+[transport-http]
+PORT = 12090
+
+[arm]
+PORT = 12095
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12094
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12093
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12092
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+#DEBUG = YES
+PORT = 12091
+PLUGINS = http
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+#PREFIX = valgrind --leak-check=full
diff --git a/src/transport/test_transport_api_timeout_https_peer1.conf b/src/transport/test_transport_api_timeout_https_peer1.conf
new file mode 100644
index 0000000..8a93ca1
--- /dev/null
+++ b/src/transport/test_transport_api_timeout_https_peer1.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-https-p1/
+DEFAULTCONFIG = test_transport_api_https_peer1.conf
+
+[transport-https]
+PORT = 12100
+KEY_FILE = $SERVICEHOME/https_key_p1.key
+CERT_FILE = $SERVICEHOME/https_cert_p1.crt
+
+[arm]
+PORT = 12105
+
+[statistics]
+PORT = 12104
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12103
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12102
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12101
+PLUGINS = https
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+DEBUG = NO
+
+
diff --git a/src/transport/test_transport_api_timeout_https_peer2.conf b/src/transport/test_transport_api_timeout_https_peer2.conf
new file mode 100644
index 0000000..0710f41
--- /dev/null
+++ b/src/transport/test_transport_api_timeout_https_peer2.conf
@@ -0,0 +1,33 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-https-p2/
+DEFAULTCONFIG = test_transport_api_https_peer2.conf
+
+[transport-https]
+PORT = 12110
+KEY_FILE = $SERVICEHOME/https_key_p2.key
+CERT_FILE = $SERVICEHOME/https_cert_p2.crt
+
+[arm]
+PORT = 12115
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12114
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12113
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12112
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12111
+PLUGINS = https
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+DEBUG = NO
+
+
diff --git a/src/transport/test_transport_api_timeout_tcp_peer1.conf b/src/transport/test_transport_api_timeout_tcp_peer1.conf
new file mode 100644
index 0000000..89beecb
--- /dev/null
+++ b/src/transport/test_transport_api_timeout_tcp_peer1.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p1/
+DEFAULTCONFIG = test_transport_api_timeout_tcp_peer1.conf
+
+[transport-tcp]
+PORT = 12000
+TIMEOUT = 5 s
+
+[arm]
+PORT = 12005
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12004
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12003
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12002
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12001
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_timeout_tcp_peer2.conf b/src/transport/test_transport_api_timeout_tcp_peer2.conf
new file mode 100644
index 0000000..a21c4f5
--- /dev/null
+++ b/src/transport/test_transport_api_timeout_tcp_peer2.conf
@@ -0,0 +1,33 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-tcp-p2/
+DEFAULTCONFIG = test_transport_api_timeout_tcp_peer2.conf
+
+[nat]
+ALLOW_NAT = NO
+
+[transport-tcp]
+PORT = 12100
+
+[arm]
+PORT = 12014
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12013
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12012
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12011
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12010
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_timeout_udp_peer1.conf b/src/transport/test_transport_api_timeout_udp_peer1.conf
new file mode 100644
index 0000000..a1216e4
--- /dev/null
+++ b/src/transport/test_transport_api_timeout_udp_peer1.conf
@@ -0,0 +1,34 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-udp-p1/
+DEFAULTCONFIG = test_transport_api_udp_peer1.conf
+
+[transport-udp]
+PORT = 12040
+BROADCAST = NO
+BROADCAST_INTERVAL = 30000
+MAX_BPS = 50000000
+
+[arm]
+PORT = 12045
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12044
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12043
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12042
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+#PREFIX = valgrind --leak-check=full
+PORT = 12041
+PLUGINS = udp
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_timeout_udp_peer2.conf b/src/transport/test_transport_api_timeout_udp_peer2.conf
new file mode 100644
index 0000000..3e487a6
--- /dev/null
+++ b/src/transport/test_transport_api_timeout_udp_peer2.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-udp-p2/
+DEFAULTCONFIG = test_transport_api_udp_peer2.conf
+
+[transport-udp]
+PORT = 12050
+BROADCAST = NO
+MAX_BPS = 50000000
+
+[arm]
+PORT = 12055
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12054
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12053
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12052
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12051
+PLUGINS = udp
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_timeout_unix_peer1.conf b/src/transport/test_transport_api_timeout_unix_peer1.conf
new file mode 100644
index 0000000..b1ace7d
--- /dev/null
+++ b/src/transport/test_transport_api_timeout_unix_peer1.conf
@@ -0,0 +1,29 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-unix-p1/
+DEFAULTCONFIG = test_transport_api_unix_peer1.conf
+
+[arm]
+PORT = 12125
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12124
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12123
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12122
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12121
+PLUGINS = unix
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+[transport-unix]
+PORT = 12120
+
diff --git a/src/transport/test_transport_api_timeout_unix_peer2.conf b/src/transport/test_transport_api_timeout_unix_peer2.conf
new file mode 100644
index 0000000..a153588
--- /dev/null
+++ b/src/transport/test_transport_api_timeout_unix_peer2.conf
@@ -0,0 +1,29 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-unix-p2/
+DEFAULTCONFIG = test_transport_api_unix_peer2.conf
+
+[arm]
+PORT = 12135
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12134
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12133
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12132
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12131
+PLUGINS = unix
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+[transport-unix]
+PORT = 12136
+
diff --git a/src/transport/test_transport_api_udp_nat_peer1.conf b/src/transport/test_transport_api_udp_nat_peer1.conf
new file mode 100644
index 0000000..16a4e62
--- /dev/null
+++ b/src/transport/test_transport_api_udp_nat_peer1.conf
@@ -0,0 +1,37 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-udp-nat-p1/
+DEFAULTCONFIG = test_transport_api_udp_nat_peer1.conf
+
+[nat]
+BEHIND_NAT = YES
+ALLOW_NAT = NO
+ONLY_NAT_ADDRESSES = YES
+
+[transport-udp]
+PORT = 0
+
+[arm]
+PORT = 12065
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12064
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12063
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12062
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12061
+PLUGINS = udp
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+DEBUG = NO
+
+
diff --git a/src/transport/test_transport_api_udp_nat_peer2.conf b/src/transport/test_transport_api_udp_nat_peer2.conf
new file mode 100644
index 0000000..0852b25
--- /dev/null
+++ b/src/transport/test_transport_api_udp_nat_peer2.conf
@@ -0,0 +1,35 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-udp-nat-p2/
+DEFAULTCONFIG = test_transport_api_udp_nat_peer2.conf
+
+[nat]
+ALLOW_NAT = YES
+
+[transport-udp]
+PORT = 12070
+
+[arm]
+PORT = 12075
+DEFAULTSERVICES = transport
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12074
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12073
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12072
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12071
+PLUGINS = udp
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+DEBUG = NO
+
+
diff --git a/src/transport/test_transport_api_udp_peer1.conf b/src/transport/test_transport_api_udp_peer1.conf
new file mode 100644
index 0000000..a1216e4
--- /dev/null
+++ b/src/transport/test_transport_api_udp_peer1.conf
@@ -0,0 +1,34 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-udp-p1/
+DEFAULTCONFIG = test_transport_api_udp_peer1.conf
+
+[transport-udp]
+PORT = 12040
+BROADCAST = NO
+BROADCAST_INTERVAL = 30000
+MAX_BPS = 50000000
+
+[arm]
+PORT = 12045
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12044
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12043
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12042
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+#PREFIX = valgrind --leak-check=full
+PORT = 12041
+PLUGINS = udp
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_udp_peer2.conf b/src/transport/test_transport_api_udp_peer2.conf
new file mode 100644
index 0000000..3e487a6
--- /dev/null
+++ b/src/transport/test_transport_api_udp_peer2.conf
@@ -0,0 +1,32 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-udp-p2/
+DEFAULTCONFIG = test_transport_api_udp_peer2.conf
+
+[transport-udp]
+PORT = 12050
+BROADCAST = NO
+MAX_BPS = 50000000
+
+[arm]
+PORT = 12055
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12054
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12053
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12052
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12051
+PLUGINS = udp
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_unix_peer1.conf b/src/transport/test_transport_api_unix_peer1.conf
new file mode 100644
index 0000000..b1ace7d
--- /dev/null
+++ b/src/transport/test_transport_api_unix_peer1.conf
@@ -0,0 +1,29 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-unix-p1/
+DEFAULTCONFIG = test_transport_api_unix_peer1.conf
+
+[arm]
+PORT = 12125
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12124
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12123
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12122
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12121
+PLUGINS = unix
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+[transport-unix]
+PORT = 12120
+
diff --git a/src/transport/test_transport_api_unix_peer2.conf b/src/transport/test_transport_api_unix_peer2.conf
new file mode 100644
index 0000000..a153588
--- /dev/null
+++ b/src/transport/test_transport_api_unix_peer2.conf
@@ -0,0 +1,29 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-unix-p2/
+DEFAULTCONFIG = test_transport_api_unix_peer2.conf
+
+[arm]
+PORT = 12135
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12134
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12133
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12132
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12131
+PLUGINS = unix
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+[transport-unix]
+PORT = 12136
+
diff --git a/src/transport/test_transport_api_unreliability.c b/src/transport/test_transport_api_unreliability.c
new file mode 100644
index 0000000..53de91a
--- /dev/null
+++ b/src/transport/test_transport_api_unreliability.c
@@ -0,0 +1,585 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api_unreliability.c
+ * @brief test case for transports; ensures messages get
+ * through, regardless of order
+ *
+ * This test case serves as a base for unreliable
+ * transport test cases to check that the transports
+ * achieve reliable message delivery.
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_transport_service.h"
+#include "gauger.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * Testcase timeout
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 900)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+static char *test_source;
+
+static char *test_plugin;
+
+static char *test_name;
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
+
+uint32_t max_bps_p1;
+uint32_t max_bps_p2;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+/*
+ * Testcase specific declarations
+ */
+
+/**
+ * Note that this value must not significantly exceed
+ * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
+ * messages may be dropped even for a reliable transport.
+ */
+#define TOTAL_MSGS (1024 * 3)
+
+#define MTYPE 12345
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+struct TestMessage
+{
+ struct GNUNET_MessageHeader header;
+ uint32_t num;
+};
+GNUNET_NETWORK_STRUCT_END
+
+static char *test_name;
+
+static int msg_scheduled;
+static int msg_sent;
+static int msg_recv_expected;
+static int msg_recv;
+
+static int test_connected;
+static int test_sending;
+static int test_send_timeout;
+
+static unsigned long long total_bytes;
+
+static struct GNUNET_TIME_Absolute start_time;
+
+static char bitmap[TOTAL_MSGS / 8];
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+/*
+ * END Testcase specific declarations
+ */
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+static int
+get_bit (const char *map, unsigned int bit);
+
+static void
+end ()
+{
+ unsigned long long delta;
+
+ char *value_name;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value;
+ FPRINTF (stderr, "\nThroughput was %llu kb/s\n",
+ total_bytes * 1000 / 1024 / delta);
+ GNUNET_asprintf (&value_name, "unreliable_%s", test_plugin);
+ GAUGER ("TRANSPORT", value_name, (int) (total_bytes * 1000 / 1024 / delta),
+ "kb/s");
+ GNUNET_free (value_name);
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (cc != NULL)
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ cc = NULL;
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ ok = 0;
+
+ int i;
+
+ for (i = 0; i < TOTAL_MSGS; i++)
+ {
+ if (get_bit (bitmap, i) == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "Did not receive message %d\n", i);
+ ok = -1;
+ }
+ }
+}
+
+static void
+end_badly ()
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ if (test_connected == GNUNET_YES)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got connected\n");
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Peers got NOT connected\n");
+
+ if (test_sending == GNUNET_NO)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Testcase did not send any messages before timeout\n");
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Reliability failed: Last message sent %u, Next message scheduled %u, Last message received %u, Message expected %u\n",
+ msg_sent, msg_scheduled, msg_recv, msg_recv_expected);
+ if (test_send_timeout == GNUNET_YES)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Test had timeout while waiting to send data\n");
+
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (cc != NULL)
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ cc = NULL;
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ ok = GNUNET_SYSERR;
+}
+
+
+static unsigned int
+get_size (unsigned int iter)
+{
+ unsigned int ret;
+
+ ret = (iter * iter * iter);
+
+#ifndef LINUX
+ /* FreeBSD/OSX etc. Unix DGRAMs do not work
+ * with large messages */
+ if (0 == strcmp ("unix", test_plugin))
+ return sizeof (struct TestMessage) + (ret % 1024);
+#endif
+ return sizeof (struct TestMessage) + (ret % 60000);
+}
+
+
+/**
+ * Sets a bit active in the bitmap.
+ *
+ * @param bitIdx which bit to set
+ */
+static void
+set_bit (unsigned int bitIdx)
+{
+ size_t arraySlot;
+ unsigned int targetBit;
+
+ if (bitIdx >= sizeof (bitmap) * 8)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_WARNING, "tried to set bit %d of %d(!?!?)\n",
+ bitIdx, sizeof (bitmap) * 8);
+ return;
+ }
+ arraySlot = bitIdx / 8;
+ targetBit = (1L << (bitIdx % 8));
+ bitmap[arraySlot] |= targetBit;
+}
+
+/**
+ * Obtain a bit from bitmap.
+ * @param map the bitmap
+ * @param bit index from bitmap
+ *
+ * @return Bit \a bit from hashcode \a code
+ */
+static int
+get_bit (const char *map, unsigned int bit)
+{
+ if (bit >= TOTAL_MSGS)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "get bit %d of %d(!?!?)\n", bit,
+ sizeof (bitmap) * 8);
+ return 0;
+ }
+ return ((map)[bit >> 3] & (1 << (bit & 7))) > 0;
+}
+
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ static int n;
+
+ unsigned int s;
+ char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ const struct TestMessage *hdr;
+
+ hdr = (const struct TestMessage *) message;
+
+ if (MTYPE != ntohs (message->type))
+ return;
+ msg_recv_expected = n;
+ msg_recv = ntohl (hdr->num);
+ s = get_size (ntohl (hdr->num));
+
+ if (ntohs (message->size) != s)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u of size %u, got %u bytes of message %u\n",
+ ntohl (hdr->num), s, ntohs (message->size), ntohl (hdr->num));
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_sending = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+
+ memset (cbuf, ntohl (hdr->num), s - sizeof (struct TestMessage));
+ if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u with bits %u, but body did not match\n",
+ ntohl (hdr->num), (unsigned char) n);
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_sending = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+#if VERBOSE
+ if (ntohl (hdr->num) % 5 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message %u of size %u\n",
+ ntohl (hdr->num), ntohs (message->size));
+ }
+#endif
+ n++;
+ set_bit (ntohl (hdr->num));
+ test_sending = GNUNET_YES;
+ if (0 == (n % (TOTAL_MSGS / 100)))
+ {
+ FPRINTF (stderr, "%s", ".");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+ }
+ if (n == TOTAL_MSGS)
+ {
+ end ();
+ }
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ static int n;
+ char *cbuf = buf;
+ struct TestMessage hdr;
+ unsigned int s;
+ unsigned int ret;
+
+ th = NULL;
+
+ if (buf == NULL)
+ {
+ test_send_timeout = GNUNET_YES;
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout occurred while waiting for transmit_ready for msg %u of %u\n",
+ msg_scheduled, TOTAL_MSGS);
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ ok = 42;
+ return 0;
+ }
+ ret = 0;
+ s = get_size (n);
+ GNUNET_assert (size >= s);
+ GNUNET_assert (buf != NULL);
+ cbuf = buf;
+ do
+ {
+ hdr.header.size = htons (s);
+ hdr.header.type = htons (MTYPE);
+ hdr.num = htonl (n);
+ msg_sent = n;
+ memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage));
+ ret += sizeof (struct TestMessage);
+ memset (&cbuf[ret], n, s - sizeof (struct TestMessage));
+ ret += s - sizeof (struct TestMessage);
+#if VERBOSE
+ if (n % 5000 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message %u of size %u\n", n,
+ s);
+ }
+
+#endif
+ n++;
+ s = get_size (n);
+ if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
+ break; /* sometimes pack buffer full, sometimes not */
+ }
+ while (size - ret >= s);
+ if (n < TOTAL_MSGS)
+ {
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0,
+ TIMEOUT_TRANSMIT,
+ &notify_ready, NULL);
+ msg_scheduled = n;
+ }
+ else
+ {
+ FPRINTF (stderr, "%s", "\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "All messages scheduled to be sent\n");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+ }
+ if (n % 5000 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Returning total message block of size %u\n", ret);
+ }
+ total_bytes += ret;
+ return ret;
+}
+
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n",
+ GNUNET_i2s (peer), cls);
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n",
+ GNUNET_i2s (peer), cls);
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+}
+
+static void
+sendtask ()
+{
+ start_time = GNUNET_TIME_absolute_get ();
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0,
+ TIMEOUT_TRANSMIT, &notify_ready,
+ NULL);
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c,
+ GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ test_connected = GNUNET_YES;
+ cc = NULL;
+
+ GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+}
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ test_connected = GNUNET_NO;
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+ test_send_timeout = GNUNET_NO;
+
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+
+
+}
+
+static int
+check ()
+{
+ static char *const argv[] = { "test-transport-api-unreliability",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+ ok = GNUNET_SYSERR;
+
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
+ GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
+ &test_plugin);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
+
+ ret = check ();
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+
+
+ return ret;
+}
+
+/* end of test_transport_api_unreliability.c */
diff --git a/src/transport/test_transport_api_unreliability_constant.c b/src/transport/test_transport_api_unreliability_constant.c
new file mode 100644
index 0000000..fb72b0f
--- /dev/null
+++ b/src/transport/test_transport_api_unreliability_constant.c
@@ -0,0 +1,523 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api_unreliability_constant.c
+ * @brief test case for transports; ensures messages get
+ * through, regardless of order, constant packet size
+ *
+ * This test case serves as a base for unreliable
+ * transport test cases to check that the transports
+ * achieve reliable message delivery.
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_transport_service.h"
+#include "gauger.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * Testcase timeout
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 900)
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT_TRANSMIT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 60)
+
+static char *test_source;
+
+static char *test_plugin;
+
+static char *test_name;
+
+static int ok;
+
+static GNUNET_SCHEDULER_TaskIdentifier die_task;
+
+struct PeerContext *p1;
+
+struct PeerContext *p2;
+
+struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+char *cfg_file_p1;
+
+char *cfg_file_p2;
+
+uint32_t max_bps_p1;
+uint32_t max_bps_p2;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+/*
+ * Testcase specific declarations
+ */
+
+/**
+ * Note that this value must not significantly exceed
+ * 'MAX_PENDING' in 'gnunet-service-transport.c', otherwise
+ * messages may be dropped even for a reliable transport.
+ */
+#define TOTAL_MSGS (1024 * 3)
+
+#define MTYPE 12345
+
+#define MSG_SIZE 10000
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+struct TestMessage
+{
+ struct GNUNET_MessageHeader header;
+ uint32_t num;
+};
+GNUNET_NETWORK_STRUCT_END
+
+static char *test_name;
+
+static int msg_scheduled;
+static int msg_sent;
+static int msg_recv_expected;
+static int msg_recv;
+
+static int test_failed;
+
+static unsigned long long total_bytes;
+
+static struct GNUNET_TIME_Absolute start_time;
+
+/*
+ * END Testcase specific declarations
+ */
+
+#if VERBOSE
+#define OKPP do { ok++; FPRINTF (stderr, "Now at stage %u at %s:%u\n", ok, __FILE__, __LINE__); } while (0)
+#else
+#define OKPP do { ok++; } while (0)
+#endif
+
+int
+get_bit (const char *map, unsigned int bit);
+
+static void
+end ()
+{
+ unsigned long long delta;
+
+ char *value_name;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ delta = GNUNET_TIME_absolute_get_duration (start_time).rel_value;
+ FPRINTF (stderr, "\nThroughput was %llu kb/s\n",
+ total_bytes * 1000 / 1024 / delta);
+ GNUNET_asprintf (&value_name, "unreliable_%s", test_plugin);
+ GAUGER ("TRANSPORT", value_name, (int) (total_bytes * 1000 / 1024 / delta),
+ "kb/s");
+ GNUNET_free (value_name);
+
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (cc != NULL)
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ cc = NULL;
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ ok = 0;
+ if (test_failed == GNUNET_NO)
+ ok = GNUNET_SYSERR;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GOT %u of %u messages\n", msg_recv,
+ TOTAL_MSGS);
+}
+
+static void
+end_badly ()
+{
+ die_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ if (test_failed == GNUNET_NO)
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Testcase timeout\n");
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Reliability failed: Last message sent %u, Next message scheduled %u, Last message received %u, Message expected %u\n",
+ msg_sent, msg_scheduled, msg_recv, msg_recv_expected);
+
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+
+ if (cc != NULL)
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ cc = NULL;
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ ok = GNUNET_SYSERR;
+}
+
+
+static unsigned int
+get_size (unsigned int iter)
+{
+/*
+ unsigned int ret;
+ ret = (iter * iter * iter);
+ return sizeof (struct TestMessage) + (ret % 60000);
+ */
+ return MSG_SIZE;
+}
+
+
+
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ static int n;
+
+ unsigned int s;
+ char cbuf[GNUNET_SERVER_MAX_MESSAGE_SIZE - 1];
+ const struct TestMessage *hdr;
+
+ hdr = (const struct TestMessage *) message;
+
+ if (MTYPE != ntohs (message->type))
+ return;
+ msg_recv_expected = n;
+ msg_recv = ntohl (hdr->num);
+ if (msg_recv_expected != msg_recv)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Expected message no %u, got %u\n",
+ msg_recv_expected, msg_recv);
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_failed = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+
+ s = get_size (ntohl (hdr->num));
+ if (ntohs (message->size) != s)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u of size %u, got %u bytes of message %u\n",
+ ntohl (hdr->num), s, ntohs (message->size), ntohl (hdr->num));
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_failed = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+
+ memset (cbuf, ntohl (hdr->num), s - sizeof (struct TestMessage));
+ if (0 != memcmp (cbuf, &hdr[1], s - sizeof (struct TestMessage)))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Expected message %u with bits %u, but body did not match\n",
+ ntohl (hdr->num), (unsigned char) n);
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_failed = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+#if VERBOSE
+ if (ntohl (hdr->num) % 5 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Got message %u of size %u\n",
+ ntohl (hdr->num), ntohs (message->size));
+ }
+#endif
+ n++;
+ if (0 == (n % (TOTAL_MSGS / 100)))
+ {
+ FPRINTF (stderr, "%s", ".");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ test_failed = GNUNET_YES;
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+ }
+ if (n == TOTAL_MSGS)
+ {
+ /* because of starting with 0 */
+ msg_recv++;
+ FPRINTF (stderr, "%s", "\n");
+ end ();
+ }
+}
+
+
+static size_t
+notify_ready (void *cls, size_t size, void *buf)
+{
+ static int n;
+ char *cbuf = buf;
+ struct TestMessage hdr;
+ unsigned int s;
+ unsigned int ret;
+
+ th = NULL;
+
+ if (buf == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR,
+ "Timeout occurred while waiting for transmit_ready\n");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ ok = 42;
+ return 0;
+ }
+ ret = 0;
+ s = get_size (n);
+ GNUNET_assert (size >= s);
+ GNUNET_assert (buf != NULL);
+ cbuf = buf;
+ do
+ {
+ hdr.header.size = htons (s);
+ hdr.header.type = htons (MTYPE);
+ hdr.num = htonl (n);
+ msg_sent = n;
+ memcpy (&cbuf[ret], &hdr, sizeof (struct TestMessage));
+ ret += sizeof (struct TestMessage);
+ memset (&cbuf[ret], n, s - sizeof (struct TestMessage));
+ ret += s - sizeof (struct TestMessage);
+#if VERBOSE
+ if (n % 1 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Sending message %u of size %u\n", n,
+ s);
+ }
+
+#endif
+ n++;
+ s = get_size (n);
+ if (0 == GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, 16))
+ break; /* sometimes pack buffer full, sometimes not */
+ }
+ while (size - ret >= s);
+ if (n < TOTAL_MSGS)
+ {
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, s, 0,
+ TIMEOUT_TRANSMIT,
+ &notify_ready, NULL);
+ msg_scheduled = n;
+ }
+ else
+ {
+ FPRINTF (stderr, "%s", "\n");
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "All messages scheduled to be sent!!\n");
+ if (GNUNET_SCHEDULER_NO_TASK != die_task)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+ }
+ if (n % 5000 == 0)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Returning total message block of size %u\n", ret);
+ }
+ total_bytes += ret;
+ return ret;
+}
+
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' connected to us (%p)!\n",
+ GNUNET_i2s (peer), cls);
+}
+
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%4s' disconnected (%p)!\n",
+ GNUNET_i2s (peer), cls);
+ if (th != NULL)
+ GNUNET_TRANSPORT_notify_transmit_ready_cancel (th);
+ th = NULL;
+}
+
+static void
+sendtask ()
+{
+ start_time = GNUNET_TIME_absolute_get ();
+ th = GNUNET_TRANSPORT_notify_transmit_ready (p2->th, &p1->id, get_size (0), 0,
+ TIMEOUT_TRANSMIT, &notify_ready,
+ NULL);
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ char *p1_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peers connected: %s <-> %s\n", p1_c,
+ GNUNET_i2s (&p2->id));
+ GNUNET_free (p1_c);
+
+ cc = NULL;
+
+ GNUNET_SCHEDULER_add_now (&sendtask, NULL);
+}
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ die_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p1, 1,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2,
+ &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb,
+ NULL);
+
+ if ((p1 == NULL) || (p2 == NULL))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, "Fail! Could not start peers!\n");
+ if (die_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (die_task);
+ die_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ return;
+ }
+}
+
+static int
+check ()
+{
+ static char *const argv[] = { "test-transport-api-unreliability-constant",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+ static struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+#if WRITECONFIG
+ setTransportOptions ("test_transport_api_data.conf");
+#endif
+ ok = GNUNET_SYSERR;
+
+ GNUNET_PROGRAM_run ((sizeof (argv) / sizeof (char *)) - 1, argv, test_name,
+ "nohelp", options, &run, &ok);
+
+ return ok;
+}
+
+int
+main (int argc, char *argv[])
+{
+ int ret;
+
+ GNUNET_TRANSPORT_TESTING_get_test_name (argv[0], &test_name);
+
+ GNUNET_log_setup (test_name,
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ GNUNET_TRANSPORT_TESTING_get_test_source_name (__FILE__, &test_source);
+ GNUNET_TRANSPORT_TESTING_get_test_plugin_name (argv[0], test_source,
+ &test_plugin);
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p1, 1);
+ GNUNET_TRANSPORT_TESTING_get_config_name (argv[0], &cfg_file_p2, 2);
+
+ ret = check ();
+
+ GNUNET_free (cfg_file_p1);
+ GNUNET_free (cfg_file_p2);
+
+ GNUNET_free (test_source);
+ GNUNET_free (test_plugin);
+ GNUNET_free (test_name);
+
+ return ret;
+}
+
+/* end of test_transport_api_unreliability_constant.c */
diff --git a/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf b/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf
new file mode 100644
index 0000000..d872f02
--- /dev/null
+++ b/src/transport/test_transport_api_unreliability_constant_udp_peer1.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-udp-p1/
+DEFAULTCONFIG = test_transport_api_unreliability_constant_udp_peer1.conf
+
+[transport-udp]
+PORT = 12040
+MAX_BPS = 1073741824
+
+[arm]
+PORT = 12045
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12044
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12043
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12042
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12041
+PLUGINS = udp
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf b/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf
new file mode 100644
index 0000000..50ee65a
--- /dev/null
+++ b/src/transport/test_transport_api_unreliability_constant_udp_peer2.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-udp-p2/
+DEFAULTCONFIG = test_transport_api_unreliability_constant_udp_peer2.conf
+
+[transport-udp]
+PORT = 12050
+MAX_BPS = 1073741824
+
+[arm]
+PORT = 12055
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12054
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12053
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12052
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12051
+PLUGINS = udp
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_unreliability_udp_peer1.conf b/src/transport/test_transport_api_unreliability_udp_peer1.conf
new file mode 100644
index 0000000..8a5a405
--- /dev/null
+++ b/src/transport/test_transport_api_unreliability_udp_peer1.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-udp-p1/
+DEFAULTCONFIG = test_transport_api_unreliability_udp_peer1.conf
+
+[transport-udp]
+PORT = 12040
+MAX_BPS = 5000000
+
+[arm]
+PORT = 12045
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12044
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12043
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12042
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12041
+PLUGINS = udp
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_unreliability_udp_peer2.conf b/src/transport/test_transport_api_unreliability_udp_peer2.conf
new file mode 100644
index 0000000..d240c42
--- /dev/null
+++ b/src/transport/test_transport_api_unreliability_udp_peer2.conf
@@ -0,0 +1,31 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-udp-p2/
+DEFAULTCONFIG = test_transport_api_unreliability_udp_peer2.conf
+
+[transport-udp]
+PORT = 12050
+MAX_BPS = 5000000
+
+[arm]
+PORT = 12055
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12054
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12053
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12052
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12051
+PLUGINS = udp
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_unreliability_unix_peer1.conf b/src/transport/test_transport_api_unreliability_unix_peer1.conf
new file mode 100644
index 0000000..8689e41
--- /dev/null
+++ b/src/transport/test_transport_api_unreliability_unix_peer1.conf
@@ -0,0 +1,29 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-unix-p1/
+DEFAULTCONFIG = test_transport_api_unreliability_unix_peer1.conf
+
+[arm]
+PORT = 12125
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12124
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12123
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12122
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12121
+PLUGINS = unix
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+[transport-unix]
+PORT = 12120
+
diff --git a/src/transport/test_transport_api_unreliability_unix_peer2.conf b/src/transport/test_transport_api_unreliability_unix_peer2.conf
new file mode 100644
index 0000000..7c3cc19
--- /dev/null
+++ b/src/transport/test_transport_api_unreliability_unix_peer2.conf
@@ -0,0 +1,29 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-unix-p2/
+DEFAULTCONFIG = test_transport_api_unreliability_unix_peer2.conf
+
+[arm]
+PORT = 12135
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12134
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12133
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12132
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12131
+PLUGINS = unix
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
+[transport-unix]
+PORT = 12131
+
diff --git a/src/transport/test_transport_api_unreliability_wlan_peer1.conf b/src/transport/test_transport_api_unreliability_wlan_peer1.conf
new file mode 100644
index 0000000..9dd9d1b
--- /dev/null
+++ b/src/transport/test_transport_api_unreliability_wlan_peer1.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-wlan-p1/
+DEFAULTCONFIG = test_transport_api_wlan_peer1.conf
+
+[transport-wlan]
+TESTMODE = 1
+
+[arm]
+PORT = 12164
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12163
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12162
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12161
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12160
+PLUGINS = wlan
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+
+
diff --git a/src/transport/test_transport_api_unreliability_wlan_peer2.conf b/src/transport/test_transport_api_unreliability_wlan_peer2.conf
new file mode 100644
index 0000000..bc868d7
--- /dev/null
+++ b/src/transport/test_transport_api_unreliability_wlan_peer2.conf
@@ -0,0 +1,30 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-wlan-p2/
+DEFAULTCONFIG = test_transport_api_wlan_peer2.conf
+
+[transport-wlan]
+INTERFACE = mon1
+TESTMODE = 2
+
+[arm]
+PORT = 12174
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12173
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12172
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12171
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12170
+PLUGINS = wlan
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+
diff --git a/src/transport/test_transport_api_wlan_peer1.conf b/src/transport/test_transport_api_wlan_peer1.conf
new file mode 100644
index 0000000..e379cf0
--- /dev/null
+++ b/src/transport/test_transport_api_wlan_peer1.conf
@@ -0,0 +1,38 @@
+@INLINE@ template_cfg_peer1.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-wlan-p1/
+DEFAULTCONFIG = test_transport_api_wlan_peer1.conf
+
+[transport-wlan]
+INTERFACE = mon0
+TESTMODE = 1
+
+[arm]
+DEBUG = YES
+PORT = 12164
+UNIXPATH = /tmp/gnunet-p1-service-arm.sock
+
+[statistics]
+PORT = 12163
+UNIXPATH = /tmp/gnunet-p1-service-statistics.sock
+
+[resolver]
+PORT = 12162
+UNIXPATH = /tmp/gnunet-p1-service-resolver.sock
+
+[peerinfo]
+PORT = 12161
+UNIXPATH = /tmp/gnunet-p1-service-peerinfo.sock
+
+[transport]
+PORT = 12160
+PLUGINS = wlan
+#DEBUG = YES
+UNIXPATH = /tmp/gnunet-p1-service-transport.sock
+#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
+#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
+#PREFIX = valgrind --leak-check=full --show-reachable=yes
+#PREFIX = valgrind --leak-check=full
+#PREFIX = valgrind --tool=massif
+#PREFIX = gdbserver :2345
+
diff --git a/src/transport/test_transport_api_wlan_peer2.conf b/src/transport/test_transport_api_wlan_peer2.conf
new file mode 100644
index 0000000..3e0ce27
--- /dev/null
+++ b/src/transport/test_transport_api_wlan_peer2.conf
@@ -0,0 +1,37 @@
+@INLINE@ template_cfg_peer2.conf
+[PATHS]
+SERVICEHOME = /tmp/test-transport/api-wlan-p2/
+DEFAULTCONFIG = test_transport_api_wlan_peer2.conf
+
+[transport-wlan]
+INTERFACE = mon1
+TESTMODE = 2
+
+[arm]
+PORT = 12174
+DEBUG = YES
+UNIXPATH = /tmp/gnunet-p2-service-arm.sock
+
+[statistics]
+PORT = 12173
+UNIXPATH = /tmp/gnunet-p2-service-statistics.sock
+
+[resolver]
+PORT = 12172
+UNIXPATH = /tmp/gnunet-p2-service-resolver.sock
+
+[peerinfo]
+PORT = 12171
+UNIXPATH = /tmp/gnunet-p2-service-peerinfo.sock
+
+[transport]
+PORT = 12170
+PLUGINS = wlan
+#DEBUG = YES
+UNIXPATH = /tmp/gnunet-p2-service-transport.sock
+#PREFIX = xterm -T transport2 -e gdb --command=cmd --args
+#PREFIX = valgrind --leak-check=full --show-reachable=yes --main-stacksize=104857600
+#PREFIX = valgrind --leak-check=full --show-reachable=yes
+#PREFIX = valgrind --leak-check=full
+#PREFIX = valgrind --tool=massif
+#PREFIX = gdbserver :2345
diff --git a/src/transport/test_transport_defaults.conf b/src/transport/test_transport_defaults.conf
new file mode 100644
index 0000000..f553377
--- /dev/null
+++ b/src/transport/test_transport_defaults.conf
@@ -0,0 +1,54 @@
+[PATHS]
+SERVICEHOME = /tmp/test-transport-api/
+DEFAULTCONFIG = test_transport_defaults.conf
+
+[transport-tcp]
+TIMEOUT = 300 s
+
+[arm]
+DEFAULTSERVICES =
+
+[transport]
+PREFIX =
+
+[core]
+AUTOSTART = NO
+
+[datastore]
+AUTOSTART = NO
+
+[fs]
+AUTOSTART = NO
+
+[dht]
+AUTOSTART = NO
+
+[mesh]
+AUTOSTART = NO
+
+[nse]
+AUTOSTART = NO
+
+[dns]
+AUTOSTART = NO
+
+[dv]
+AUTOSTART = NO
+
+[gns]
+AUTOSTART = NO
+
+[chat]
+AUTOSTART = NO
+
+[vpn]
+AUTOSTART = NO
+
+[nat]
+DISABLEV6 = YES
+BINDTO = 127.0.0.1
+INTERNAL_ADDRESS = 127.0.0.1
+EXTERNAL_ADDRESS = 127.0.0.1
+
+[TESTING]
+WEAKRANDOM = YES
diff --git a/src/transport/test_transport_startonly.c b/src/transport/test_transport_startonly.c
new file mode 100644
index 0000000..79578ab
--- /dev/null
+++ b/src/transport/test_transport_startonly.c
@@ -0,0 +1,189 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api.c
+ * @brief base test case for transport implementations
+ *
+ * This test case serves as a base for tcp, udp, and udp-nat
+ * transport test cases. Based on the executable being run
+ * the correct test case will be performed. Conservation of
+ * C code apparently.
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 90)
+
+#define ITERATIONS 10
+
+GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+static struct PeerContext *p1;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+static int connected = GNUNET_NO;
+
+static int ret = 0;
+
+static int i;
+
+static void
+end ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (timeout_task);
+ timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Exiting\n");
+}
+
+static void
+end_badly (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+
+ ret = GNUNET_SYSERR;
+}
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected \n",
+ GNUNET_i2s (peer));
+ connected++;
+}
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected \n",
+ GNUNET_i2s (peer));
+}
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving\n");
+}
+
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ timeout_task = GNUNET_SCHEDULER_add_delayed (TIMEOUT, &end_badly, NULL);
+
+ i = 1;
+ FPRINTF (stderr, "%i", i);
+ while (i <= ITERATIONS)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting peer\n");
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
+ "test_transport_startonly.conf",
+ 1, &notify_receive,
+ &notify_connect,
+ &notify_disconnect, NULL, p1);
+
+
+ if (p1 != NULL)
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer was successfully started\n");
+ else
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer1 was not started successfully\n");
+ GNUNET_assert (p1 != NULL);
+ GNUNET_assert (p1->th != NULL);
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+
+ i++;
+ if (i <= ITERATIONS)
+ FPRINTF (stderr, "..%i", i);
+ }
+
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ FPRINTF (stderr, "%s", "\n");
+ end ();
+}
+
+int
+main (int argc, char *argv[])
+{
+ GNUNET_log_setup ("test_transport_testing",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ char *const argv_1[] = { "test_transport_testing",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ GNUNET_PROGRAM_run ((sizeof (argv_1) / sizeof (char *)) - 1, argv_1,
+ "test_transport_testing", "nohelp", options, &run, &ret);
+
+ return ret;
+}
+
+/* end of test_transport_api.c */
diff --git a/src/transport/test_transport_startonly.conf b/src/transport/test_transport_startonly.conf
new file mode 100644
index 0000000..255df4c
--- /dev/null
+++ b/src/transport/test_transport_startonly.conf
@@ -0,0 +1,15 @@
+@INLINE@ test_transport_defaults.conf
+[PATHS]
+DEFAULTCONFIG = test_transport_api_data.conf
+
+[arm]
+DEFAULTSERVICES = transport
+
+[transport-tcp]
+PORT = 2094
+
+[transport-udp]
+PORT = 2094
+
+
+
diff --git a/src/transport/test_transport_testing.c b/src/transport/test_transport_testing.c
new file mode 100644
index 0000000..842d686
--- /dev/null
+++ b/src/transport/test_transport_testing.c
@@ -0,0 +1,227 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+/**
+ * @file transport/test_transport_api.c
+ * @brief base test case for transport implementations
+ *
+ * This test case serves as a base for tcp, udp, and udp-nat
+ * transport test cases. Based on the executable being run
+ * the correct test case will be performed. Conservation of
+ * C code apparently.
+ */
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_scheduler_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+#include "transport-testing.h"
+
+#define VERBOSE GNUNET_NO
+
+#define VERBOSE_ARM GNUNET_NO
+
+#define START_ARM GNUNET_YES
+
+/**
+ * How long until we give up on transmitting the message?
+ */
+#define TIMEOUT GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)
+
+GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+static struct PeerContext *p1;
+static struct PeerContext *p2;
+
+static GNUNET_TRANSPORT_TESTING_ConnectRequest cc;
+
+struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+static int connected = GNUNET_NO;
+
+static int ret = 0;
+
+static void
+end ()
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Stopping peers\n");
+
+ if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (timeout_task);
+
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+}
+
+static void
+end_badly ()
+{
+ timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Fail! Stopping peers\n");
+
+ if (p1 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p1);
+ if (p2 != NULL)
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p2);
+
+ GNUNET_TRANSPORT_TESTING_done (tth);
+
+ ret = GNUNET_SYSERR;
+}
+
+static void
+testing_connect_cb (struct PeerContext *p1, struct PeerContext *p2, void *cls)
+{
+ char *ps = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer %u (`%4s') connected to peer %u (`%s')!\n", p1->no, ps,
+ p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (ps);
+ GNUNET_SCHEDULER_add_now (&end, NULL);
+}
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' connected \n",
+ GNUNET_i2s (peer));
+ connected++;
+}
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer `%s' disconnected \n",
+ GNUNET_i2s (peer));
+}
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Receiving\n");
+}
+
+void
+start_cb (struct PeerContext *p, void *cls)
+{
+ static int started;
+
+ started++;
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Peer %u (`%s') started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ if (started != 2)
+ return;
+
+ char *sender_c = GNUNET_strdup (GNUNET_i2s (&p1->id));
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Test tries to connect peer %u (`%s') -> peer %u (`%s')\n",
+ p1->no, sender_c, p2->no, GNUNET_i2s (&p2->id));
+ GNUNET_free (sender_c);
+
+ cc = GNUNET_TRANSPORT_TESTING_connect_peers (tth, p1, p2, &testing_connect_cb,
+ NULL);
+
+}
+
+static void
+run (void *cls, char *const *args, const char *cfgfile,
+ const struct GNUNET_CONFIGURATION_Handle *cfg)
+{
+ tth = GNUNET_TRANSPORT_TESTING_init ();
+
+ timeout_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_MINUTES, &end_badly, NULL);
+
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Starting peer\n");
+ p1 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
+ "test_transport_api_tcp_peer1.conf",
+ 1, &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb, p1);
+
+ GNUNET_assert (p1->hostkeyfile != NULL);
+
+ p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth,
+ "test_transport_api_tcp_peer2.conf",
+ 2, &notify_receive, &notify_connect,
+ &notify_disconnect, &start_cb, p2);
+
+ GNUNET_assert (p2->hostkeyfile != NULL);
+
+ if (p1 == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer1 was not started successfully\n");
+ if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (timeout_task);
+ timeout_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ }
+ if (p2 == NULL)
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG,
+ "Peer2 was not started successfully\n");
+ if (timeout_task != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (timeout_task);
+ timeout_task = GNUNET_SCHEDULER_add_now (&end_badly, NULL);
+ }
+}
+
+int
+main (int argc, char *argv[])
+{
+ GNUNET_log_setup ("test_transport_testing",
+#if VERBOSE
+ "DEBUG",
+#else
+ "WARNING",
+#endif
+ NULL);
+
+ char *const argv_1[] = { "test_transport_testing",
+ "-c",
+ "test_transport_api_data.conf",
+#if VERBOSE
+ "-L", "DEBUG",
+#endif
+ NULL
+ };
+
+ struct GNUNET_GETOPT_CommandLineOption options[] = {
+ GNUNET_GETOPT_OPTION_END
+ };
+
+ GNUNET_PROGRAM_run ((sizeof (argv_1) / sizeof (char *)) - 1, argv_1,
+ "test_transport_testing", "nohelp", options, &run, &ret);
+
+ return ret;
+}
+
+/* end of test_transport_api.c */
diff --git a/src/transport/transport-testing.c b/src/transport/transport-testing.c
new file mode 100644
index 0000000..752106b
--- /dev/null
+++ b/src/transport/transport-testing.c
@@ -0,0 +1,872 @@
+/*
+ This file is part of GNUnet.
+ (C) 2006, 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport-testing.c
+ * @brief testing lib for transport service
+ *
+ * @author Matthias Wachs
+ */
+
+#include "transport-testing.h"
+
+#define HOSTKEYFILESIZE 914
+
+static const char *
+get_host_key (struct GNUNET_TRANSPORT_TESTING_handle *tth)
+{
+ if (tth->hostkey_data == NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "No precomputed hostkeys available\n");
+ return NULL;
+ }
+ if (tth->hostkeys_total > tth->hostkeys_last)
+ {
+ tth->hostkeys_last++;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Used hostkey %u of %u available hostkeys\n",
+ tth->hostkeys_last, tth->hostkeys_total);
+ return &tth->hostkey_data[(tth->hostkeys_last - 1) * HOSTKEYFILESIZE];
+ }
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "No hostkey available (%u of %u already used)\n",
+ tth->hostkeys_last, tth->hostkeys_total);
+ return NULL;
+}
+
+static struct PeerContext *
+find_peer_context (struct GNUNET_TRANSPORT_TESTING_handle *tth,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ GNUNET_assert (tth != NULL);
+ struct PeerContext *t = tth->p_head;
+
+ while (t != NULL)
+ {
+ if (0 == memcmp (&t->id, peer, sizeof (struct GNUNET_PeerIdentity)))
+ break;
+ t = t->next;
+ }
+
+ return t;
+}
+
+struct ConnectingContext *
+find_connecting_context (struct GNUNET_TRANSPORT_TESTING_handle *tth,
+ struct PeerContext *p1, struct PeerContext *p2)
+{
+ GNUNET_assert (tth != NULL);
+ struct ConnectingContext *cc = tth->cc_head;
+
+ while (cc != NULL)
+ {
+ if ((cc->p1 == p1) && (cc->p2 == p2))
+ break;
+ if ((cc->p1 == p2) && (cc->p2 == p1))
+ break;
+ cc = cc->next;
+ }
+
+ return cc;
+}
+
+static void
+notify_connect (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ struct PeerContext *p = cls;
+
+ /* Find PeerContext */
+ GNUNET_assert (p != 0);
+ GNUNET_assert (p->tth != NULL);
+ struct PeerContext *p2 = find_peer_context (p->tth, peer);
+
+ if (p == NULL)
+ return;
+ if (p->nc != NULL)
+ p->nc (p->cb_cls, peer, ats, ats_count);
+
+ char *p2_s;
+
+ if (p2 != NULL)
+ GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id));
+ else
+ GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer));
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Peers %s connected to peer %u (`%s')\n", p2_s, p->no,
+ GNUNET_i2s (&p->id));
+ GNUNET_free (p2_s);
+
+ /* Find ConnectingContext */
+ struct ConnectingContext *cc = find_connecting_context (p->tth, p, p2);
+
+ if (cc == NULL)
+ return;
+
+ if (p == cc->p1)
+ cc->p1_c = GNUNET_YES;
+
+ if (p == cc->p2)
+ cc->p2_c = GNUNET_YES;
+
+ if ((cc->p1_c == GNUNET_YES) && (cc->p2_c == GNUNET_YES))
+ {
+ cc->cb (cc->p1, cc->p2, cc->cb_cls);
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (p->tth, cc);
+ }
+}
+
+static void
+notify_disconnect (void *cls, const struct GNUNET_PeerIdentity *peer)
+{
+ struct PeerContext *p = cls;
+
+ /* Find PeerContext */
+ int no = 0;
+ struct PeerContext *p2 = NULL;
+
+ if (p != NULL)
+ {
+ GNUNET_assert (p->tth != NULL);
+ p2 = find_peer_context (p->tth, peer);
+ no = p->no;
+ }
+
+ char *p2_s;
+
+ if (p2 != NULL)
+ GNUNET_asprintf (&p2_s, "%u (`%s')", p2->no, GNUNET_i2s (&p2->id));
+ else
+ GNUNET_asprintf (&p2_s, "`%s'", GNUNET_i2s (peer));
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Peers %s disconnected from peer %u (`%s')\n", p2_s, no,
+ GNUNET_i2s (&p->id));
+ GNUNET_free (p2_s);
+
+ if (p == NULL)
+ return;
+ if (p->nd != NULL)
+ p->nd (p->cb_cls, peer);
+}
+
+static void
+notify_receive (void *cls, const struct GNUNET_PeerIdentity *peer,
+ const struct GNUNET_MessageHeader *message,
+ const struct GNUNET_ATS_Information *ats, uint32_t ats_count)
+{
+ struct PeerContext *p = cls;
+
+ if (p == NULL)
+ return;
+ if (p->rec != NULL)
+ p->rec (p->cb_cls, peer, message, ats, ats_count);
+}
+
+static void
+get_hello (void *cb_cls, const struct GNUNET_MessageHeader *message)
+{
+ struct PeerContext *p = cb_cls;
+
+ GNUNET_assert (message != NULL);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *)
+ message, &p->id));
+ GNUNET_free_non_null (p->hello);
+ p->hello = (struct GNUNET_HELLO_Message *) GNUNET_copy_message (message);
+
+ if (p->start_cb != NULL)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Peer %u (`%s') successfully started\n", p->no,
+ GNUNET_i2s (&p->id));
+
+ p->start_cb (p, p->cb_cls);
+ p->start_cb = NULL;
+ }
+}
+
+
+static void
+try_connect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct ConnectingContext *cc = cls;
+ struct PeerContext *p1 = cc->p1;
+ struct PeerContext *p2 = cc->p2;
+
+ cc->tct = GNUNET_SCHEDULER_NO_TASK;
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ return;
+
+ GNUNET_assert (cc != NULL);
+ GNUNET_assert (cc->p1 != NULL);
+ GNUNET_assert (cc->p2 != NULL);
+
+ char *p2_s = GNUNET_strdup (GNUNET_i2s (&p2->id));
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Asking peer %u (`%s') to connect peer %u (`%s'), providing HELLO with %u bytes\n",
+ p1->no, GNUNET_i2s (&p1->id), p2->no, p2_s,
+ GNUNET_HELLO_size (cc->p2->hello));
+ GNUNET_free (p2_s);
+
+ GNUNET_TRANSPORT_offer_hello (cc->th_p1,
+ (const struct GNUNET_MessageHeader *) cc->
+ p2->hello, NULL, NULL);
+ GNUNET_TRANSPORT_try_connect (cc->th_p1, &p2->id);
+
+ cc->tct =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_UNIT_SECONDS, &try_connect, cc);
+}
+
+
+/**
+ * Start a peer with the given configuration
+ * @param tth the testing handle
+ * @param cfgname configuration file
+ * @param peer_id the peer_id
+ * @param rec receive callback
+ * @param nc connect callback
+ * @param nd disconnect callback
+ * @param start_cb start callback
+ * @param cb_cls closure for callback
+ * @return the peer context
+ */
+struct PeerContext *
+GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle
+ *tth, const char *cfgname, int peer_id,
+ GNUNET_TRANSPORT_ReceiveCallback rec,
+ GNUNET_TRANSPORT_NotifyConnect nc,
+ GNUNET_TRANSPORT_NotifyDisconnect nd,
+ GNUNET_TRANSPORT_TESTING_start_cb start_cb,
+ void *cb_cls)
+{
+ const char *hostkey = NULL;
+ struct GNUNET_DISK_FileHandle *fn;
+
+ GNUNET_assert (tth != NULL);
+ if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
+ "File not found: `%s' \n", cfgname);
+ return NULL;
+ }
+
+ struct PeerContext *p = GNUNET_malloc (sizeof (struct PeerContext));
+
+ p->cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
+
+ if (GNUNET_CONFIGURATION_have_value (p->cfg, "PATHS", "SERVICEHOME"))
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONFIGURATION_get_value_string (p->cfg, "PATHS",
+ "SERVICEHOME",
+ &p->servicehome));
+
+ if (NULL != p->servicehome)
+ GNUNET_DISK_directory_remove (p->servicehome);
+
+ hostkey = get_host_key (tth);
+ if (hostkey != NULL)
+ {
+
+ GNUNET_asprintf (&p->hostkeyfile, "%s/.hostkey", p->servicehome);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_DISK_directory_create_for_file (p->hostkeyfile));
+ fn = GNUNET_DISK_file_open (p->hostkeyfile,
+ GNUNET_DISK_OPEN_READWRITE |
+ GNUNET_DISK_OPEN_CREATE,
+ GNUNET_DISK_PERM_USER_READ |
+ GNUNET_DISK_PERM_USER_WRITE);
+ GNUNET_assert (fn != NULL);
+ GNUNET_assert (HOSTKEYFILESIZE ==
+ GNUNET_DISK_file_write (fn, hostkey, HOSTKEYFILESIZE));
+ GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fn));
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Wrote hostkey to file: `%s' \n", p->hostkeyfile);
+ }
+
+ p->arm_proc =
+ GNUNET_OS_start_process (GNUNET_YES,
+ NULL, NULL, "gnunet-service-arm",
+ "gnunet-service-arm", "-c", cfgname,
+#if VERBOSE_PEERS
+ "-L", "DEBUG",
+#else
+ "-L", "ERROR",
+#endif
+ NULL);
+
+ p->no = peer_id;
+ p->tth = tth;
+ p->nc = nc;
+ p->nd = nd;
+ p->rec = rec;
+ p->start_cb = start_cb;
+ if (cb_cls != NULL)
+ p->cb_cls = cb_cls;
+ else
+ p->cb_cls = p;
+
+ p->th =
+ GNUNET_TRANSPORT_connect (p->cfg, NULL, p, &notify_receive,
+ &notify_connect, &notify_disconnect);
+ GNUNET_assert (p->th != NULL);
+
+ p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
+ GNUNET_assert (p->ghh != NULL);
+
+ GNUNET_CONTAINER_DLL_insert (tth->p_head, tth->p_tail, p);
+ return p;
+}
+
+/**
+* Restart the given peer
+* @param tth testing handle
+* @param p the peer
+* @param cfgname the cfg file used to restart
+* @param restart_cb callback to call when restarted
+* @param cb_cls callback closure
+* @return GNUNET_OK in success otherwise GNUNET_SYSERR
+*/
+int
+GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle
+ *tth, struct PeerContext *p,
+ const char *cfgname,
+ GNUNET_TRANSPORT_TESTING_start_cb
+ restart_cb, void *cb_cls)
+{
+ struct GNUNET_DISK_FileHandle *fn;
+
+ GNUNET_assert (tth != NULL);
+ GNUNET_assert (p != NULL);
+ GNUNET_assert (p->hostkeyfile != NULL);
+ GNUNET_assert (p->servicehome != NULL);
+
+ /* shutdown */
+#if VERBOSE
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Stopping peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
+#endif
+ if (p->ghh != NULL)
+ GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
+ p->ghh = NULL;
+
+ if (p->th != NULL)
+ GNUNET_TRANSPORT_disconnect (p->th);
+
+ if (NULL != p->arm_proc)
+ {
+ if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ GNUNET_OS_process_wait (p->arm_proc);
+ GNUNET_OS_process_close (p->arm_proc);
+ p->arm_proc = NULL;
+ }
+ if (p->hello != NULL)
+ GNUNET_free (p->hello);
+ p->hello = NULL;
+
+ if (p->cfg != NULL)
+ GNUNET_CONFIGURATION_destroy (p->cfg);
+ p->cfg = NULL;
+
+
+ /* start */
+#if VERBOSE
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Restarting peer %u (`%s')\n", p->no, GNUNET_i2s (&p->id));
+#endif
+
+ sleep (5); // YUCK!
+
+ if (GNUNET_DISK_file_test (cfgname) == GNUNET_NO)
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
+ "File not found: `%s' \n", cfgname);
+ goto fail;
+ }
+
+ p->cfg = GNUNET_CONFIGURATION_create ();
+ GNUNET_assert (GNUNET_OK == GNUNET_CONFIGURATION_load (p->cfg, cfgname));
+
+ if (!GNUNET_CONFIGURATION_have_value (p->cfg, "PATHS", "SERVICEHOME"))
+ goto fail;
+
+ fn = GNUNET_DISK_file_open (p->hostkeyfile,
+ GNUNET_DISK_OPEN_READWRITE |
+ GNUNET_DISK_OPEN_CREATE,
+ GNUNET_DISK_PERM_USER_READ |
+ GNUNET_DISK_PERM_USER_WRITE);
+ if (fn == NULL)
+ goto fail;
+ if (GNUNET_OK != GNUNET_DISK_file_close (fn))
+ goto fail;
+
+ p->arm_proc =
+ GNUNET_OS_start_process (GNUNET_YES,
+ NULL, NULL, "gnunet-service-arm",
+ "gnunet-service-arm", "-c", cfgname,
+#if VERBOSE_PEERS
+ "-L", "DEBUG",
+#else
+ "-L", "ERROR",
+#endif
+ NULL);
+
+ p->th =
+ GNUNET_TRANSPORT_connect (p->cfg, NULL, p, &notify_receive,
+ &notify_connect, &notify_disconnect);
+ GNUNET_assert (p->th != NULL);
+
+ p->start_cb = restart_cb;
+ p->cb_cls = cb_cls;
+
+ p->ghh = GNUNET_TRANSPORT_get_hello (p->th, &get_hello, p);
+ GNUNET_assert (p->ghh != NULL);
+ return GNUNET_OK;
+
+fail:
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Restarting peer %u (`%s') failed, removing peer\n", p->no,
+ GNUNET_i2s (&p->id));
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
+ return GNUNET_SYSERR;
+}
+
+/**
+ * shutdown the given peer
+ * @param tth testing handle
+ * @param p the peer
+ */
+void
+GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth,
+ struct PeerContext *p)
+{
+ GNUNET_assert (p != NULL);
+
+ if (p->ghh != NULL)
+ GNUNET_TRANSPORT_get_hello_cancel (p->ghh);
+ p->ghh = NULL;
+
+ if (p->th != NULL)
+ GNUNET_TRANSPORT_disconnect (p->th);
+
+ if (NULL != p->arm_proc)
+ {
+ if (0 != GNUNET_OS_process_kill (p->arm_proc, SIGTERM))
+ GNUNET_log_strerror (GNUNET_ERROR_TYPE_WARNING, "kill");
+ GNUNET_OS_process_wait (p->arm_proc);
+ GNUNET_OS_process_close (p->arm_proc);
+ p->arm_proc = NULL;
+ }
+
+ if (p->hostkeyfile != NULL)
+ {
+ GNUNET_DISK_directory_remove (p->hostkeyfile);
+ GNUNET_free (p->hostkeyfile);
+ }
+
+ if (p->servicehome != NULL)
+ {
+ GNUNET_DISK_directory_remove (p->servicehome);
+ GNUNET_free (p->servicehome);
+ }
+
+ if (p->hello != NULL)
+ GNUNET_free (p->hello);
+ p->hello = NULL;
+
+ if (p->cfg != NULL)
+ GNUNET_CONFIGURATION_destroy (p->cfg);
+ p->cfg = NULL;
+
+ GNUNET_CONTAINER_DLL_remove (tth->p_head, tth->p_tail, p);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Peer %u (`%s') stopped \n", p->no,
+ GNUNET_i2s (&p->id));
+
+ GNUNET_free (p);
+ p = NULL;
+}
+
+/**
+ * Connect the given peers and call the callback when both peers report the
+ * inbound connection. Remarks: start_peer's notify_connect callback can be called
+ * before.
+ *
+ * @param tth transport testing handle
+ * @param p1 peer 1
+ * @param p2 peer 2
+ * @param cb the callback to call when both peers notified that they are connected
+ * @param cls callback cls
+ * @return a connect request handle
+ */
+GNUNET_TRANSPORT_TESTING_ConnectRequest
+GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth,
+ struct PeerContext *p1,
+ struct PeerContext *p2,
+ GNUNET_TRANSPORT_TESTING_connect_cb cb,
+ void *cls)
+{
+ GNUNET_assert (tth != NULL);
+
+ struct ConnectingContext *cc =
+ GNUNET_malloc (sizeof (struct ConnectingContext));
+
+ GNUNET_assert (p1 != NULL);
+ GNUNET_assert (p2 != NULL);
+
+ cc->p1 = p1;
+ cc->p2 = p2;
+
+ cc->cb = cb;
+ if (cls != NULL)
+ cc->cb_cls = cls;
+ else
+ cc->cb_cls = cc;
+
+ cc->th_p1 = p1->th;
+ cc->th_p2 = p2->th;
+
+ GNUNET_assert (cc->th_p1 != NULL);
+ GNUNET_assert (cc->th_p2 != NULL);
+
+ GNUNET_CONTAINER_DLL_insert (tth->cc_head, tth->cc_tail, cc);
+
+ cc->tct = GNUNET_SCHEDULER_add_now (&try_connect, cc);
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "New connect request %X\n", cc);
+
+ return cc;
+}
+
+/**
+ * Cancel the request to connect two peers
+ * Tou MUST cancel the request if you stop the peers before the peers connected succesfully
+ *
+ * @param tth transport testing handle
+ * @param ccr a connect request handle
+ */
+void
+GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
+ GNUNET_TRANSPORT_TESTING_handle
+ *tth,
+ GNUNET_TRANSPORT_TESTING_ConnectRequest
+ ccr)
+{
+ struct ConnectingContext *cc = ccr;
+
+ GNUNET_assert (tth != NULL);
+
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Canceling connect request %X!\n", cc);
+
+ if (cc->tct != GNUNET_SCHEDULER_NO_TASK)
+ GNUNET_SCHEDULER_cancel (cc->tct);
+ cc->tct = GNUNET_SCHEDULER_NO_TASK;
+
+ GNUNET_CONTAINER_DLL_remove (tth->cc_head, tth->cc_tail, cc);
+ GNUNET_free (cc);
+}
+
+
+/**
+ * Clean up the transport testing
+ * @param tth transport testing handle
+ */
+void
+GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth)
+{
+ struct ConnectingContext *cc = tth->cc_head;
+ struct ConnectingContext *ct = NULL;
+ struct PeerContext *p = tth->p_head;
+ struct PeerContext *t = NULL;
+
+ GNUNET_assert (tth != NULL);
+
+ while (cc != tth->cc_tail)
+ {
+ ct = cc->next;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
+ "Developer forgot to cancel connect request %X!\n", cc);
+ GNUNET_TRANSPORT_TESTING_connect_peers_cancel (tth, cc);
+ cc = ct;
+ }
+
+ while (p != NULL)
+ {
+ t = p->next;
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
+ "Developer forgot to stop peer!\n");
+ GNUNET_TRANSPORT_TESTING_stop_peer (tth, p);
+ p = t;
+ }
+
+ GNUNET_free_non_null (tth->hostkey_data);
+
+ GNUNET_free (tth);
+ tth = NULL;
+}
+
+/**
+ * Initialize the transport testing
+ * @return transport testing handle
+ */
+struct GNUNET_TRANSPORT_TESTING_handle *
+GNUNET_TRANSPORT_TESTING_init ()
+{
+ struct GNUNET_TRANSPORT_TESTING_handle *tth;
+ struct GNUNET_DISK_FileHandle *fd;
+ uint64_t fs;
+ uint64_t total_hostkeys;
+
+
+ /* prepare hostkeys */
+ tth = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TESTING_handle));
+ tth->hostkey_data = NULL;
+ const char *hostkeys_file = "../../contrib/testing_hostkeys.dat";
+
+ if (GNUNET_YES != GNUNET_DISK_file_test (hostkeys_file))
+ {
+ GNUNET_log (GNUNET_ERROR_TYPE_ERROR, _("Could not read hostkeys file!\n"));
+ }
+ else
+ {
+ /* Check hostkey file size, read entire thing into memory */
+ fd = GNUNET_DISK_file_open (hostkeys_file, GNUNET_DISK_OPEN_READ,
+ GNUNET_DISK_PERM_NONE);
+ if (NULL == fd)
+ {
+ GNUNET_log_strerror_file (GNUNET_ERROR_TYPE_ERROR, "open", hostkeys_file);
+ GNUNET_free (tth);
+ return NULL;
+ }
+
+ if (GNUNET_YES != GNUNET_DISK_file_size (hostkeys_file, &fs, GNUNET_YES))
+ fs = 0;
+
+ if (0 != (fs % HOSTKEYFILESIZE))
+ {
+ GNUNET_log_from (GNUNET_ERROR_TYPE_ERROR, "transport-testing",
+ "File size %llu seems incorrect for hostkeys...\n", fs);
+ }
+ else
+ {
+ total_hostkeys = fs / HOSTKEYFILESIZE;
+ tth->hostkey_data = GNUNET_malloc_large (fs);
+ GNUNET_assert (fs == GNUNET_DISK_file_read (fd, tth->hostkey_data, fs));
+ GNUNET_log_from (GNUNET_ERROR_TYPE_DEBUG, "transport-testing",
+ "Read %llu hostkeys from file\n", total_hostkeys);
+ tth->hostkeys_total = total_hostkeys;
+ }
+ GNUNET_assert (GNUNET_OK == GNUNET_DISK_file_close (fd));
+ }
+
+ return tth;
+}
+
+
+/*
+ * Some utility functions
+ */
+
+/**
+ * Removes all directory separators from absolute filename
+ * @param file the absolute file name, e.g. as found in argv[0]
+ * @return extracted file name, has to be freed by caller
+ */
+static char *
+extract_filename (const char *file)
+{
+ char *pch = GNUNET_strdup (file);
+ char *backup = pch;
+ char *filename = NULL;
+ char *res;
+
+ if (NULL != strstr (pch, "/"))
+ {
+ pch = strtok (pch, "/");
+ while (pch != NULL)
+ {
+ pch = strtok (NULL, "/");
+ if (pch != NULL)
+ {
+ filename = pch;
+ }
+ }
+ }
+ else
+ filename = pch;
+
+ res = GNUNET_strdup (filename);
+ GNUNET_free (backup);
+ return res;
+}
+
+/**
+ * Extracts the test filename from an absolute file name and removes the extension
+ * @param file absolute file name
+ * @param dest where to store result
+ */
+void
+GNUNET_TRANSPORT_TESTING_get_test_name (const char *file, char **dest)
+{
+ char *filename = extract_filename (file);
+ char *backup = filename;
+ char *dotexe;
+
+ if (filename == NULL)
+ goto fail;
+
+ /* remove "lt-" */
+ filename = strstr (filename, "tes");
+ if (filename == NULL)
+ goto fail;
+
+ /* remove ".exe" */
+ if (NULL != (dotexe = strstr (filename, ".exe")))
+ dotexe[0] = '\0';
+
+ goto suc;
+
+fail:
+ (*dest) = NULL;
+ return;
+
+suc:
+ /* create filename */
+ GNUNET_asprintf (dest, "%s", filename);
+ GNUNET_free (backup);
+}
+
+
+/**
+ * Extracts the filename from an absolute file name and removes the extension
+ * @param file absolute file name
+ * @param dest where to store result
+ */
+void
+GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file, char **dest)
+{
+ char *src = extract_filename (file);
+ char *split;
+
+ split = strstr (src, ".");
+ if (split != NULL)
+ {
+ split[0] = '\0';
+ }
+ GNUNET_asprintf (dest, "%s", src);
+ GNUNET_free (src);
+}
+
+
+/**
+ * Extracts the plugin anme from an absolute file name and the test name
+ * @param file absolute file name
+ * @param test test name
+ * @param dest where to store result
+ */
+void
+GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *file,
+ const char *test, char **dest)
+{
+ char *e = extract_filename (file);
+ char *t = extract_filename (test);
+
+ char *filename = NULL;
+ char *dotexe;
+
+ if (e == NULL)
+ goto fail;
+
+ /* remove "lt-" */
+ filename = strstr (e, "tes");
+ if (filename == NULL)
+ goto fail;
+
+ /* remove ".exe" */
+ if (NULL != (dotexe = strstr (filename, ".exe")))
+ dotexe[0] = '\0';
+
+ /* find last _ */
+ filename = strstr (filename, t);
+ if (filename == NULL)
+ goto fail;
+
+ /* copy plugin */
+ filename += strlen (t);
+ filename++;
+ GNUNET_asprintf (dest, "%s", filename);
+ goto suc;
+
+fail:
+ (*dest) = NULL;
+suc:
+ GNUNET_free (t);
+ GNUNET_free (e);
+
+}
+
+/**
+ * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
+ * if existing ".exe"-prefix and adds the peer-number
+ *
+ * @param file filename of the test, e.g. argv[0]
+ * @param dest where to write the filename
+ * @param count peer number
+ */
+void
+GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest,
+ int count)
+{
+ char *filename = extract_filename (file);
+ char *backup = filename;
+ char *dotexe;
+
+ if (filename == NULL)
+ goto fail;
+
+ /* remove "lt-" */
+ filename = strstr (filename, "tes");
+ if (filename == NULL)
+ goto fail;
+
+ /* remove ".exe" */
+ if (NULL != (dotexe = strstr (filename, ".exe")))
+ dotexe[0] = '\0';
+
+ goto suc;
+
+fail:
+ (*dest) = NULL;
+ return;
+
+suc:
+ /* create cfg filename */
+ GNUNET_asprintf (dest, "%s_peer%u.conf", filename, count);
+ GNUNET_free (backup);
+}
+
+
+
+/* end of transport_testing.h */
diff --git a/src/transport/transport-testing.h b/src/transport/transport-testing.h
new file mode 100644
index 0000000..20e802d
--- /dev/null
+++ b/src/transport/transport-testing.h
@@ -0,0 +1,275 @@
+/*
+ This file is part of GNUnet.
+ (C) 2006, 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 2, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport-testing.h
+ * @brief testing lib for transport service
+ *
+ * @author Matthias Wachs
+ */
+
+#include "platform.h"
+#include "gnunet_common.h"
+#include "gnunet_getopt_lib.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_os_lib.h"
+#include "gnunet_program_lib.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_transport_service.h"
+
+
+#define GNUNET_TRANSPORT_TESTING_ConnectRequest void *
+
+
+/**
+ * Context for a single peer
+ */
+struct PeerContext;
+
+/**
+ * Callback when two peers are connected and both have called the connect callback
+ * to notify clients about a new peer
+ */
+typedef void (*GNUNET_TRANSPORT_TESTING_start_cb) (struct PeerContext * p,
+ void *cls);
+
+/**
+ * Callback when two peers are connected and both have called the connect callback
+ * to notify clients about a new peer
+ */
+typedef void (*GNUNET_TRANSPORT_TESTING_connect_cb) (struct PeerContext * p1,
+ struct PeerContext * p2,
+ void *cls);
+
+
+
+struct GNUNET_TRANSPORT_TESTING_handle;
+
+/**
+ * Context for a single peer
+ */
+struct PeerContext
+{
+ struct PeerContext *next;
+ struct PeerContext *prev;
+
+ struct GNUNET_TRANSPORT_TESTING_handle *tth;
+
+ struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ struct GNUNET_TRANSPORT_Handle *th;
+
+ struct GNUNET_TRANSPORT_GetHelloHandle *ghh;
+
+ struct GNUNET_PeerIdentity id;
+
+ struct GNUNET_OS_Process *arm_proc;
+
+ GNUNET_TRANSPORT_ReceiveCallback rec;
+
+ GNUNET_TRANSPORT_NotifyConnect nc;
+
+ GNUNET_TRANSPORT_NotifyDisconnect nd;
+
+ GNUNET_TRANSPORT_TESTING_start_cb start_cb;
+
+ struct GNUNET_HELLO_Message *hello;
+
+ void *cb_cls;
+
+ char *servicehome;
+
+ char *hostkeyfile;
+
+ unsigned int no;
+};
+
+
+struct ConnectingContext
+{
+ struct ConnectingContext *next;
+ struct ConnectingContext *prev;
+ struct PeerContext *p1;
+ struct PeerContext *p2;
+ GNUNET_SCHEDULER_TaskIdentifier tct;
+ GNUNET_TRANSPORT_TESTING_connect_cb cb;
+ void *cb_cls;
+ struct GNUNET_TRANSPORT_Handle *th_p1;
+ struct GNUNET_TRANSPORT_Handle *th_p2;
+ int p1_c;
+ int p2_c;
+};
+
+struct GNUNET_TRANSPORT_TESTING_handle
+{
+ struct ConnectingContext *cc_head;
+ struct ConnectingContext *cc_tail;
+
+ char *hostkey_data;
+ int hostkeys_total;
+ int hostkeys_last;
+
+ struct PeerContext *p_head;
+ struct PeerContext *p_tail;
+};
+
+
+/**
+* Start a peer with the given configuration
+* @param tth the testing handle
+* @param cfgname configuration file
+* @param peer_id the peer_id
+* @param rec receive callback
+* @param nc connect callback
+* @param nd disconnect callback
+* @param start_cb start callback
+* @param cb_cls closure for callback
+* @return the peer context
+*/
+struct PeerContext *
+GNUNET_TRANSPORT_TESTING_start_peer (struct GNUNET_TRANSPORT_TESTING_handle
+ *tth, const char *cfgname, int peer_id,
+ GNUNET_TRANSPORT_ReceiveCallback rec,
+ GNUNET_TRANSPORT_NotifyConnect nc,
+ GNUNET_TRANSPORT_NotifyDisconnect nd,
+ GNUNET_TRANSPORT_TESTING_start_cb start_cb,
+ void *cb_cls);
+
+
+/**
+ * shutdown the given peer
+ * @param tth the testing handle
+ * @param p the peer
+ */
+
+void
+GNUNET_TRANSPORT_TESTING_stop_peer (struct GNUNET_TRANSPORT_TESTING_handle *tth,
+ struct PeerContext *pc);
+
+
+/**
+* Restart the given peer
+* @param tth testing handle
+* @param p the peer
+* @param cfgname the cfg file used to restart
+* @param restart_cb restart callback
+* @param cb_cls callback closure
+* @return GNUNET_OK in success otherwise GNUNET_SYSERR
+*/
+int
+GNUNET_TRANSPORT_TESTING_restart_peer (struct GNUNET_TRANSPORT_TESTING_handle
+ *tth, struct PeerContext *p,
+ const char *cfgname,
+ GNUNET_TRANSPORT_TESTING_start_cb
+ restart_cb, void *cb_cls);
+
+/**
+ * Connect the given peers and call the callback when both peers report the
+ * inbound connection. Remarks: start_peer's notify_connect callback can be called
+ * before.
+ *
+ * @param tth transport testing handle
+ * @param p1 peer 1
+ * @param p2 peer 2
+ * @param cb the callback to call when both peers notified that they are connected
+ * @param cls callback cls
+ * @return a connect request handle
+ */
+GNUNET_TRANSPORT_TESTING_ConnectRequest
+GNUNET_TRANSPORT_TESTING_connect_peers (struct GNUNET_TRANSPORT_TESTING_handle *tth,
+ struct PeerContext *p1,
+ struct PeerContext *p2,
+ GNUNET_TRANSPORT_TESTING_connect_cb cb,
+ void *cls);
+
+/**
+ * Cancel the request to connect two peers
+ * Tou MUST cancel the request if you stop the peers before the peers connected succesfully
+ * @param tth testing
+ * @param ccr a connect request handle
+ */
+void
+GNUNET_TRANSPORT_TESTING_connect_peers_cancel (struct
+ GNUNET_TRANSPORT_TESTING_handle
+ *tth,
+ GNUNET_TRANSPORT_TESTING_ConnectRequest
+ ccr);
+
+/**
+ * Clean up the transport testing
+ * @param tth transport testing handle
+ */
+void
+GNUNET_TRANSPORT_TESTING_done (struct GNUNET_TRANSPORT_TESTING_handle *tth);
+
+/**
+ * Initialize the transport testing
+ * @return transport testing handle
+ */
+struct GNUNET_TRANSPORT_TESTING_handle *
+GNUNET_TRANSPORT_TESTING_init ();
+
+/*
+ * Some utility functions
+ */
+
+/**
+ * Extracts the test filename from an absolute file name and removes the extension
+ * @param file absolute file name
+ * @param dest where to store result
+ */
+void
+GNUNET_TRANSPORT_TESTING_get_test_name (const char *file, char **dest);
+
+/**
+ * This function takes the filename (e.g. argv[0), removes a "lt-"-prefix and
+ * if existing ".exe"-prefix and adds the peer-number
+ *
+ * @param file filename of the test, e.g. argv[0]
+ * @param dest where to write the filename
+ * @param count peer number
+ */
+void
+GNUNET_TRANSPORT_TESTING_get_config_name (const char *file, char **dest,
+ int count);
+
+
+/**
+ * Extracts the plugin anme from an absolute file name and the test name
+ * @param file absolute file name
+ * @param test test name
+ * @param dest where to store result
+ */
+void
+GNUNET_TRANSPORT_TESTING_get_test_plugin_name (const char *executable,
+ const char *testname,
+ char **pluginname);
+
+
+/**
+ * Extracts the filename from an absolute file name and removes the extenstion
+ * @param file absolute file name
+ * @param dest where to store result
+ */
+void
+GNUNET_TRANSPORT_TESTING_get_test_source_name (const char *file,
+ char **testname);
+
+/* end of transport_testing.h */
diff --git a/src/transport/transport.conf.in b/src/transport/transport.conf.in
new file mode 100644
index 0000000..ff81ff0
--- /dev/null
+++ b/src/transport/transport.conf.in
@@ -0,0 +1,67 @@
+[transport]
+AUTOSTART = YES
+@UNIXONLY@ PORT = 2091
+HOSTNAME = localhost
+HOME = $SERVICEHOME
+CONFIG = $DEFAULTCONFIG
+BINARY = gnunet-service-transport
+#PREFIX = valgrind
+NEIGHBOUR_LIMIT = 50
+ACCEPT_FROM = 127.0.0.1;
+ACCEPT_FROM6 = ::1;
+PLUGINS = tcp
+UNIXPATH = /tmp/gnunet-service-transport.sock
+BLACKLIST_FILE = $SERVICEHOME/blacklist
+# This could possibly be relaxed
+UNIX_MATCH_UID = YES
+UNIX_MATCH_GID = YES
+# DISABLE_SOCKET_FORWARDING = NO
+# USERNAME =
+# MAXBUF =
+# TIMEOUT =
+# DISABLEV6 =
+# BINDTO =
+# REJECT_FROM =
+# REJECT_FROM6 =
+# PREFIX = valgrind --leak-check=full
+
+
+[transport-tcp]
+# Use 0 to ONLY advertise as a peer behind NAT (no port binding)
+PORT = 2086
+ADVERTISED_PORT = 2086
+
+# Maximum number of open TCP connections allowed
+MAX_CONNECTIONS = 128
+
+TIMEOUT = 5 s
+# ACCEPT_FROM =
+# ACCEPT_FROM6 =
+# REJECT_FROM =
+# REJECT_FROM6 =
+# BINDTO =
+MAX_CONNECTIONS = 128
+
+[transport-udp]
+PORT = 2086
+BROADCAST = YES
+BROADCAST_INTERVAL = 30000
+MAX_BPS = 1000000
+
+[transport-http]
+PORT = 1080
+MAX_CONNECTIONS = 128
+
+[transport-https]
+PORT = 4433
+CRYPTO_INIT = NORMAL
+KEY_FILE = https.key
+CERT_FILE = https.cert
+MAX_CONNECTIONS = 128
+
+[transport-wlan]
+# Name of the interface in monitor mode (typically monX)
+INTERFACE = mon0
+# Real hardware, no testing
+TESTMODE = 0
+
diff --git a/src/transport/transport.h b/src/transport/transport.h
new file mode 100644
index 0000000..ff68188
--- /dev/null
+++ b/src/transport/transport.h
@@ -0,0 +1,438 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/transport.h
+ * @brief common internal definitions for transport service
+ * @author Christian Grothoff
+ */
+#ifndef TRANSPORT_H
+#define TRANSPORT_H
+
+#include "gnunet_crypto_lib.h"
+#include "gnunet_time_lib.h"
+#include "gnunet_transport_service.h"
+#include "gnunet_constants.h"
+
+#define DEBUG_TRANSPORT GNUNET_EXTRA_LOGGING
+
+#define DEBUG_TRANSPORT_TIMEOUT GNUNET_EXTRA_LOGGING
+
+#define DEBUG_TRANSPORT_DISCONNECT GNUNET_EXTRA_LOGGING
+
+#define DEBUG_TRANSPORT_API GNUNET_EXTRA_LOGGING
+
+/**
+ * For how long do we allow unused bandwidth
+ * from the past to carry over into the future? (in seconds)
+ */
+#define MAX_BANDWIDTH_CARRY_S GNUNET_CONSTANTS_MAX_BANDWIDTH_CARRY_S
+
+/**
+ * How often do we (at most) do a full quota
+ * recalculation? (in ms)
+ */
+#define MIN_QUOTA_REFRESH_TIME 2000
+
+/**
+ * Maximum frequency for re-evaluating latencies for all transport addresses.
+ */
+#define LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 1)
+
+/**
+ * Maximum frequency for re-evaluating latencies for connected addresses.
+ */
+#define CONNECTED_LATENCY_EVALUATION_MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MINUTES, 1)
+
+GNUNET_NETWORK_STRUCT_BEGIN
+
+/**
+ * Message from the transport service to the library
+ * asking to check if both processes agree about this
+ * peers identity.
+ */
+struct StartMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_START
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * 0: no options
+ * 1: The 'self' field should be checked
+ * 2: this client is interested in payload traffic
+ */
+ uint32_t options;
+
+ /**
+ * Identity we think we have. If it does not match, the
+ * receiver should print out an error message and disconnect.
+ */
+ struct GNUNET_PeerIdentity self;
+
+};
+
+
+/**
+ * Message from the transport service to the library
+ * informing about neighbors.
+ */
+struct ConnectInfoMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Number of ATS key-value pairs that follow this struct
+ * (excluding the 0-terminator).
+ */
+ uint32_t ats_count GNUNET_PACKED;
+
+ /**
+ * Identity of the new neighbour.
+ */
+ struct GNUNET_PeerIdentity id;
+};
+
+
+/**
+ * Message from the transport service to the library
+ * informing about disconnects.
+ */
+struct DisconnectInfoMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Reserved, always zero.
+ */
+ uint32_t reserved GNUNET_PACKED;
+
+ /**
+ * Who got disconnected?
+ */
+ struct GNUNET_PeerIdentity peer;
+
+};
+
+/**
+ * Message type for sending a request connect message
+ * to the transport service. Must be done before transport
+ * api will allow messages to be queued/sent to transport
+ * service for transmission to a peer.
+ */
+struct TransportRequestConnectMessage
+{
+ /**
+ * Message header
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * For alignment.
+ */
+ uint32_t reserved;
+
+ /**
+ * Identity of the peer we would like to connect to.
+ */
+ struct GNUNET_PeerIdentity peer;
+};
+
+/**
+ * Message used to set a particular bandwidth quota. Sent TO the
+ * service to set an incoming quota, sent FROM the service to update
+ * an outgoing quota.
+ */
+struct QuotaSetMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Quota.
+ */
+ struct GNUNET_BANDWIDTH_Value32NBO quota;
+
+ /**
+ * About which peer are we talking here?
+ */
+ struct GNUNET_PeerIdentity peer;
+
+};
+
+
+/**
+ * Message used to notify the transport API about a message
+ * received from the network. The actual message follows.
+ */
+struct InboundMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_RECV
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Number of ATS key-value pairs that follow this struct
+ * (excluding the 0-terminator).
+ */
+ uint32_t ats_count GNUNET_PACKED;
+
+ /**
+ * Which peer sent the message?
+ */
+ struct GNUNET_PeerIdentity peer;
+
+};
+
+
+/**
+ * Message used to notify the transport API that it can
+ * send another message to the transport service.
+ */
+struct SendOkMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * GNUNET_OK if the transmission succeeded,
+ * GNUNET_SYSERR if it failed (i.e. network disconnect);
+ * in either case, it is now OK for this client to
+ * send us another message for the given peer.
+ */
+ uint32_t success GNUNET_PACKED;
+
+ /**
+ * Latency estimate.
+ */
+ struct GNUNET_TIME_RelativeNBO latency;
+
+ /**
+ * Which peer can send more now?
+ */
+ struct GNUNET_PeerIdentity peer;
+
+};
+
+
+/**
+ * Message used to notify the transport service about a message
+ * to be transmitted to another peer. The actual message follows.
+ */
+struct OutboundMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_SEND
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Message priority.
+ */
+ uint32_t priority GNUNET_PACKED;
+
+ /**
+ * Allowed delay.
+ */
+ struct GNUNET_TIME_RelativeNBO timeout;
+
+ /**
+ * Which peer should receive the message?
+ */
+ struct GNUNET_PeerIdentity peer;
+
+};
+
+
+/**
+ * Message from the library to the transport service
+ * asking for converting a transport address to a
+ * human-readable UTF-8 string.
+ */
+struct AddressLookupMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_LOOKUP
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * Should the conversion use numeric IP addresses (otherwise
+ * a reverse DNS lookup is OK -- if applicable).
+ */
+ int16_t numeric_only GNUNET_PACKED;
+
+ /**
+ * Length of the (binary) address in bytes, in big-endian.
+ */
+ uint16_t addrlen GNUNET_PACKED;
+
+ /**
+ * timeout to give up.
+ */
+ struct GNUNET_TIME_RelativeNBO timeout;
+
+ /* followed by 'addrlen' bytes of the actual address, then
+ * followed by the 0-terminated name of the transport */
+};
+
+
+/**
+ * Message from the library to the transport service
+ * asking for human readable addresses known for a peer.
+ */
+struct PeerAddressLookupMessage
+{
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_PEER_ADDRESS_LOOKUP
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * For alignment.
+ */
+ uint32_t reserved;
+
+ /**
+ * timeout to give up. FIXME: remove in the future.
+ */
+ struct GNUNET_TIME_RelativeNBO timeout;
+
+ /**
+ * The identity of the peer to look up.
+ */
+ struct GNUNET_PeerIdentity peer;
+};
+
+
+/**
+ * Message from the library to the transport service
+ * asking for binary addresses known for a peer.
+ */
+struct AddressIterateMessage
+{
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * One shot call or continous replies?
+ */
+ uint32_t one_shot;
+
+ /**
+ * timeout to give up. FIXME: remove in the future
+ */
+ struct GNUNET_TIME_AbsoluteNBO timeout;
+
+ /**
+ * The identity of the peer to look up.
+ */
+ struct GNUNET_PeerIdentity peer;
+
+};
+
+
+/**
+ * Message from the transport service to the library
+ * containing binary addresses known for a peer.
+ * Memory layout:
+ * [AddressIterateResponseMessage][address[addrlen]][transportname[pluginlen]]
+ */
+struct AddressIterateResponseMessage
+{
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * For alignment.
+ */
+ uint32_t reserved;
+
+ /**
+ * Peer identity
+ */
+ struct GNUNET_PeerIdentity peer;
+
+ /**
+ * address length
+ */
+ uint32_t addrlen GNUNET_PACKED;
+
+ /**
+ * length of the plugin name
+ */
+ uint32_t pluginlen GNUNET_PACKED;
+
+};
+
+
+/**
+ * Change in blacklisting (either request or notification,
+ * depending on which direction it is going).
+ */
+struct BlacklistMessage
+{
+
+ /**
+ * Type will be GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY or
+ * GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY.
+ */
+ struct GNUNET_MessageHeader header;
+
+ /**
+ * 0 for the query, GNUNET_OK (allowed) or GNUNET_SYSERR (disallowed)
+ * for the response.
+ */
+ uint32_t is_allowed GNUNET_PACKED;
+
+ /**
+ * Which peer is being blacklisted or queried?
+ */
+ struct GNUNET_PeerIdentity peer;
+
+};
+GNUNET_NETWORK_STRUCT_END
+
+/* end of transport.h */
+#endif
diff --git a/src/transport/transport_api.c b/src/transport/transport_api.c
new file mode 100644
index 0000000..9ff5cec
--- /dev/null
+++ b/src/transport/transport_api.c
@@ -0,0 +1,1337 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010, 2011 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/transport_api.c
+ * @brief library to access the low-level P2P IO service
+ * @author Christian Grothoff
+ *
+ * TODO:
+ * - adjust testcases to use new 'try connect' style (should be easy, breaks API compatibility!)
+ * - adjust core service to use new 'try connect' style (should be MUCH nicer there as well!)
+ * - test test test
+ */
+#include "platform.h"
+#include "gnunet_constants.h"
+#include "gnunet_bandwidth_lib.h"
+#include "gnunet_client_lib.h"
+#include "gnunet_constants.h"
+#include "gnunet_container_lib.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_time_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+
+#define LOG(kind,...) GNUNET_log_from (kind, "transport-api",__VA_ARGS__)
+
+/**
+ * How large to start with for the hashmap of neighbours.
+ */
+#define STARTING_NEIGHBOURS_SIZE 16
+
+/**
+ * Handle for a message that should be transmitted to the service.
+ * Used for both control messages and normal messages.
+ */
+struct GNUNET_TRANSPORT_TransmitHandle
+{
+
+ /**
+ * We keep all requests in a DLL.
+ */
+ struct GNUNET_TRANSPORT_TransmitHandle *next;
+
+ /**
+ * We keep all requests in a DLL.
+ */
+ struct GNUNET_TRANSPORT_TransmitHandle *prev;
+
+ /**
+ * Neighbour for this handle, NULL for control messages.
+ */
+ struct Neighbour *neighbour;
+
+ /**
+ * Function to call when notify_size bytes are available
+ * for transmission.
+ */
+ GNUNET_CONNECTION_TransmitReadyNotify notify;
+
+ /**
+ * Closure for notify.
+ */
+ void *notify_cls;
+
+ /**
+ * Timeout for this request, 0 for control messages.
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * Task to trigger request timeout if the request is stalled due to
+ * congestion.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier timeout_task;
+
+ /**
+ * How many bytes is our notify callback waiting for?
+ */
+ size_t notify_size;
+
+ /**
+ * How important is this message? Not used for control messages.
+ */
+ uint32_t priority;
+
+};
+
+
+/**
+ * Entry in hash table of all of our current neighbours.
+ */
+struct Neighbour
+{
+ /**
+ * Overall transport handle.
+ */
+ struct GNUNET_TRANSPORT_Handle *h;
+
+ /**
+ * Active transmit handle or NULL.
+ */
+ struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+ /**
+ * Identity of this neighbour.
+ */
+ struct GNUNET_PeerIdentity id;
+
+ /**
+ * Outbound bandwidh tracker.
+ */
+ struct GNUNET_BANDWIDTH_Tracker out_tracker;
+
+ /**
+ * Entry in our readyness heap (which is sorted by 'next_ready'
+ * value). NULL if there is no pending transmission request for
+ * this neighbour or if we're waiting for 'is_ready' to become
+ * true AFTER the 'out_tracker' suggested that this peer's quota
+ * has been satisfied (so once 'is_ready' goes to GNUNET_YES,
+ * we should immediately go back into the heap).
+ */
+ struct GNUNET_CONTAINER_HeapNode *hn;
+
+ /**
+ * Is this peer currently ready to receive a message?
+ */
+ int is_ready;
+
+};
+
+
+/**
+ * Linked list of functions to call whenever our HELLO is updated.
+ */
+struct GNUNET_TRANSPORT_GetHelloHandle
+{
+
+ /**
+ * This is a doubly linked list.
+ */
+ struct GNUNET_TRANSPORT_GetHelloHandle *next;
+
+ /**
+ * This is a doubly linked list.
+ */
+ struct GNUNET_TRANSPORT_GetHelloHandle *prev;
+
+ /**
+ * Transport handle.
+ */
+ struct GNUNET_TRANSPORT_Handle *handle;
+
+ /**
+ * Callback to call once we got our HELLO.
+ */
+ GNUNET_TRANSPORT_HelloUpdateCallback rec;
+
+ /**
+ * Closure for rec.
+ */
+ void *rec_cls;
+
+};
+
+
+/**
+ * Handle for the transport service (includes all of the
+ * state for the transport service).
+ */
+struct GNUNET_TRANSPORT_Handle
+{
+
+ /**
+ * Closure for the callbacks.
+ */
+ void *cls;
+
+ /**
+ * Function to call for received data.
+ */
+ GNUNET_TRANSPORT_ReceiveCallback rec;
+
+ /**
+ * function to call on connect events
+ */
+ GNUNET_TRANSPORT_NotifyConnect nc_cb;
+
+ /**
+ * function to call on disconnect events
+ */
+ GNUNET_TRANSPORT_NotifyDisconnect nd_cb;
+
+ /**
+ * Head of DLL of control messages.
+ */
+ struct GNUNET_TRANSPORT_TransmitHandle *control_head;
+
+ /**
+ * Tail of DLL of control messages.
+ */
+ struct GNUNET_TRANSPORT_TransmitHandle *control_tail;
+
+ /**
+ * The current HELLO message for this peer. Updated
+ * whenever transports change their addresses.
+ */
+ struct GNUNET_HELLO_Message *my_hello;
+
+ /**
+ * My client connection to the transport service.
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * Handle to our registration with the client for notification.
+ */
+ struct GNUNET_CLIENT_TransmitHandle *cth;
+
+ /**
+ * Linked list of pending requests for our HELLO.
+ */
+ struct GNUNET_TRANSPORT_GetHelloHandle *hwl_head;
+
+ /**
+ * Linked list of pending requests for our HELLO.
+ */
+ struct GNUNET_TRANSPORT_GetHelloHandle *hwl_tail;
+
+ /**
+ * My configuration.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Hash map of the current connected neighbours of this peer.
+ * Maps peer identities to 'struct Neighbour' entries.
+ */
+ struct GNUNET_CONTAINER_MultiHashMap *neighbours;
+
+ /**
+ * Heap sorting peers with pending messages by the timestamps that
+ * specify when we could next send a message to the respective peer.
+ * Excludes control messages (which can always go out immediately).
+ * Maps time stamps to 'struct Neighbour' entries.
+ */
+ struct GNUNET_CONTAINER_Heap *ready_heap;
+
+ /**
+ * Peer identity as assumed by this process, or all zeros.
+ */
+ struct GNUNET_PeerIdentity self;
+
+ /**
+ * ID of the task trying to reconnect to the service.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+
+ /**
+ * ID of the task trying to trigger transmission for a peer while
+ * maintaining bandwidth quotas. In use if there are no control
+ * messages and the smallest entry in the 'ready_heap' has a time
+ * stamp in the future.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier quota_task;
+
+ /**
+ * Delay until we try to reconnect.
+ */
+ struct GNUNET_TIME_Relative reconnect_delay;
+
+ /**
+ * Should we check that 'self' matches what the service thinks?
+ * (if GNUNET_NO, then 'self' is all zeros!).
+ */
+ int check_self;
+};
+
+
+/**
+ * Schedule the task to send one message, either from the control
+ * list or the peer message queues to the service.
+ *
+ * @param h transport service to schedule a transmission for
+ */
+static void
+schedule_transmission (struct GNUNET_TRANSPORT_Handle *h);
+
+
+/**
+ * Function that will schedule the job that will try
+ * to connect us again to the client.
+ *
+ * @param h transport service to reconnect
+ */
+static void
+disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_Handle *h);
+
+
+/**
+ * Get the neighbour list entry for the given peer
+ *
+ * @param h our context
+ * @param peer peer to look up
+ * @return NULL if no such peer entry exists
+ */
+static struct Neighbour *
+neighbour_find (struct GNUNET_TRANSPORT_Handle *h,
+ const struct GNUNET_PeerIdentity *peer)
+{
+ return GNUNET_CONTAINER_multihashmap_get (h->neighbours, &peer->hashPubKey);
+}
+
+
+/**
+ * Add neighbour to our list
+ *
+ * @return NULL if this API is currently disconnecting from the service
+ */
+static struct Neighbour *
+neighbour_add (struct GNUNET_TRANSPORT_Handle *h,
+ const struct GNUNET_PeerIdentity *pid)
+{
+ struct Neighbour *n;
+
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Creating entry for neighbour `%4s'.\n",
+ GNUNET_i2s (pid));
+#endif
+ n = GNUNET_malloc (sizeof (struct Neighbour));
+ n->id = *pid;
+ n->h = h;
+ n->is_ready = GNUNET_YES;
+ GNUNET_BANDWIDTH_tracker_init (&n->out_tracker,
+ GNUNET_CONSTANTS_DEFAULT_BW_IN_OUT,
+ MAX_BANDWIDTH_CARRY_S);
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CONTAINER_multihashmap_put (h->neighbours,
+ &pid->hashPubKey, n,
+ GNUNET_CONTAINER_MULTIHASHMAPOPTION_UNIQUE_ONLY));
+ return n;
+}
+
+
+/**
+ * Iterator over hash map entries, for deleting state of a neighbour.
+ *
+ * @param cls the 'struct GNUNET_TRANSPORT_Handle*'
+ * @param key peer identity
+ * @param value value in the hash map, the neighbour entry to delete
+ * @return GNUNET_YES if we should continue to
+ * iterate,
+ * GNUNET_NO if not.
+ */
+static int
+neighbour_delete (void *cls, const GNUNET_HashCode * key, void *value)
+{
+ struct GNUNET_TRANSPORT_Handle *handle = cls;
+ struct Neighbour *n = value;
+
+ if (NULL != handle->nd_cb)
+ handle->nd_cb (handle->cls, &n->id);
+ GNUNET_assert (NULL == n->th);
+ GNUNET_assert (NULL == n->hn);
+ GNUNET_assert (GNUNET_YES ==
+ GNUNET_CONTAINER_multihashmap_remove (handle->neighbours, key,
+ n));
+ GNUNET_free (n);
+ return GNUNET_YES;
+}
+
+
+/**
+ * Function we use for handling incoming messages.
+ *
+ * @param cls closure (struct GNUNET_TRANSPORT_Handle *)
+ * @param msg message received, NULL on timeout or fatal error
+ */
+static void
+demultiplexer (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_TRANSPORT_Handle *h = cls;
+ const struct DisconnectInfoMessage *dim;
+ const struct ConnectInfoMessage *cim;
+ const struct InboundMessage *im;
+ const struct GNUNET_MessageHeader *imm;
+ const struct SendOkMessage *okm;
+ const struct QuotaSetMessage *qm;
+ const struct GNUNET_ATS_Information *ats;
+ struct GNUNET_TRANSPORT_GetHelloHandle *hwl;
+ struct GNUNET_TRANSPORT_GetHelloHandle *next_hwl;
+ struct Neighbour *n;
+ struct GNUNET_PeerIdentity me;
+ uint16_t size;
+ uint32_t ats_count;
+
+ GNUNET_assert (h->client != NULL);
+ if (msg == NULL)
+ {
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_INFO,
+ "Error receiving from transport service, disconnecting temporarily.\n");
+#endif
+ disconnect_and_schedule_reconnect (h);
+ return;
+ }
+ GNUNET_CLIENT_receive (h->client, &demultiplexer, h,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ size = ntohs (msg->size);
+ switch (ntohs (msg->type))
+ {
+ case GNUNET_MESSAGE_TYPE_HELLO:
+ if (GNUNET_OK !=
+ GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) msg, &me))
+ {
+ GNUNET_break (0);
+ break;
+ }
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Receiving (my own) `%s' message, I am `%4s'.\n", "HELLO",
+ GNUNET_i2s (&me));
+#endif
+ GNUNET_free_non_null (h->my_hello);
+ h->my_hello = NULL;
+ if (size < sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break (0);
+ break;
+ }
+ h->my_hello = GNUNET_malloc (size);
+ memcpy (h->my_hello, msg, size);
+ hwl = h->hwl_head;
+ while (NULL != hwl)
+ {
+ next_hwl = hwl->next;
+ hwl->rec (hwl->rec_cls,
+ (const struct GNUNET_MessageHeader *) h->my_hello);
+ hwl = next_hwl;
+ }
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_CONNECT:
+ if (size < sizeof (struct ConnectInfoMessage))
+ {
+ GNUNET_break (0);
+ break;
+ }
+ cim = (const struct ConnectInfoMessage *) msg;
+ ats_count = ntohl (cim->ats_count);
+ if (size !=
+ sizeof (struct ConnectInfoMessage) +
+ ats_count * sizeof (struct GNUNET_ATS_Information))
+ {
+ GNUNET_break (0);
+ break;
+ }
+ ats = (const struct GNUNET_ATS_Information *) &cim[1];
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message for `%4s'.\n",
+ "CONNECT", GNUNET_i2s (&cim->id));
+#endif
+ n = neighbour_find (h, &cim->id);
+ if (n != NULL)
+ {
+ GNUNET_break (0);
+ break;
+ }
+ n = neighbour_add (h, &cim->id);
+ if (h->nc_cb != NULL)
+ h->nc_cb (h->cls, &n->id, ats, ats_count);
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_DISCONNECT:
+ if (size != sizeof (struct DisconnectInfoMessage))
+ {
+ GNUNET_break (0);
+ break;
+ }
+ dim = (const struct DisconnectInfoMessage *) msg;
+ GNUNET_break (ntohl (dim->reserved) == 0);
+#if DEBUG_TRANSPORT_API_DISCONNECT
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message for `%4s'.\n",
+ "DISCONNECT", GNUNET_i2s (&dim->peer));
+#endif
+ n = neighbour_find (h, &dim->peer);
+ if (n == NULL)
+ {
+ GNUNET_break (0);
+ break;
+ }
+ neighbour_delete (h, &dim->peer.hashPubKey, n);
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_SEND_OK:
+ if (size != sizeof (struct SendOkMessage))
+ {
+ GNUNET_break (0);
+ break;
+ }
+ okm = (const struct SendOkMessage *) msg;
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message, transmission %s.\n",
+ "SEND_OK", ntohl (okm->success) == GNUNET_OK ? "succeeded" : "failed");
+#endif
+ n = neighbour_find (h, &okm->peer);
+ if (n == NULL)
+ break;
+ GNUNET_break (GNUNET_NO == n->is_ready);
+ n->is_ready = GNUNET_YES;
+ if ((n->th != NULL) && (n->hn == NULL))
+ {
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != n->th->timeout_task);
+ GNUNET_SCHEDULER_cancel (n->th->timeout_task);
+ n->th->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ /* we've been waiting for this (congestion, not quota,
+ * caused delayed transmission) */
+ n->hn = GNUNET_CONTAINER_heap_insert (h->ready_heap, n, 0);
+ schedule_transmission (h);
+ }
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_RECV:
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message.\n", "RECV");
+#endif
+ if (size <
+ sizeof (struct InboundMessage) + sizeof (struct GNUNET_MessageHeader))
+ {
+ GNUNET_break (0);
+ break;
+ }
+ im = (const struct InboundMessage *) msg;
+ ats_count = ntohl (im->ats_count);
+ ats = (const struct GNUNET_ATS_Information *) &im[1];
+ imm = (const struct GNUNET_MessageHeader *) &ats[ats_count];
+ if (ntohs (imm->size) + sizeof (struct InboundMessage) +
+ ats_count * sizeof (struct GNUNET_ATS_Information) != size)
+ {
+ GNUNET_break (0);
+ break;
+ }
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Received message of type %u from `%4s'.\n",
+ ntohs (imm->type), GNUNET_i2s (&im->peer));
+#endif
+ n = neighbour_find (h, &im->peer);
+ if (n == NULL)
+ {
+ GNUNET_break (0);
+ break;
+ }
+ if (h->rec != NULL)
+ h->rec (h->cls, &im->peer, imm, ats, ats_count);
+ break;
+ case GNUNET_MESSAGE_TYPE_TRANSPORT_SET_QUOTA:
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Receiving `%s' message.\n", "SET_QUOTA");
+#endif
+ if (size != sizeof (struct QuotaSetMessage))
+ {
+ GNUNET_break (0);
+ break;
+ }
+ qm = (const struct QuotaSetMessage *) msg;
+ n = neighbour_find (h, &qm->peer);
+ if (n == NULL)
+ break;
+ GNUNET_BANDWIDTH_tracker_update_quota (&n->out_tracker, qm->quota);
+ break;
+ default:
+ LOG (GNUNET_ERROR_TYPE_ERROR,
+ _("Received unexpected message of type %u in %s:%u\n"),
+ ntohs (msg->type), __FILE__, __LINE__);
+ GNUNET_break (0);
+ break;
+ }
+}
+
+
+/**
+ * A transmission request could not be satisfied because of
+ * network congestion. Notify the initiator and clean up.
+ *
+ * @param cls the 'struct GNUNET_TRANSPORT_TransmitHandle'
+ * @param tc scheduler context
+ */
+static void
+timeout_request_due_to_congestion (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext
+ *tc)
+{
+ struct GNUNET_TRANSPORT_TransmitHandle *th = cls;
+ struct Neighbour *n = th->neighbour;
+
+ n->th->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_assert (th == n->th);
+ GNUNET_assert (NULL == n->hn);
+ n->th = NULL;
+ th->notify (th->notify_cls, 0, NULL);
+ GNUNET_free (th);
+}
+
+
+/**
+ * Transmit message(s) to service.
+ *
+ * @param cls handle to transport
+ * @param size number of bytes available in buf
+ * @param buf where to copy the message
+ * @return number of bytes copied to buf
+ */
+static size_t
+transport_notify_ready (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_TRANSPORT_Handle *h = cls;
+ struct GNUNET_TRANSPORT_TransmitHandle *th;
+ struct Neighbour *n;
+ char *cbuf;
+ struct OutboundMessage obm;
+ size_t ret;
+ size_t nret;
+ size_t mret;
+
+ GNUNET_assert (NULL != h->client);
+ h->cth = NULL;
+ if (NULL == buf)
+ {
+ /* transmission failed */
+ disconnect_and_schedule_reconnect (h);
+ return 0;
+ }
+
+ cbuf = buf;
+ ret = 0;
+ /* first send control messages */
+ while ((NULL != (th = h->control_head)) && (th->notify_size <= size))
+ {
+ GNUNET_CONTAINER_DLL_remove (h->control_head, h->control_tail, th);
+ nret = th->notify (th->notify_cls, size, &cbuf[ret]);
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Added %u bytes of control message at %u\n",
+ nret, ret);
+#endif
+ GNUNET_free (th);
+ ret += nret;
+ size -= nret;
+ }
+
+ /* then, if possible and no control messages pending, send data messages */
+ while ((NULL == h->control_head) &&
+ (NULL != (n = GNUNET_CONTAINER_heap_peek (h->ready_heap))))
+ {
+ if (GNUNET_YES != n->is_ready)
+ {
+ /* peer not ready, wait for notification! */
+ GNUNET_assert (n == GNUNET_CONTAINER_heap_remove_root (h->ready_heap));
+ n->hn = NULL;
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK == n->th->timeout_task);
+ n->th->timeout_task =
+ GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_absolute_get_remaining
+ (n->th->timeout),
+ &timeout_request_due_to_congestion,
+ n->th);
+ continue;
+ }
+ th = n->th;
+ if (th->notify_size + sizeof (struct OutboundMessage) > size)
+ break; /* does not fit */
+ if (GNUNET_BANDWIDTH_tracker_get_delay
+ (&n->out_tracker, th->notify_size).rel_value > 0)
+ break; /* too early */
+ GNUNET_assert (n == GNUNET_CONTAINER_heap_remove_root (h->ready_heap));
+ n->hn = NULL;
+ n->th = NULL;
+ n->is_ready = GNUNET_NO;
+ GNUNET_assert (size >= sizeof (struct OutboundMessage));
+ mret =
+ th->notify (th->notify_cls, size - sizeof (struct OutboundMessage),
+ &cbuf[ret + sizeof (struct OutboundMessage)]);
+ GNUNET_assert (mret <= size - sizeof (struct OutboundMessage));
+ if (mret != 0)
+ {
+ GNUNET_assert (mret + sizeof (struct OutboundMessage) <
+ GNUNET_SERVER_MAX_MESSAGE_SIZE);
+ obm.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_SEND);
+ obm.header.size = htons (mret + sizeof (struct OutboundMessage));
+ obm.priority = htonl (th->priority);
+ obm.timeout =
+ GNUNET_TIME_relative_hton (GNUNET_TIME_absolute_get_remaining
+ (th->timeout));
+ obm.peer = n->id;
+ memcpy (&cbuf[ret], &obm, sizeof (struct OutboundMessage));
+ ret += (mret + sizeof (struct OutboundMessage));
+ size -= (mret + sizeof (struct OutboundMessage));
+ GNUNET_BANDWIDTH_tracker_consume (&n->out_tracker, mret);
+ }
+ GNUNET_free (th);
+ }
+ /* if there are more pending messages, try to schedule those */
+ schedule_transmission (h);
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting %u bytes to transport service\n",
+ ret);
+#endif
+ return ret;
+}
+
+
+/**
+ * Schedule the task to send one message, either from the control
+ * list or the peer message queues to the service.
+ *
+ * @param cls transport service to schedule a transmission for
+ * @param tc scheduler context
+ */
+static void
+schedule_transmission_task (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TRANSPORT_Handle *h = cls;
+ size_t size;
+ struct GNUNET_TRANSPORT_TransmitHandle *th;
+ struct Neighbour *n;
+
+ h->quota_task = GNUNET_SCHEDULER_NO_TASK;
+ GNUNET_assert (NULL != h->client);
+ /* destroy all requests that have timed out */
+ while ((NULL != (n = GNUNET_CONTAINER_heap_peek (h->ready_heap))) &&
+ (GNUNET_TIME_absolute_get_remaining (n->th->timeout).rel_value == 0))
+ {
+ /* notify client that the request could not be satisfied within
+ * the given time constraints */
+ th = n->th;
+ n->th = NULL;
+ GNUNET_assert (n == GNUNET_CONTAINER_heap_remove_root (h->ready_heap));
+ n->hn = NULL;
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Signalling timeout for transmission to peer %s due to congestion\n",
+ GNUNET_i2s (&n->id));
+#endif
+ GNUNET_assert (0 == th->notify (th->notify_cls, 0, NULL));
+ GNUNET_free (th);
+ }
+ if (NULL != h->cth)
+ return;
+ if (NULL != h->control_head)
+ {
+ size = h->control_head->notify_size;
+ }
+ else
+ {
+ n = GNUNET_CONTAINER_heap_peek (h->ready_heap);
+ if (NULL == n)
+ return; /* no pending messages */
+ size = n->th->notify_size + sizeof (struct OutboundMessage);
+ }
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Calling notify_transmit_ready\n");
+#endif
+ h->cth =
+ GNUNET_CLIENT_notify_transmit_ready (h->client, size,
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_NO, &transport_notify_ready,
+ h);
+ GNUNET_assert (NULL != h->cth);
+}
+
+
+/**
+ * Schedule the task to send one message, either from the control
+ * list or the peer message queues to the service.
+ *
+ * @param h transport service to schedule a transmission for
+ */
+static void
+schedule_transmission (struct GNUNET_TRANSPORT_Handle *h)
+{
+ struct GNUNET_TIME_Relative delay;
+ struct Neighbour *n;
+
+ GNUNET_assert (NULL != h->client);
+ if (h->quota_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (h->quota_task);
+ h->quota_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ if (NULL != h->control_head)
+ delay = GNUNET_TIME_UNIT_ZERO;
+ else if (NULL != (n = GNUNET_CONTAINER_heap_peek (h->ready_heap)))
+ delay =
+ GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker,
+ n->th->notify_size);
+ else
+ return; /* no work to be done */
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Scheduling next transmission to service in %llu ms\n",
+ (unsigned long long) delay.rel_value);
+#endif
+ h->quota_task =
+ GNUNET_SCHEDULER_add_delayed (delay, &schedule_transmission_task, h);
+}
+
+
+/**
+ * Queue control request for transmission to the transport
+ * service.
+ *
+ * @param h handle to the transport service
+ * @param size number of bytes to be transmitted
+ * @param notify function to call to get the content
+ * @param notify_cls closure for notify
+ */
+static void
+schedule_control_transmit (struct GNUNET_TRANSPORT_Handle *h, size_t size,
+ GNUNET_CONNECTION_TransmitReadyNotify notify,
+ void *notify_cls)
+{
+ struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Control transmit of %u bytes requested\n",
+ size);
+#endif
+ th = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TransmitHandle));
+ th->notify = notify;
+ th->notify_cls = notify_cls;
+ th->notify_size = size;
+ GNUNET_CONTAINER_DLL_insert_tail (h->control_head, h->control_tail, th);
+ schedule_transmission (h);
+}
+
+
+/**
+ * Transmit START message to service.
+ *
+ * @param cls unused
+ * @param size number of bytes available in buf
+ * @param buf where to copy the message
+ * @return number of bytes copied to buf
+ */
+static size_t
+send_start (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_TRANSPORT_Handle *h = cls;
+ struct StartMessage s;
+ uint32_t options;
+
+ if (buf == NULL)
+ {
+ /* Can only be shutdown, just give up */
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Shutdown while trying to transmit `%s' request.\n", "START");
+#endif
+ return 0;
+ }
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "START");
+#endif
+ GNUNET_assert (size >= sizeof (struct StartMessage));
+ s.header.size = htons (sizeof (struct StartMessage));
+ s.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_START);
+ options = 0;
+ if (h->check_self)
+ options |= 1;
+ if (h->rec != NULL)
+ options |= 2;
+ s.options = htonl (options);
+ s.self = h->self;
+ memcpy (buf, &s, sizeof (struct StartMessage));
+ GNUNET_CLIENT_receive (h->client, &demultiplexer, h,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+ return sizeof (struct StartMessage);
+}
+
+
+/**
+ * Try again to connect to transport service.
+ *
+ * @param cls the handle to the transport service
+ * @param tc scheduler context
+ */
+static void
+reconnect (void *cls, const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TRANSPORT_Handle *h = cls;
+
+ h->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ if ((tc->reason & GNUNET_SCHEDULER_REASON_SHUTDOWN) != 0)
+ {
+ /* shutdown, just give up */
+ return;
+ }
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Connecting to transport service.\n");
+#endif
+ GNUNET_assert (h->client == NULL);
+ GNUNET_assert (h->control_head == NULL);
+ GNUNET_assert (h->control_tail == NULL);
+ h->client = GNUNET_CLIENT_connect ("transport", h->cfg);
+ GNUNET_assert (h->client != NULL);
+ schedule_control_transmit (h, sizeof (struct StartMessage), &send_start, h);
+}
+
+
+/**
+ * Function that will schedule the job that will try
+ * to connect us again to the client.
+ *
+ * @param h transport service to reconnect
+ */
+static void
+disconnect_and_schedule_reconnect (struct GNUNET_TRANSPORT_Handle *h)
+{
+ struct GNUNET_TRANSPORT_TransmitHandle *th;
+
+ GNUNET_assert (h->reconnect_task == GNUNET_SCHEDULER_NO_TASK);
+ if (NULL != h->cth)
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (h->cth);
+ h->cth = NULL;
+ }
+ if (NULL != h->client)
+ {
+ GNUNET_CLIENT_disconnect (h->client, GNUNET_YES);
+ h->client = NULL;
+ }
+ /* Forget about all neighbours that we used to be connected to */
+ GNUNET_CONTAINER_multihashmap_iterate (h->neighbours, &neighbour_delete, h);
+ if (h->quota_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (h->quota_task);
+ h->quota_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ while ((NULL != (th = h->control_head)))
+ {
+ GNUNET_CONTAINER_DLL_remove (h->control_head, h->control_tail, th);
+ th->notify (th->notify_cls, 0, NULL);
+ GNUNET_free (th);
+ }
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Scheduling task to reconnect to transport service in %llu ms.\n",
+ h->reconnect_delay.rel_value);
+#endif
+ h->reconnect_task =
+ GNUNET_SCHEDULER_add_delayed (h->reconnect_delay, &reconnect, h);
+ if (h->reconnect_delay.rel_value == 0)
+ {
+ h->reconnect_delay = GNUNET_TIME_UNIT_MILLISECONDS;
+ }
+ else
+ {
+ h->reconnect_delay = GNUNET_TIME_relative_multiply (h->reconnect_delay, 2);
+ h->reconnect_delay =
+ GNUNET_TIME_relative_min (GNUNET_TIME_UNIT_SECONDS, h->reconnect_delay);
+ }
+}
+
+
+/**
+ * Send REQUEST_CONNECT message to the service.
+ *
+ * @param cls the 'struct GNUNET_PeerIdentity'
+ * @param size number of bytes available in buf
+ * @param buf where to copy the message
+ * @return number of bytes copied to buf
+ */
+static size_t
+send_try_connect (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_PeerIdentity *pid = cls;
+ struct TransportRequestConnectMessage msg;
+
+ if (buf == NULL)
+ {
+ GNUNET_free (pid);
+ return 0;
+ }
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Transmitting `%s' request with respect to `%4s'.\n", "REQUEST_CONNECT",
+ GNUNET_i2s (pid));
+#endif
+ GNUNET_assert (size >= sizeof (struct TransportRequestConnectMessage));
+ msg.header.size = htons (sizeof (struct TransportRequestConnectMessage));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_REQUEST_CONNECT);
+ msg.reserved = htonl (0);
+ msg.peer = *pid;
+ memcpy (buf, &msg, sizeof (msg));
+ GNUNET_free (pid);
+ return sizeof (struct TransportRequestConnectMessage);
+}
+
+
+/**
+ * Ask the transport service to establish a connection to
+ * the given peer.
+ *
+ * @param handle connection to transport service
+ * @param target who we should try to connect to
+ */
+void
+GNUNET_TRANSPORT_try_connect (struct GNUNET_TRANSPORT_Handle *handle,
+ const struct GNUNET_PeerIdentity *target)
+{
+ struct GNUNET_PeerIdentity *pid;
+
+ if (NULL == handle->client)
+ return;
+ pid = GNUNET_malloc (sizeof (struct GNUNET_PeerIdentity));
+ *pid = *target;
+ schedule_control_transmit (handle,
+ sizeof (struct TransportRequestConnectMessage),
+ &send_try_connect, pid);
+}
+
+
+/**
+ * Send HELLO message to the service.
+ *
+ * @param cls the HELLO message to send
+ * @param size number of bytes available in buf
+ * @param buf where to copy the message
+ * @return number of bytes copied to buf
+ */
+static size_t
+send_hello (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_MessageHeader *msg = cls;
+ uint16_t ssize;
+
+ if (buf == NULL)
+ {
+#if DEBUG_TRANSPORT_TIMEOUT
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Timeout while trying to transmit `%s' request.\n", "HELLO");
+#endif
+ GNUNET_free (msg);
+ return 0;
+ }
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transmitting `%s' request.\n", "HELLO");
+#endif
+ ssize = ntohs (msg->size);
+ GNUNET_assert (size >= ssize);
+ memcpy (buf, msg, ssize);
+ GNUNET_free (msg);
+ return ssize;
+}
+
+
+/**
+ * Offer the transport service the HELLO of another peer. Note that
+ * the transport service may just ignore this message if the HELLO is
+ * malformed or useless due to our local configuration.
+ *
+ * @param handle connection to transport service
+ * @param hello the hello message
+ * @param cont continuation to call when HELLO has been sent
+ * @param cls closure for continuation
+ *
+ */
+void
+GNUNET_TRANSPORT_offer_hello (struct GNUNET_TRANSPORT_Handle *handle,
+ const struct GNUNET_MessageHeader *hello,
+ GNUNET_SCHEDULER_Task cont, void *cls)
+{
+ uint16_t size;
+ struct GNUNET_PeerIdentity peer;
+ struct GNUNET_MessageHeader *msg;
+
+ if (NULL == handle->client)
+ return;
+ GNUNET_break (ntohs (hello->type) == GNUNET_MESSAGE_TYPE_HELLO);
+ size = ntohs (hello->size);
+ GNUNET_break (size >= sizeof (struct GNUNET_MessageHeader));
+ if (GNUNET_OK !=
+ GNUNET_HELLO_get_id ((const struct GNUNET_HELLO_Message *) hello, &peer))
+ {
+ GNUNET_break (0);
+ return;
+ }
+ msg = GNUNET_malloc (size);
+ memcpy (msg, hello, size);
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Offering `%s' message of `%4s' to transport for validation.\n", "HELLO",
+ GNUNET_i2s (&peer));
+#endif
+ schedule_control_transmit (handle, size, &send_hello, msg);
+}
+
+
+/**
+ * Obtain the HELLO message for this peer.
+ *
+ * @param handle connection to transport service
+ * @param rec function to call with the HELLO, sender will be our peer
+ * identity; message and sender will be NULL on timeout
+ * (handshake with transport service pending/failed).
+ * cost estimate will be 0.
+ * @param rec_cls closure for rec
+ * @return handle to cancel the operation
+ */
+struct GNUNET_TRANSPORT_GetHelloHandle *
+GNUNET_TRANSPORT_get_hello (struct GNUNET_TRANSPORT_Handle *handle,
+ GNUNET_TRANSPORT_HelloUpdateCallback rec,
+ void *rec_cls)
+{
+ struct GNUNET_TRANSPORT_GetHelloHandle *hwl;
+
+ hwl = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_GetHelloHandle));
+ hwl->rec = rec;
+ hwl->rec_cls = rec_cls;
+ hwl->handle = handle;
+ GNUNET_CONTAINER_DLL_insert (handle->hwl_head, handle->hwl_tail, hwl);
+ if (handle->my_hello != NULL)
+ rec (rec_cls, (const struct GNUNET_MessageHeader *) handle->my_hello);
+ return hwl;
+}
+
+
+/**
+ * Stop receiving updates about changes to our HELLO message.
+ *
+ * @param ghh handle to cancel
+ */
+void
+GNUNET_TRANSPORT_get_hello_cancel (struct GNUNET_TRANSPORT_GetHelloHandle *ghh)
+{
+ struct GNUNET_TRANSPORT_Handle *handle = ghh->handle;
+
+ GNUNET_CONTAINER_DLL_remove (handle->hwl_head, handle->hwl_tail, ghh);
+ GNUNET_free (ghh);
+}
+
+
+/**
+ * Connect to the transport service. Note that the connection may
+ * complete (or fail) asynchronously.
+ *
+ * @param cfg configuration to use
+ * @param self our own identity (API should check that it matches
+ * the identity found by transport), or NULL (no check)
+ * @param cls closure for the callbacks
+ * @param rec receive function to call
+ * @param nc function to call on connect events
+ * @param nd function to call on disconnect events
+ */
+struct GNUNET_TRANSPORT_Handle *
+GNUNET_TRANSPORT_connect (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_PeerIdentity *self, void *cls,
+ GNUNET_TRANSPORT_ReceiveCallback rec,
+ GNUNET_TRANSPORT_NotifyConnect nc,
+ GNUNET_TRANSPORT_NotifyDisconnect nd)
+{
+ struct GNUNET_TRANSPORT_Handle *ret;
+
+ ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_Handle));
+ if (self != NULL)
+ {
+ ret->self = *self;
+ ret->check_self = GNUNET_YES;
+ }
+ ret->cfg = cfg;
+ ret->cls = cls;
+ ret->rec = rec;
+ ret->nc_cb = nc;
+ ret->nd_cb = nd;
+ ret->reconnect_delay = GNUNET_TIME_UNIT_ZERO;
+ ret->neighbours =
+ GNUNET_CONTAINER_multihashmap_create (STARTING_NEIGHBOURS_SIZE);
+ ret->ready_heap =
+ GNUNET_CONTAINER_heap_create (GNUNET_CONTAINER_HEAP_ORDER_MIN);
+ ret->reconnect_task = GNUNET_SCHEDULER_add_now (&reconnect, ret);
+ return ret;
+}
+
+
+/**
+ * Disconnect from the transport service.
+ *
+ * @param handle handle to the service as returned from GNUNET_TRANSPORT_connect
+ */
+void
+GNUNET_TRANSPORT_disconnect (struct GNUNET_TRANSPORT_Handle *handle)
+{
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG, "Transport disconnect called!\n");
+#endif
+ /* this disconnects all neighbours... */
+ if (handle->reconnect_task == GNUNET_SCHEDULER_NO_TASK)
+ disconnect_and_schedule_reconnect (handle);
+ /* and now we stop trying to connect again... */
+ if (handle->reconnect_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (handle->reconnect_task);
+ handle->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_CONTAINER_multihashmap_destroy (handle->neighbours);
+ handle->neighbours = NULL;
+ if (handle->quota_task != GNUNET_SCHEDULER_NO_TASK)
+ {
+ GNUNET_SCHEDULER_cancel (handle->quota_task);
+ handle->quota_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_free_non_null (handle->my_hello);
+ handle->my_hello = NULL;
+ GNUNET_assert (handle->hwl_head == NULL);
+ GNUNET_assert (handle->hwl_tail == NULL);
+ GNUNET_CONTAINER_heap_destroy (handle->ready_heap);
+ handle->ready_heap = NULL;
+ GNUNET_free (handle);
+}
+
+
+/**
+ * Check if we could queue a message of the given size for
+ * transmission. The transport service will take both its
+ * internal buffers and bandwidth limits imposed by the
+ * other peer into consideration when answering this query.
+ *
+ * @param handle connection to transport service
+ * @param target who should receive the message
+ * @param size how big is the message we want to transmit?
+ * @param priority how important is the message?
+ * @param timeout after how long should we give up (and call
+ * notify with buf NULL and size 0)?
+ * @param notify function to call when we are ready to
+ * send such a message
+ * @param notify_cls closure for notify
+ * @return NULL if someone else is already waiting to be notified
+ * non-NULL if the notify callback was queued (can be used to cancel
+ * using GNUNET_TRANSPORT_notify_transmit_ready_cancel)
+ */
+struct GNUNET_TRANSPORT_TransmitHandle *
+GNUNET_TRANSPORT_notify_transmit_ready (struct GNUNET_TRANSPORT_Handle *handle,
+ const struct GNUNET_PeerIdentity
+ *target, size_t size, uint32_t priority,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_CONNECTION_TransmitReadyNotify
+ notify, void *notify_cls)
+{
+ struct Neighbour *n;
+ struct GNUNET_TRANSPORT_TransmitHandle *th;
+ struct GNUNET_TIME_Relative delay;
+
+ n = neighbour_find (handle, target);
+ if (NULL == n)
+ {
+ /* use GNUNET_TRANSPORT_try_connect first, only use this function
+ * once a connection has been established */
+ GNUNET_assert (0);
+ return NULL;
+ }
+ if (NULL != n->th)
+ {
+ /* attempt to send two messages at the same time to the same peer */
+ GNUNET_assert (0);
+ return NULL;
+ }
+ GNUNET_assert (NULL == n->hn);
+ th = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_TransmitHandle));
+ th->neighbour = n;
+ th->notify = notify;
+ th->notify_cls = notify_cls;
+ th->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ th->notify_size = size;
+ th->priority = priority;
+ n->th = th;
+ /* calculate when our transmission should be ready */
+ delay = GNUNET_BANDWIDTH_tracker_get_delay (&n->out_tracker, size);
+ if (delay.rel_value > timeout.rel_value)
+ delay.rel_value = 0; /* notify immediately (with failure) */
+#if DEBUG_TRANSPORT_API
+ LOG (GNUNET_ERROR_TYPE_DEBUG,
+ "Bandwidth tracker allows next transmission to peer %s in %llu ms\n",
+ GNUNET_i2s (target), (unsigned long long) delay.rel_value);
+#endif
+ n->hn = GNUNET_CONTAINER_heap_insert (handle->ready_heap, n, delay.rel_value);
+ schedule_transmission (handle);
+ return th;
+}
+
+
+/**
+ * Cancel the specified transmission-ready notification.
+ *
+ * @param th handle returned from GNUNET_TRANSPORT_notify_transmit_ready
+ */
+void
+GNUNET_TRANSPORT_notify_transmit_ready_cancel (struct
+ GNUNET_TRANSPORT_TransmitHandle
+ *th)
+{
+ struct Neighbour *n;
+
+ GNUNET_assert (NULL == th->next);
+ GNUNET_assert (NULL == th->prev);
+ n = th->neighbour;
+ GNUNET_assert (th == n->th);
+ n->th = NULL;
+ if (n->hn != NULL)
+ {
+ GNUNET_CONTAINER_heap_remove_node (n->hn);
+ n->hn = NULL;
+ }
+ else
+ {
+ GNUNET_assert (GNUNET_SCHEDULER_NO_TASK != th->timeout_task);
+ GNUNET_SCHEDULER_cancel (th->timeout_task);
+ th->timeout_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_free (th);
+}
+
+
+/* end of transport_api.c */
diff --git a/src/transport/transport_api_address_lookup.c b/src/transport/transport_api_address_lookup.c
new file mode 100644
index 0000000..6e03945
--- /dev/null
+++ b/src/transport/transport_api_address_lookup.c
@@ -0,0 +1,369 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/transport_api_address_lookup.c
+ * @brief given a peer id, get all known addresses from transport service
+ *
+ * This api provides the ability to query the transport service about
+ * the status of connections to a specific peer. Calls back with a
+ * pretty printed string of the address, as formatted by the appropriate
+ * transport plugin, and whether or not the address given is currently
+ * in the 'connected' state (according to the transport service).
+ */
+
+#include "platform.h"
+#include "gnunet_client_lib.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_time_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+
+/**
+ * Context for the address lookup.
+ */
+struct GNUNET_TRANSPORT_PeerIterateContext
+{
+ /**
+ * Function to call with the binary address.
+ */
+ GNUNET_TRANSPORT_PeerIterateCallback cb;
+
+ /**
+ * Closure for cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Connection to the service.
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * Configuration we use.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * When should this operation time out?
+ */
+ struct GNUNET_TIME_Absolute timeout;
+
+ /**
+ * Backoff for reconnect.
+ */
+ struct GNUNET_TIME_Relative backoff;
+
+ /**
+ * Task ID for reconnect.
+ */
+ GNUNET_SCHEDULER_TaskIdentifier reconnect_task;
+
+ /**
+ * Identity of the peer to monitor.
+ */
+ struct GNUNET_PeerIdentity peer;
+
+ /**
+ * Was this a one-shot request?
+ */
+ int one_shot;
+};
+
+
+/**
+ * Function called with responses from the service.
+ *
+ * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
+ * @param msg NULL on timeout or error, otherwise presumably a
+ * message with the human-readable address
+ */
+static void
+peer_address_response_processor (void *cls,
+ const struct GNUNET_MessageHeader *msg);
+
+
+/**
+ * Send our subscription request to the service.
+ *
+ * @param pal_ctx our context
+ */
+static void
+send_request (struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx)
+{
+ struct AddressIterateMessage msg;
+
+ msg.header.size = htons (sizeof (struct AddressIterateMessage));
+ msg.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE);
+ msg.one_shot = htonl (pal_ctx->one_shot);
+ msg.timeout = GNUNET_TIME_absolute_hton (pal_ctx->timeout);
+ msg.peer = pal_ctx->peer;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CLIENT_transmit_and_get_response (pal_ctx->client,
+ &msg.header,
+ GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout),
+ GNUNET_YES,
+ &peer_address_response_processor,
+ pal_ctx));
+}
+
+/**
+ * Task run to re-establish the connection.
+ *
+ * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
+ * @param tc scheduler context, unused
+ */
+static void
+do_connect (void *cls,
+ const struct GNUNET_SCHEDULER_TaskContext *tc)
+{
+ struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx = cls;
+
+ pal_ctx->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ pal_ctx->client = GNUNET_CLIENT_connect ("transport", pal_ctx->cfg);
+ GNUNET_assert (NULL != pal_ctx->client);
+ send_request (pal_ctx);
+}
+
+
+/**
+ * Cut the existing connection and reconnect.
+ *
+ * @param pal_ctx our context
+ */
+static void
+reconnect (struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx)
+{
+ GNUNET_assert (GNUNET_NO == pal_ctx->one_shot);
+ GNUNET_CLIENT_disconnect (pal_ctx->client, GNUNET_NO);
+ pal_ctx->client = NULL;
+ pal_ctx->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS,
+ GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (pal_ctx->backoff, 2),
+ GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30)));
+ pal_ctx->reconnect_task = GNUNET_SCHEDULER_add_delayed (pal_ctx->backoff,
+ &do_connect,
+ pal_ctx);
+}
+
+
+/**
+ * Function called with responses from the service.
+ *
+ * @param cls our 'struct GNUNET_TRANSPORT_PeerAddressLookupContext*'
+ * @param msg NULL on timeout or error, otherwise presumably a
+ * message with the human-readable address
+ */
+static void
+peer_address_response_processor (void *cls,
+ const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx = cls;
+ struct AddressIterateResponseMessage *air_msg;
+ struct GNUNET_HELLO_Address *address;
+ const char *addr;
+ const char *transport_name;
+ uint16_t size;
+ size_t alen;
+ size_t tlen;
+
+ if (msg == NULL)
+ {
+ if (pal_ctx->one_shot)
+ {
+ pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL);
+ GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx);
+ }
+ else
+ {
+ reconnect (pal_ctx);
+ }
+ return;
+ }
+ size = ntohs (msg->size);
+ GNUNET_break (ntohs (msg->type) ==
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE);
+ if (size == sizeof (struct GNUNET_MessageHeader))
+ {
+ /* done! */
+ if (pal_ctx->one_shot)
+ {
+ pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL);
+ GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx);
+ }
+ else
+ {
+ reconnect (pal_ctx);
+ }
+ return;
+ }
+
+ if ((size < sizeof (struct AddressIterateResponseMessage)) ||
+ (ntohs (msg->type) !=
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_ITERATE_RESPONSE))
+ {
+ GNUNET_break (0);
+ if (pal_ctx->one_shot)
+ {
+ pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL);
+ GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx);
+ }
+ else
+ {
+ reconnect (pal_ctx);
+ }
+ return;
+ }
+
+ air_msg = (struct AddressIterateResponseMessage *) msg;
+ tlen = ntohl (air_msg->pluginlen);
+ alen = ntohl (air_msg->addrlen);
+
+ if (size != sizeof (struct AddressIterateResponseMessage) + tlen + alen)
+ {
+ GNUNET_break (0);
+ if (pal_ctx->one_shot)
+ {
+ pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL);
+ GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx);
+ }
+ else
+ {
+ reconnect (pal_ctx);
+ }
+ return;
+ }
+
+ if (alen == 0 && tlen == 0)
+ {
+ pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, NULL);
+ }
+ else
+ {
+ addr = (const char *) &air_msg[1];
+ transport_name = &addr[alen];
+
+ if (transport_name[tlen - 1] != '\0')
+ {
+ GNUNET_break (0);
+ if (pal_ctx->one_shot)
+ {
+ pal_ctx->cb (pal_ctx->cb_cls, NULL, NULL);
+ GNUNET_TRANSPORT_peer_get_active_addresses_cancel (pal_ctx);
+ }
+ else
+ {
+ reconnect (pal_ctx);
+ }
+ return;
+ }
+
+ /* notify client */
+ address =
+ GNUNET_HELLO_address_allocate (&air_msg->peer, transport_name, addr,
+ alen);
+ pal_ctx->cb (pal_ctx->cb_cls, &air_msg->peer, address);
+ GNUNET_HELLO_address_free (address);
+ }
+
+ /* expect more replies */
+ GNUNET_CLIENT_receive (pal_ctx->client, &peer_address_response_processor,
+ pal_ctx,
+ GNUNET_TIME_absolute_get_remaining (pal_ctx->timeout));
+}
+
+
+/**
+ * Return all the known addresses for a specific peer or all peers.
+ * Returns continously all address if one_shot is set to GNUNET_NO
+ *
+ * CHANGE: Returns the address(es) that we are currently using for this
+ * peer. Upon completion, the 'AddressLookUpCallback' is called one more
+ * time with 'NULL' for the address and the peer. After this, the operation must no
+ * longer be explicitly cancelled.
+ *
+ * @param cfg configuration to use
+ * @param peer peer identity to look up the addresses of, CHANGE: allow NULL for all (connected) peers
+ * @param one_shot GNUNET_YES to return the current state and then end (with NULL+NULL),
+ * GNUNET_NO to monitor the set of addresses used (continuously, must be explicitly cancelled)
+ * @param timeout how long is the lookup allowed to take at most (irrelevant if one_shot is set to GNUNET_NO)
+ * @param peer_address_callback function to call with the results
+ * @param peer_address_callback_cls closure for peer_address_callback
+ */
+struct GNUNET_TRANSPORT_PeerIterateContext *
+GNUNET_TRANSPORT_peer_get_active_addresses (const struct
+ GNUNET_CONFIGURATION_Handle *cfg,
+ const struct GNUNET_PeerIdentity
+ *peer, int one_shot,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_PeerIterateCallback
+ peer_address_callback,
+ void *peer_address_callback_cls)
+{
+ struct GNUNET_TRANSPORT_PeerIterateContext *pal_ctx;
+ struct GNUNET_CLIENT_Connection *client;
+
+ client = GNUNET_CLIENT_connect ("transport", cfg);
+ if (client == NULL)
+ return NULL;
+ if (GNUNET_YES != one_shot)
+ timeout = GNUNET_TIME_UNIT_FOREVER_REL;
+ pal_ctx = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_PeerIterateContext));
+ pal_ctx->cb = peer_address_callback;
+ pal_ctx->cb_cls = peer_address_callback_cls;
+ pal_ctx->cfg = cfg;
+ pal_ctx->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ if (NULL != peer)
+ pal_ctx->peer = *peer;
+ pal_ctx->one_shot = one_shot;
+ pal_ctx->client = client;
+ send_request (pal_ctx);
+
+ return pal_ctx;
+}
+
+
+/**
+ * Cancel request for address conversion.
+ *
+ * @param alc handle for the request to cancel
+ */
+void
+GNUNET_TRANSPORT_peer_get_active_addresses_cancel (struct
+ GNUNET_TRANSPORT_PeerIterateContext
+ *alc)
+{
+ if (NULL != alc->client)
+ {
+ GNUNET_CLIENT_disconnect (alc->client, GNUNET_NO);
+ alc->client = NULL;
+ }
+ if (GNUNET_SCHEDULER_NO_TASK != alc->reconnect_task)
+ {
+ GNUNET_SCHEDULER_cancel (alc->reconnect_task);
+ alc->reconnect_task = GNUNET_SCHEDULER_NO_TASK;
+ }
+ GNUNET_free (alc);
+}
+
+
+/* end of transport_api_peer_address_lookup.c */
diff --git a/src/transport/transport_api_address_to_string.c b/src/transport/transport_api_address_to_string.c
new file mode 100644
index 0000000..4d80953
--- /dev/null
+++ b/src/transport/transport_api_address_to_string.c
@@ -0,0 +1,192 @@
+/*
+ This file is part of GNUnet.
+ (C) 2009, 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+#include "platform.h"
+#include "gnunet_client_lib.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_time_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+
+/**
+ * Context for the address lookup.
+ */
+struct GNUNET_TRANSPORT_AddressToStringContext
+{
+ /**
+ * Function to call with the human-readable address.
+ */
+ GNUNET_TRANSPORT_AddressToStringCallback cb;
+
+ /**
+ * Closure for cb.
+ */
+ void *cb_cls;
+
+ /**
+ * Connection to the service.
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * When should this operation time out?
+ */
+ struct GNUNET_TIME_Absolute timeout;
+};
+
+
+/**
+ * Function called with responses from the service.
+ *
+ * @param cls our 'struct GNUNET_TRANSPORT_AddressLookupContext*'
+ * @param msg NULL on timeout or error, otherwise presumably a
+ * message with the human-readable address
+ */
+static void
+address_response_processor (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_TRANSPORT_AddressToStringContext *alucb = cls;
+ const char *address;
+ uint16_t size;
+
+ if (msg == NULL)
+ {
+ alucb->cb (alucb->cb_cls, NULL);
+ GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO);
+ GNUNET_free (alucb);
+ return;
+ }
+ GNUNET_break (ntohs (msg->type) ==
+ GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING_REPLY);
+ size = ntohs (msg->size);
+ if (size == sizeof (struct GNUNET_MessageHeader))
+ {
+ /* done! */
+ alucb->cb (alucb->cb_cls, NULL);
+ GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO);
+ GNUNET_free (alucb);
+ return;
+ }
+ address = (const char *) &msg[1];
+ if (address[size - sizeof (struct GNUNET_MessageHeader) - 1] != '\0')
+ {
+ /* invalid reply */
+ GNUNET_break (0);
+ alucb->cb (alucb->cb_cls, NULL);
+ GNUNET_CLIENT_disconnect (alucb->client, GNUNET_NO);
+ GNUNET_free (alucb);
+ return;
+ }
+ /* expect more replies */
+ GNUNET_CLIENT_receive (alucb->client, &address_response_processor, alucb,
+ GNUNET_TIME_absolute_get_remaining (alucb->timeout));
+ alucb->cb (alucb->cb_cls, address);
+}
+
+
+/**
+ * Convert a binary address into a human readable address.
+ *
+ * @param cfg configuration to use
+ * @param address address to convert (binary format)
+ * @param numeric should (IP) addresses be displayed in numeric form
+ * (otherwise do reverse DNS lookup)
+ * @param timeout how long is the lookup allowed to take at most
+ * @param aluc function to call with the results
+ * @param aluc_cls closure for aluc
+ * @return handle to cancel the operation, NULL on error
+ */
+struct GNUNET_TRANSPORT_AddressToStringContext *
+GNUNET_TRANSPORT_address_to_string (const struct GNUNET_CONFIGURATION_Handle
+ *cfg,
+ const struct GNUNET_HELLO_Address *address,
+ int numeric,
+ struct GNUNET_TIME_Relative timeout,
+ GNUNET_TRANSPORT_AddressToStringCallback
+ aluc, void *aluc_cls)
+{
+ size_t len;
+ size_t alen;
+ size_t slen;
+ struct AddressLookupMessage *msg;
+ struct GNUNET_TRANSPORT_AddressToStringContext *alc;
+ struct GNUNET_CLIENT_Connection *client;
+ char *addrbuf;
+
+ GNUNET_assert (address != NULL);
+ alen = address->address_length;
+ slen = strlen (address->transport_name) + 1;
+ len = sizeof (struct AddressLookupMessage) + alen + slen;
+ if (len >= GNUNET_SERVER_MAX_MESSAGE_SIZE)
+ {
+ GNUNET_break (0);
+ return NULL;
+ }
+
+ client = GNUNET_CLIENT_connect ("transport", cfg);
+ if (client == NULL)
+ return NULL;
+#if DEBUG_TRANSPORT
+ GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "GNUNET_TRANSPORT_address_to_string\n");
+#endif
+ msg = GNUNET_malloc (len);
+ msg->header.size = htons (len);
+ msg->header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_ADDRESS_TO_STRING);
+ msg->numeric_only = htons ((int16_t) numeric);
+ msg->addrlen = htons ((uint16_t) alen);
+ msg->timeout = GNUNET_TIME_relative_hton (timeout);
+ addrbuf = (char *) &msg[1];
+ memcpy (addrbuf, address->address, alen);
+ memcpy (&addrbuf[alen], address->transport_name, slen);
+
+ alc = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_AddressToStringContext));
+ alc->cb = aluc;
+ alc->cb_cls = aluc_cls;
+ alc->timeout = GNUNET_TIME_relative_to_absolute (timeout);
+ alc->client = client;
+ GNUNET_assert (GNUNET_OK ==
+ GNUNET_CLIENT_transmit_and_get_response (client, &msg->header,
+ timeout, GNUNET_YES,
+ &address_response_processor,
+ alc));
+ GNUNET_free (msg);
+ return alc;
+}
+
+
+/**
+ * Cancel request for address conversion.
+ *
+ * @param alc handle for the request to cancel
+ */
+void
+GNUNET_TRANSPORT_address_to_string_cancel (struct
+ GNUNET_TRANSPORT_AddressToStringContext
+ *alc)
+{
+ GNUNET_CLIENT_disconnect (alc->client, GNUNET_NO);
+ GNUNET_free (alc);
+}
+
+
+
+/* end of transport_api_address_to_string.c */
diff --git a/src/transport/transport_api_blacklist.c b/src/transport/transport_api_blacklist.c
new file mode 100644
index 0000000..be52623
--- /dev/null
+++ b/src/transport/transport_api_blacklist.c
@@ -0,0 +1,296 @@
+/*
+ This file is part of GNUnet.
+ (C) 2010 Christian Grothoff (and other contributing authors)
+
+ GNUnet is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published
+ by the Free Software Foundation; either version 3, or (at your
+ option) any later version.
+
+ GNUnet is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with GNUnet; see the file COPYING. If not, write to the
+ Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+*/
+
+/**
+ * @file transport/transport_api_blacklist.c
+ * @brief library to access the blacklisting functions of the transport service
+ * @author Christian Grothoff
+ */
+#include "platform.h"
+#include "gnunet_client_lib.h"
+#include "gnunet_arm_service.h"
+#include "gnunet_hello_lib.h"
+#include "gnunet_protocols.h"
+#include "gnunet_server_lib.h"
+#include "gnunet_time_lib.h"
+#include "gnunet_transport_service.h"
+#include "transport.h"
+
+/**
+ * Handle for blacklisting requests.
+ */
+struct GNUNET_TRANSPORT_Blacklist
+{
+
+ /**
+ * Connection to transport service.
+ */
+ struct GNUNET_CLIENT_Connection *client;
+
+ /**
+ * Configuration to use.
+ */
+ const struct GNUNET_CONFIGURATION_Handle *cfg;
+
+ /**
+ * Pending handle for the current request.
+ */
+ struct GNUNET_CLIENT_TransmitHandle *th;
+
+ /**
+ * Function to call for determining if a peer is allowed
+ * to communicate with us.
+ */
+ GNUNET_TRANSPORT_BlacklistCallback cb;
+
+ /**
+ * Closure for 'cb'.
+ */
+ void *cb_cls;
+
+ /**
+ * Peer currently under consideration.
+ */
+ struct GNUNET_PeerIdentity peer;
+
+};
+
+
+/**
+ * Establish blacklist connection to transport service.
+ *
+ * @param br overall handle
+ */
+static void
+reconnect (struct GNUNET_TRANSPORT_Blacklist *br);
+
+
+/**
+ * Send our reply to a blacklisting request.
+ *
+ * @param br our overall context
+ */
+static void
+reply (struct GNUNET_TRANSPORT_Blacklist *br);
+
+
+/**
+ * Handle blacklist queries.
+ *
+ * @param cls our overall handle
+ * @param msg query
+ */
+static void
+query_handler (void *cls, const struct GNUNET_MessageHeader *msg)
+{
+ struct GNUNET_TRANSPORT_Blacklist *br = cls;
+ const struct BlacklistMessage *bm;
+
+ GNUNET_assert (br != NULL);
+ if ((NULL == msg) ||
+ (ntohs (msg->size) != sizeof (struct BlacklistMessage)) ||
+ (ntohs (msg->type) != GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_QUERY))
+ {
+ reconnect (br);
+ return;
+ }
+ bm = (const struct BlacklistMessage *) msg;
+ GNUNET_break (0 == ntohl (bm->is_allowed));
+ br->peer = bm->peer;
+ reply (br);
+}
+
+
+/**
+ * Receive blacklist queries from transport service.
+ *
+ * @param br overall handle
+ */
+static void
+receive (struct GNUNET_TRANSPORT_Blacklist *br)
+{
+ GNUNET_CLIENT_receive (br->client, &query_handler, br,
+ GNUNET_TIME_UNIT_FOREVER_REL);
+}
+
+
+/**
+ * Transmit the blacklist initialization request to the service.
+ *
+ * @param cls closure (struct GNUNET_TRANSPORT_Blacklist*)
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_blacklist_init (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_TRANSPORT_Blacklist *br = cls;
+ struct GNUNET_MessageHeader req;
+
+ br->th = NULL;
+ if (buf == NULL)
+ {
+ reconnect (br);
+ return 0;
+ }
+ req.size = htons (sizeof (struct GNUNET_MessageHeader));
+ req.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_INIT);
+ memcpy (buf, &req, sizeof (req));
+ receive (br);
+ return sizeof (req);
+}
+
+
+/**
+ * Establish blacklist connection to transport service.
+ *
+ * @param br overall handle
+ */
+static void
+reconnect (struct GNUNET_TRANSPORT_Blacklist *br)
+{
+ if (br->client != NULL)
+ GNUNET_CLIENT_disconnect (br->client, GNUNET_NO);
+ br->client = GNUNET_CLIENT_connect ("transport", br->cfg);
+ GNUNET_assert (br->client != NULL);
+ br->th =
+ GNUNET_CLIENT_notify_transmit_ready (br->client,
+ sizeof (struct GNUNET_MessageHeader),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES, &transmit_blacklist_init,
+ br);
+}
+
+
+/**
+ * Transmit the blacklist response to the service.
+ *
+ * @param cls closure (struct GNUNET_TRANSPORT_Blacklist*)
+ * @param size number of bytes available in buf
+ * @param buf where the callee should write the message
+ * @return number of bytes written to buf
+ */
+static size_t
+transmit_blacklist_reply (void *cls, size_t size, void *buf)
+{
+ struct GNUNET_TRANSPORT_Blacklist *br = cls;
+ struct BlacklistMessage req;
+
+ br->th = NULL;
+ if (buf == NULL)
+ {
+ reconnect (br);
+ return 0;
+ }
+ req.header.size = htons (sizeof (req));
+ req.header.type = htons (GNUNET_MESSAGE_TYPE_TRANSPORT_BLACKLIST_REPLY);
+ req.is_allowed = htonl (br->cb (br->cb_cls, &br->peer));
+ req.peer = br->peer;
+ memcpy (buf, &req, sizeof (req));
+ br->th = NULL;
+ receive (br);
+ return sizeof (req);
+}
+
+
+/**
+ * Send our reply to a blacklisting request.
+ *
+ * @param br our overall context
+ */
+static void
+reply (struct GNUNET_TRANSPORT_Blacklist *br)
+{
+ GNUNET_assert (br->th == NULL);
+ br->th =
+ GNUNET_CLIENT_notify_transmit_ready (br->client,
+ sizeof (struct BlacklistMessage),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_NO, &transmit_blacklist_reply,
+ br);
+ if (br->th == NULL)
+ {
+ reconnect (br);
+ return;
+ }
+}
+
+
+/**
+ * Install a blacklist callback. The service will be queried for all
+ * existing connections as well as any fresh connections to check if
+ * they are permitted. If the blacklisting callback is unregistered,
+ * all hosts that were denied in the past will automatically be
+ * whitelisted again. Cancelling the blacklist handle is also the
+ * only way to re-enable connections from peers that were previously
+ * blacklisted.
+ *
+ * @param cfg configuration to use
+ * @param cb callback to invoke to check if connections are allowed
+ * @param cb_cls closure for cb
+ * @return NULL on error, otherwise handle for cancellation
+ */
+struct GNUNET_TRANSPORT_Blacklist *
+GNUNET_TRANSPORT_blacklist (const struct GNUNET_CONFIGURATION_Handle *cfg,
+ GNUNET_TRANSPORT_BlacklistCallback cb, void *cb_cls)
+{
+ struct GNUNET_CLIENT_Connection *client;
+ struct GNUNET_TRANSPORT_Blacklist *ret;
+
+ client = GNUNET_CLIENT_connect ("transport", cfg);
+ if (NULL == client)
+ return NULL;
+ ret = GNUNET_malloc (sizeof (struct GNUNET_TRANSPORT_Blacklist));
+ ret->client = client;
+ ret->cfg = cfg;
+ ret->cb = cb;
+ ret->cb_cls = cb_cls;
+ GNUNET_assert (ret->th == NULL);
+ ret->th =
+ GNUNET_CLIENT_notify_transmit_ready (client,
+ sizeof (struct GNUNET_MessageHeader),
+ GNUNET_TIME_UNIT_FOREVER_REL,
+ GNUNET_YES, &transmit_blacklist_init,
+ ret);
+ return ret;
+}
+
+
+/**
+ * Abort the blacklist. Note that this function is the only way for
+ * removing a peer from the blacklist.
+ *
+ * @param br handle of the request that is to be cancelled
+ */
+void
+GNUNET_TRANSPORT_blacklist_cancel (struct GNUNET_TRANSPORT_Blacklist *br)
+{
+ if (br->th != NULL)
+ {
+ GNUNET_CLIENT_notify_transmit_ready_cancel (br->th);
+ br->th = NULL;
+ }
+ GNUNET_CLIENT_disconnect (br->client, GNUNET_NO);
+ GNUNET_free (br);
+}
+
+
+/* end of transport_api_blacklist.c */