diff options
author | Bertrand Marc <beberking@gmail.com> | 2012-05-02 21:43:37 +0200 |
---|---|---|
committer | Bertrand Marc <beberking@gmail.com> | 2012-05-02 21:43:37 +0200 |
commit | 2b81464a43485fcc8ce079fafdee7b7a171835f4 (patch) | |
tree | 394774c0f735199b57d51a2d3840356317853fe1 /src/transport |
Imported Upstream version 0.9.2upstream/0.9.2
Diffstat (limited to 'src/transport')
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 (¬ify_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, ¬ify_receive, + ¬ify_connect, ¬ify_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, ¬ify_receive, + ¬ify_connect, ¬ify_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, + ¬ify_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, + ¬ify_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, ¬ify_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, ¬ify_receive, + ¬ify_connect, ¬ify_disconnect, + &start_cb, NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, gen_cfg_p2, 2, ¬ify_receive, + ¬ify_connect, ¬ify_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, ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, "test_transport_api_tcp_peer2.conf", 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, + ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, + ¬ify_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, ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, + ¬ify_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, ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, + ¬ify_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, ¬ify_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, + ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, + NULL); + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, cfg_file_p2, 2, + ¬ify_receive, ¬ify_connect, + ¬ify_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, ¬ify_receive, + ¬ify_connect, + ¬ify_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, ¬ify_receive, ¬ify_connect, + ¬ify_disconnect, &start_cb, p1); + + GNUNET_assert (p1->hostkeyfile != NULL); + + p2 = GNUNET_TRANSPORT_TESTING_start_peer (tth, + "test_transport_api_tcp_peer2.conf", + 2, ¬ify_receive, ¬ify_connect, + ¬ify_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, ¬ify_receive, + ¬ify_connect, ¬ify_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, ¬ify_receive, + ¬ify_connect, ¬ify_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 */ |